1/// Find and parse sign and get remaining bytes. 2#[inline] 3fn parse_sign<'a>(bytes: &'a [u8]) -> (bool, &'a [u8]) { 4 match bytes.get(0) { 5 Some(&b'+') => (true, &bytes[1..]), 6 Some(&b'-') => (false, &bytes[1..]), 7 _ => (true, bytes), 8 } 9} 10 11// Convert u8 to digit. 12#[inline] 13fn to_digit(c: u8) -> Option<u32> { 14 (c as char).to_digit(10) 15} 16 17// Add digit from exponent. 18#[inline] 19fn add_digit_i32(value: i32, digit: u32) -> Option<i32> { 20 return value.checked_mul(10)?.checked_add(digit as i32); 21} 22 23// Subtract digit from exponent. 24#[inline] 25fn sub_digit_i32(value: i32, digit: u32) -> Option<i32> { 26 return value.checked_mul(10)?.checked_sub(digit as i32); 27} 28 29// Convert character to digit. 30#[inline] 31fn is_digit(c: u8) -> bool { 32 to_digit(c).is_some() 33} 34 35// Split buffer at index. 36#[inline] 37fn split_at_index<'a>(digits: &'a [u8], index: usize) -> (&'a [u8], &'a [u8]) { 38 (&digits[..index], &digits[index..]) 39} 40 41/// Consume until a an invalid digit is found. 42/// 43/// - `digits` - Slice containing 0 or more digits. 44#[inline] 45fn consume_digits<'a>(digits: &'a [u8]) -> (&'a [u8], &'a [u8]) { 46 // Consume all digits. 47 let mut index = 0; 48 while index < digits.len() && is_digit(digits[index]) { 49 index += 1; 50 } 51 split_at_index(digits, index) 52} 53 54// Trim leading 0s. 55#[inline] 56fn ltrim_zero<'a>(bytes: &'a [u8]) -> &'a [u8] { 57 let count = bytes.iter().take_while(|&&si| si == b'0').count(); 58 &bytes[count..] 59} 60 61// Trim trailing 0s. 62#[inline] 63fn rtrim_zero<'a>(bytes: &'a [u8]) -> &'a [u8] { 64 let count = bytes.iter().rev().take_while(|&&si| si == b'0').count(); 65 let index = bytes.len() - count; 66 &bytes[..index] 67} 68 69// PARSERS 70// ------- 71 72/// Parse the exponent of the float. 73/// 74/// * `exponent` - Slice containing the exponent digits. 75/// * `is_positive` - If the exponent sign is positive. 76fn parse_exponent(exponent: &[u8], is_positive: bool) -> i32 { 77 // Parse the sign bit or current data. 78 let mut value: i32 = 0; 79 match is_positive { 80 true => { 81 for c in exponent { 82 value = match add_digit_i32(value, to_digit(*c).unwrap()) { 83 Some(v) => v, 84 None => return i32::max_value(), 85 }; 86 } 87 }, 88 false => { 89 for c in exponent { 90 value = match sub_digit_i32(value, to_digit(*c).unwrap()) { 91 Some(v) => v, 92 None => return i32::min_value(), 93 }; 94 } 95 }, 96 } 97 98 value 99} 100 101pub fn case_insensitive_starts_with<'a, 'b, Iter1, Iter2>(mut x: Iter1, mut y: Iter2) -> bool 102where 103 Iter1: Iterator<Item = &'a u8>, 104 Iter2: Iterator<Item = &'b u8>, 105{ 106 // We use a faster optimization here for ASCII letters, which NaN 107 // and infinite strings **must** be. [A-Z] is 0x41-0x5A, while 108 // [a-z] is 0x61-0x7A. Therefore, the xor must be 0 or 32 if they 109 // are case-insensitive equal, but only if at least 1 of the inputs 110 // is an ASCII letter. 111 loop { 112 let yi = y.next(); 113 if yi.is_none() { 114 return true; 115 } 116 let yi = *yi.unwrap(); 117 let is_not_equal = x.next().map_or(true, |&xi| { 118 let xor = xi ^ yi; 119 xor != 0 && xor != 0x20 120 }); 121 if is_not_equal { 122 return false; 123 } 124 } 125} 126 127/// Parse float from input bytes, returning the float and the remaining bytes. 128/// 129/// * `bytes` - Array of bytes leading with float-data. 130pub fn parse_float<'a, F>(bytes: &'a [u8]) -> (F, &'a [u8]) 131where 132 F: minimal_lexical::Float, 133{ 134 let start = bytes; 135 136 // Parse the sign. 137 let (is_positive, bytes) = parse_sign(bytes); 138 139 // Check NaN, Inf, Infinity 140 if case_insensitive_starts_with(bytes.iter(), b"NaN".iter()) { 141 let mut float = F::from_bits(F::EXPONENT_MASK | (F::HIDDEN_BIT_MASK >> 1)); 142 if !is_positive { 143 float = -float; 144 } 145 return (float, &bytes[3..]); 146 } else if case_insensitive_starts_with(bytes.iter(), b"Infinity".iter()) { 147 let mut float = F::from_bits(F::EXPONENT_MASK); 148 if !is_positive { 149 float = -float; 150 } 151 return (float, &bytes[8..]); 152 } else if case_insensitive_starts_with(bytes.iter(), b"inf".iter()) { 153 let mut float = F::from_bits(F::EXPONENT_MASK); 154 if !is_positive { 155 float = -float; 156 } 157 return (float, &bytes[3..]); 158 } 159 160 // Extract and parse the float components: 161 // 1. Integer 162 // 2. Fraction 163 // 3. Exponent 164 let (integer_slc, bytes) = consume_digits(bytes); 165 let (fraction_slc, bytes) = match bytes.first() { 166 Some(&b'.') => consume_digits(&bytes[1..]), 167 _ => (&bytes[..0], bytes), 168 }; 169 let (exponent, bytes) = match bytes.first() { 170 Some(&b'e') | Some(&b'E') => { 171 // Extract and parse the exponent. 172 let (is_positive, bytes) = parse_sign(&bytes[1..]); 173 let (exponent, bytes) = consume_digits(bytes); 174 (parse_exponent(exponent, is_positive), bytes) 175 }, 176 _ => (0, bytes), 177 }; 178 179 if bytes.len() == start.len() { 180 return (F::from_u64(0), bytes); 181 } 182 183 // Note: You may want to check and validate the float data here: 184 // 1). Many floats require integer or fraction digits, if a fraction 185 // is present. 186 // 2). All floats require either integer or fraction digits. 187 // 3). Some floats do not allow a '+' sign before the significant digits. 188 // 4). Many floats require exponent digits after the exponent symbol. 189 // 5). Some floats do not allow a '+' sign before the exponent. 190 191 // We now need to trim leading and trailing 0s from the integer 192 // and fraction, respectively. This is required to make the 193 // fast and moderate paths more efficient, and for the slow 194 // path. 195 let integer_slc = ltrim_zero(integer_slc); 196 let fraction_slc = rtrim_zero(fraction_slc); 197 198 // Create the float and return our data. 199 let mut float: F = 200 minimal_lexical::parse_float(integer_slc.iter(), fraction_slc.iter(), exponent); 201 if !is_positive { 202 float = -float; 203 } 204 205 (float, bytes) 206} 207 208macro_rules! b { 209 ($x:literal) => { 210 $x.as_bytes() 211 }; 212} 213 214#[test] 215fn f32_test() { 216 assert_eq!( 217 (184467440000000000000.0, b!("\x00\x00006")), 218 parse_float::<f32>(b"000184467440737095516150\x00\x00006") 219 ); 220} 221 222#[test] 223fn f64_test() { 224 assert_eq!( 225 (184467440737095500000.0, b!("\x00\x00006")), 226 parse_float::<f64>(b"000184467440737095516150\x00\x00006") 227 ); 228} 229