• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /// Find and parse sign and get remaining bytes.
2 #[inline]
parse_sign<'a>(bytes: &'a [u8]) -> (bool, &'a [u8])3 fn 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]
to_digit(c: u8) -> Option<u32>13 fn to_digit(c: u8) -> Option<u32> {
14     (c as char).to_digit(10)
15 }
16 
17 // Add digit from exponent.
18 #[inline]
add_digit_i32(value: i32, digit: u32) -> Option<i32>19 fn 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]
sub_digit_i32(value: i32, digit: u32) -> Option<i32>25 fn 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]
is_digit(c: u8) -> bool31 fn is_digit(c: u8) -> bool {
32     to_digit(c).is_some()
33 }
34 
35 // Split buffer at index.
36 #[inline]
split_at_index<'a>(digits: &'a [u8], index: usize) -> (&'a [u8], &'a [u8])37 fn 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]
consume_digits<'a>(digits: &'a [u8]) -> (&'a [u8], &'a [u8])45 fn 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]
ltrim_zero<'a>(bytes: &'a [u8]) -> &'a [u8]56 fn 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]
rtrim_zero<'a>(bytes: &'a [u8]) -> &'a [u8]63 fn 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.
parse_exponent(exponent: &[u8], is_positive: bool) -> i3276 fn 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 
case_insensitive_starts_with<'a, 'b, Iter1, Iter2>(mut x: Iter1, mut y: Iter2) -> bool where Iter1: Iterator<Item = &'a u8>, Iter2: Iterator<Item = &'b u8>,101 pub fn case_insensitive_starts_with<'a, 'b, Iter1, Iter2>(mut x: Iter1, mut y: Iter2) -> bool
102 where
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.
parse_float<'a, F>(bytes: &'a [u8]) -> (F, &'a [u8]) where F: minimal_lexical::Float,130 pub fn parse_float<'a, F>(bytes: &'a [u8]) -> (F, &'a [u8])
131 where
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