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