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