1 //! Wrap the low-level API into idiomatic serializers.
2 
3 use super::format::NumberFormat;
4 use super::num::Number;
5 use super::result::Result;
6 
7 // HELPERS
8 
9 /// Map partial result to complete result.
10 macro_rules! to_complete {
11     ($cb:expr, $bytes:expr $(,$args:expr)*) => {
12         match $cb($bytes $(,$args)*) {
13             Err(e)                  => Err(e),
14             Ok((value, processed))  => if processed == $bytes.len() {
15                 Ok(value)
16             } else{
17                 Err((ErrorCode::InvalidDigit, processed).into())
18             }
19         }
20     };
21 }
22 
23 // FROM LEXICAL
24 
25 /// Trait for numerical types that can be parsed from bytes.
26 pub trait FromLexical: Number {
27     /// Checked parser for a string-to-number conversion.
28     ///
29     /// This method parses the entire string, returning an error if
30     /// any invalid digits are found during parsing.
31     ///
32     /// Returns a `Result` containing either the parsed value,
33     /// or an error containing any errors that occurred during parsing.
34     ///
35     /// Numeric overflow takes precedence over the presence of an invalid
36     /// digit, and therefore may mask an invalid digit error.
37     ///
38     /// * `bytes`   - Slice containing a numeric string.
from_lexical(bytes: &[u8]) -> Result<Self>39     fn from_lexical(bytes: &[u8]) -> Result<Self>;
40 
41     /// Checked parser for a string-to-number conversion.
42     ///
43     /// This method parses until an invalid digit is found (or the end
44     /// of the string), returning the number of processed digits
45     /// and the parsed value until that point.
46     ///
47     /// Returns a `Result` containing either the parsed value
48     /// and the number of processed digits, or an error containing
49     /// any errors that occurred during parsing.
50     ///
51     /// * `bytes`   - Slice containing a numeric string.
from_lexical_partial(bytes: &[u8]) -> Result<(Self, usize)>52     fn from_lexical_partial(bytes: &[u8]) -> Result<(Self, usize)>;
53 
54     /// Checked parser for a string-to-number conversion.
55     ///
56     /// This method parses the entire string, returning an error if
57     /// any invalid digits are found during parsing.
58     ///
59     /// Returns a `Result` containing either the parsed value,
60     /// or an error containing any errors that occurred during parsing.
61     ///
62     /// Numeric overflow takes precedence over the presence of an invalid
63     /// digit, and therefore may mask an invalid digit error.
64     ///
65     /// * `bytes`   - Slice containing a numeric string.
66     /// * `radix`   - Radix for the number parsing.
67     ///
68     /// # Panics
69     ///
70     /// Panics if the radix is not in the range `[2, 36]`.
71     #[cfg(feature = "radix")]
from_lexical_radix(bytes: &[u8], radix: u8) -> Result<Self>72     fn from_lexical_radix(bytes: &[u8], radix: u8) -> Result<Self>;
73 
74     /// Checked parser for a string-to-number conversion.
75     ///
76     /// This method parses until an invalid digit is found (or the end
77     /// of the string), returning the number of processed digits
78     /// and the parsed value until that point.
79     ///
80     /// Returns a `Result` containing either the parsed value
81     /// and the number of processed digits, or an error containing
82     /// any errors that occurred during parsing.
83     ///
84     /// * `bytes`   - Slice containing a numeric string.
85     /// * `radix`   - Radix for the number parsing.
86     ///
87     /// # Panics
88     ///
89     /// Panics if the radix is not in the range `[2, 36]`.
90     #[cfg(feature = "radix")]
from_lexical_partial_radix(bytes: &[u8], radix: u8) -> Result<(Self, usize)>91     fn from_lexical_partial_radix(bytes: &[u8], radix: u8) -> Result<(Self, usize)>;
92 }
93 
94 // Implement FromLexical for numeric type.
95 macro_rules! from_lexical {
96     ($cb:expr, $t:ty) => (
97         impl FromLexical for $t {
98             #[inline]
99             fn from_lexical(bytes: &[u8]) -> Result<$t>
100             {
101                 to_complete!($cb, bytes, 10)
102             }
103 
104             #[inline]
105             fn from_lexical_partial(bytes: &[u8]) -> Result<($t, usize)>
106             {
107                 $cb(bytes, 10)
108             }
109 
110             #[cfg(feature = "radix")]
111             #[inline]
112             fn from_lexical_radix(bytes: &[u8], radix: u8) -> Result<$t>
113             {
114                 to_complete!($cb, bytes, radix.as_u32())
115             }
116 
117             #[cfg(feature = "radix")]
118             #[inline]
119             fn from_lexical_partial_radix(bytes: &[u8], radix: u8) -> Result<($t, usize)>
120             {
121                 $cb(bytes, radix.as_u32())
122             }
123         }
124     )
125 }
126 
127 // FROM LEXICAL LOSSY
128 
129 /// Trait for floating-point types that can be parsed using lossy algorithms from bytes.
130 pub trait FromLexicalLossy: FromLexical {
131     /// Lossy, checked parser for a string-to-number conversion.
132     ///
133     /// This method parses the entire string, returning an error if
134     /// any invalid digits are found during parsing. This parser is
135     /// lossy, so numerical rounding may occur during parsing.
136     ///
137     /// Returns a `Result` containing either the parsed value,
138     /// or an error containing any errors that occurred during parsing.
139     ///
140     /// * `bytes`   - Slice containing a numeric string.
from_lexical_lossy(bytes: &[u8]) -> Result<Self>141     fn from_lexical_lossy(bytes: &[u8]) -> Result<Self>;
142 
143     /// Lossy, checked parser for a string-to-number conversion.
144     ///
145     /// This method parses until an invalid digit is found (or the end
146     /// of the string), returning the number of processed digits
147     /// and the parsed value until that point. This parser is
148     /// lossy, so numerical rounding may occur during parsing.
149     ///
150     /// Returns a `Result` containing either the parsed value
151     /// and the number of processed digits, or an error containing
152     /// any errors that occurred during parsing.
153     ///
154     /// * `bytes`   - Slice containing a numeric string.
from_lexical_partial_lossy(bytes: &[u8]) -> Result<(Self, usize)>155     fn from_lexical_partial_lossy(bytes: &[u8]) -> Result<(Self, usize)>;
156 
157     /// Lossy, checked parser for a string-to-number conversion.
158     ///
159     /// This method parses the entire string, returning an error if
160     /// any invalid digits are found during parsing. This parser is
161     /// lossy, so numerical rounding may occur during parsing.
162     ///
163     /// Returns a `Result` containing either the parsed value,
164     /// or an error containing any errors that occurred during parsing.
165     ///
166     /// * `bytes`   - Slice containing a numeric string.
167     /// * `radix`   - Radix for the number parsing.
168     ///
169     /// # Panics
170     ///
171     /// Panics if the radix is not in the range `[2, 36]`.
172     #[cfg(feature = "radix")]
from_lexical_lossy_radix(bytes: &[u8], radix: u8) -> Result<Self>173     fn from_lexical_lossy_radix(bytes: &[u8], radix: u8) -> Result<Self>;
174 
175     /// Lossy, checked parser for a string-to-number conversion.
176     ///
177     /// This method parses until an invalid digit is found (or the end
178     /// of the string), returning the number of processed digits
179     /// and the parsed value until that point. This parser is
180     /// lossy, so numerical rounding may occur during parsing.
181     ///
182     /// Returns a `Result` containing either the parsed value
183     /// and the number of processed digits, or an error containing
184     /// any errors that occurred during parsing.
185     ///
186     /// * `bytes`   - Slice containing a numeric string.
187     /// * `radix`   - Radix for the number parsing.
188     ///
189     /// # Panics
190     ///
191     /// Panics if the radix is not in the range `[2, 36]`.
192     #[cfg(feature = "radix")]
from_lexical_partial_lossy_radix(bytes: &[u8], radix: u8) -> Result<(Self, usize)>193     fn from_lexical_partial_lossy_radix(bytes: &[u8], radix: u8) -> Result<(Self, usize)>;
194 }
195 
196 // Implement FromLexicalLossy for numeric type.
197 macro_rules! from_lexical_lossy {
198     ($cb:expr, $t:ty) => (
199         impl FromLexicalLossy for $t {
200             #[inline]
201             fn from_lexical_lossy(bytes: &[u8]) -> Result<$t>
202             {
203                 to_complete!($cb, bytes, 10)
204             }
205 
206             #[inline]
207             fn from_lexical_partial_lossy(bytes: &[u8]) -> Result<($t, usize)>
208             {
209                 $cb(bytes, 10)
210             }
211 
212             #[cfg(feature = "radix")]
213             #[inline]
214             fn from_lexical_lossy_radix(bytes: &[u8], radix: u8) -> Result<$t>
215             {
216                 to_complete!($cb, bytes, radix.as_u32())
217             }
218 
219             #[cfg(feature = "radix")]
220             #[inline]
221             fn from_lexical_partial_lossy_radix(bytes: &[u8], radix: u8) -> Result<($t, usize)>
222             {
223                 $cb(bytes, radix.as_u32())
224             }
225         }
226     )
227 }
228 
229 // FROM LEXICAL FORMAT
230 
231 /// Trait for number that can be parsed using a custom format specification.
232 #[cfg(feature = "format")]
233 pub trait FromLexicalFormat: FromLexical {
234     /// Checked parser for a string-to-number conversion.
235     ///
236     /// This method parses the entire string, returning an error if
237     /// any invalid digits are found during parsing. The numerical format
238     /// is specified by the format bitflags, which customize the required
239     /// components, digit separators, and other parameters of the number.
240     ///
241     /// Returns a `Result` containing either the parsed value,
242     /// or an error containing any errors that occurred during parsing.
243     ///
244     /// * `bytes`   - Slice containing a numeric string.
245     /// * `format`  - Numerical format.
from_lexical_format(bytes: &[u8], format: NumberFormat) -> Result<Self>246     fn from_lexical_format(bytes: &[u8], format: NumberFormat) -> Result<Self>;
247 
248     /// Checked parser for a string-to-number conversion.
249     ///
250     /// This method parses until an invalid digit is found (or the end
251     /// of the string), returning the number of processed digits
252     /// and the parsed value until that point. The numerical format
253     /// is specified by the format bitflags, which customize the required
254     /// components, digit separators, and other parameters of the number.
255     ///
256     /// Returns a `Result` containing either the parsed value
257     /// and the number of processed digits, or an error containing
258     /// any errors that occurred during parsing.
259     ///
260     /// * `bytes`   - Slice containing a numeric string.
261     /// * `format`  - Numerical format.
from_lexical_partial_format(bytes: &[u8], format: NumberFormat) -> Result<(Self, usize)>262     fn from_lexical_partial_format(bytes: &[u8], format: NumberFormat) -> Result<(Self, usize)>;
263 
264     /// Checked parser for a string-to-number conversion.
265     ///
266     /// This method parses the entire string, returning an error if
267     /// any invalid digits are found during parsing. The numerical format
268     /// is specified by the format bitflags, which customize the required
269     /// components, digit separators, and other parameters of the number.
270     ///
271     /// Returns a `Result` containing either the parsed value,
272     /// or an error containing any errors that occurred during parsing.
273     ///
274     /// * `bytes`   - Slice containing a numeric string.
275     /// * `radix`   - Radix for the number parsing.
276     /// * `format`  - Numerical format.
277     ///
278     /// # Panics
279     ///
280     /// Panics if the radix is not in the range `[2, 36]`.
281     #[cfg(feature = "radix")]
from_lexical_format_radix(bytes: &[u8], radix: u8, format: NumberFormat) -> Result<Self>282     fn from_lexical_format_radix(bytes: &[u8], radix: u8, format: NumberFormat) -> Result<Self>;
283 
284     /// Checked parser for a string-to-number conversion.
285     ///
286     /// This method parses until an invalid digit is found (or the end
287     /// of the string), returning the number of processed digits
288     /// and the parsed value until that point. The numerical format
289     /// is specified by the format bitflags, which customize the required
290     /// components, digit separators, and other parameters of the number.
291     ///
292     /// Returns a `Result` containing either the parsed value
293     /// and the number of processed digits, or an error containing
294     /// any errors that occurred during parsing.
295     ///
296     /// * `bytes`   - Slice containing a numeric string.
297     /// * `radix`   - Radix for the number parsing.
298     /// * `format`  - Numerical format.
299     ///
300     /// # Panics
301     ///
302     /// Panics if the radix is not in the range `[2, 36]`.
303     #[cfg(feature = "radix")]
from_lexical_partial_format_radix(bytes: &[u8], radix: u8, format: NumberFormat) -> Result<(Self, usize)>304     fn from_lexical_partial_format_radix(bytes: &[u8], radix: u8, format: NumberFormat) -> Result<(Self, usize)>;
305 }
306 
307 // Implement FromLexicalFormat for numeric type.
308 #[cfg(feature = "format")]
309 macro_rules! from_lexical_format {
310     ($cb:expr, $t:ty) => (
311         impl FromLexicalFormat for $t {
312             #[inline]
313             fn from_lexical_format(bytes: &[u8], format: NumberFormat) -> Result<$t>
314             {
315                 to_complete!($cb, bytes, 10, format)
316             }
317 
318             #[inline]
319             fn from_lexical_partial_format(bytes: &[u8], format: NumberFormat) -> Result<($t, usize)>
320             {
321                 $cb(bytes, 10, format)
322             }
323 
324             #[cfg(feature = "radix")]
325             #[inline]
326             fn from_lexical_format_radix(bytes: &[u8], radix: u8, format: NumberFormat) -> Result<$t>
327             {
328                 to_complete!($cb, bytes, radix.as_u32(), format)
329             }
330 
331             #[cfg(feature = "radix")]
332             #[inline]
333             fn from_lexical_partial_format_radix(bytes: &[u8], radix: u8, format: NumberFormat) -> Result<($t, usize)>
334             {
335                 $cb(bytes, radix.as_u32(), format)
336             }
337         }
338     )
339 }
340 
341 // FROM LEXICAL LOSSY
342 
343 /// Trait for floating-point types that can be parsed using lossy algorithms with a custom format specification.
344 #[cfg(feature = "format")]
345 pub trait FromLexicalLossyFormat: FromLexical {
346     /// Lossy, checked parser for a string-to-number conversion.
347     ///
348     /// This method parses the entire string, returning an error if
349     /// any invalid digits are found during parsing. This parser is
350     /// lossy, so numerical rounding may occur during parsing. The
351     /// numerical format is specified by the format bitflags, which
352     /// customize the required components, digit separators, and other
353     /// parameters of the number.
354     ///
355     /// Returns a `Result` containing either the parsed value,
356     /// or an error containing any errors that occurred during parsing.
357     ///
358     /// * `bytes`   - Slice containing a numeric string.
359     /// * `format`  - Numerical format.
from_lexical_lossy_format(bytes: &[u8], format: NumberFormat) -> Result<Self>360     fn from_lexical_lossy_format(bytes: &[u8], format: NumberFormat) -> Result<Self>;
361 
362     /// Lossy, checked parser for a string-to-number conversion.
363     ///
364     /// This method parses until an invalid digit is found (or the end
365     /// of the string), returning the number of processed digits
366     /// and the parsed value until that point. This parser is
367     /// lossy, so numerical rounding may occur during parsing. The
368     /// numerical format is specified by the format bitflags, which
369     /// customize the required components, digit separators, and other
370     /// parameters of the number.
371     ///
372     /// Returns a `Result` containing either the parsed value
373     /// and the number of processed digits, or an error containing
374     /// any errors that occurred during parsing.
375     ///
376     /// * `bytes`   - Slice containing a numeric string.
377     /// * `format`  - Numerical format.
from_lexical_partial_lossy_format(bytes: &[u8], format: NumberFormat) -> Result<(Self, usize)>378     fn from_lexical_partial_lossy_format(bytes: &[u8], format: NumberFormat) -> Result<(Self, usize)>;
379 
380     /// Lossy, checked parser for a string-to-number conversion.
381     ///
382     /// This method parses the entire string, returning an error if
383     /// any invalid digits are found during parsing. This parser is
384     /// lossy, so numerical rounding may occur during parsing. The
385     /// numerical format is specified by the format bitflags, which
386     /// customize the required components, digit separators, and other
387     /// parameters of the number.
388     ///
389     /// Returns a `Result` containing either the parsed value,
390     /// or an error containing any errors that occurred during parsing.
391     ///
392     /// * `bytes`   - Slice containing a numeric string.
393     /// * `radix`   - Radix for the number parsing.
394     /// * `format`  - Numerical format.
395     ///
396     /// # Panics
397     ///
398     /// Panics if the radix is not in the range `[2, 36]`.
399     #[cfg(feature = "radix")]
from_lexical_lossy_format_radix(bytes: &[u8], radix: u8, format: NumberFormat) -> Result<Self>400     fn from_lexical_lossy_format_radix(bytes: &[u8], radix: u8, format: NumberFormat) -> Result<Self>;
401 
402     /// Lossy, checked parser for a string-to-number conversion.
403     ///
404     /// This method parses until an invalid digit is found (or the end
405     /// of the string), returning the number of processed digits
406     /// and the parsed value until that point. This parser is
407     /// lossy, so numerical rounding may occur during parsing. The
408     /// numerical format is specified by the format bitflags, which
409     /// customize the required components, digit separators, and other
410     /// parameters of the number.
411     ///
412     /// Returns a `Result` containing either the parsed value
413     /// and the number of processed digits, or an error containing
414     /// any errors that occurred during parsing.
415     ///
416     /// * `bytes`   - Slice containing a numeric string.
417     /// * `radix`   - Radix for the number parsing.
418     /// * `format`  - Numerical format.
419     ///
420     /// # Panics
421     ///
422     /// Panics if the radix is not in the range `[2, 36]`.
423     #[cfg(feature = "radix")]
from_lexical_partial_lossy_format_radix(bytes: &[u8], radix: u8, format: NumberFormat) -> Result<(Self, usize)>424     fn from_lexical_partial_lossy_format_radix(bytes: &[u8], radix: u8, format: NumberFormat) -> Result<(Self, usize)>;
425 }
426 
427 // Implement FromLexicalLossyFormat for numeric type.
428 #[cfg(feature = "format")]
429 macro_rules! from_lexical_lossy_format {
430     ($cb:expr, $t:ty) => (
431         impl FromLexicalLossyFormat for $t {
432             #[inline]
433             fn from_lexical_lossy_format(bytes: &[u8], format: NumberFormat)
434                 -> Result<$t>
435             {
436                 to_complete!($cb, bytes, 10, format)
437             }
438 
439             #[inline]
440             fn from_lexical_partial_lossy_format(bytes: &[u8], format: NumberFormat)
441                 -> Result<($t, usize)>
442             {
443                 $cb(bytes, 10, format)
444             }
445 
446             #[cfg(feature = "radix")]
447             #[inline]
448             fn from_lexical_lossy_format_radix(bytes: &[u8], radix: u8, format: NumberFormat)
449                 -> Result<$t>
450             {
451                 to_complete!($cb, bytes, radix.as_u32(), format)
452             }
453 
454             #[cfg(feature = "radix")]
455             #[inline]
456             fn from_lexical_partial_lossy_format_radix(bytes: &[u8], radix: u8, format: NumberFormat)
457                 -> Result<($t, usize)>
458             {
459                 $cb(bytes, radix.as_u32(), format)
460             }
461         }
462     )
463 }
464 
465 // TO LEXICAL
466 
467 /// Trait for numerical types that can be serialized to bytes.
468 ///
469 /// To determine the number of bytes required to serialize a value to
470 /// string, check the associated constants from a required trait:
471 /// - [`FORMATTED_SIZE`]
472 /// - [`FORMATTED_SIZE_DECIMAL`]
473 ///
474 /// [`FORMATTED_SIZE`]: trait.Number.html#associatedconstant.FORMATTED_SIZE
475 /// [`FORMATTED_SIZE_DECIMAL`]: trait.Number.html#associatedconstant.FORMATTED_SIZE_DECIMAL
476 pub trait ToLexical: Number {
477     /// Serializer for a number-to-string conversion.
478     ///
479     /// Returns a subslice of the input buffer containing the written bytes,
480     /// starting from the same address in memory as the input slice.
481     ///
482     /// * `value`   - Number to serialize.
483     /// * `bytes`   - Slice containing a numeric string.
484     ///
485     /// # Panics
486     ///
487     /// Panics if the buffer is not of sufficient size. The caller
488     /// must provide a slice of sufficient size. In order to ensure
489     /// the function will not panic, ensure the buffer has at least
490     /// [`FORMATTED_SIZE_DECIMAL`] elements.
491     ///
492     /// [`FORMATTED_SIZE_DECIMAL`]: trait.Number.html#associatedconstant.FORMATTED_SIZE_DECIMAL
to_lexical<'a>(self, bytes: &'a mut [u8]) -> &'a mut [u8]493     fn to_lexical<'a>(self, bytes: &'a mut [u8]) -> &'a mut [u8];
494 
495      /// Serializer for a number-to-string conversion.
496     ///
497     /// Returns a subslice of the input buffer containing the written bytes,
498     /// starting from the same address in memory as the input slice.
499     ///
500     /// * `value`   - Number to serialize.
501     /// * `radix`   - Radix for number encoding.
502     /// * `bytes`   - Slice containing a numeric string.
503     ///
504     /// # Panics
505     ///
506     /// Panics if the radix is not in the range `[2, 36]`.
507     ///
508     /// Also panics if the buffer is not of sufficient size. The caller
509     /// must provide a slice of sufficient size. In order to ensure
510     /// the function will not panic, ensure the buffer has at least
511     /// [`FORMATTED_SIZE`] elements.
512     ///
513     /// [`FORMATTED_SIZE`]: trait.Number.html#associatedconstant.FORMATTED_SIZE
514     #[cfg(feature = "radix")]
to_lexical_radix<'a>(self, radix: u8, bytes: &'a mut [u8]) -> &'a mut [u8]515     fn to_lexical_radix<'a>(self, radix: u8, bytes: &'a mut [u8]) -> &'a mut [u8];
516 }
517 
518 // Implement ToLexical for numeric type.
519 macro_rules! to_lexical {
520     ($cb:expr, $t:ty) => (
521         impl ToLexical for $t {
522             #[inline]
523             fn to_lexical<'a>(self, bytes: &'a mut [u8])
524                 -> &'a mut [u8]
525             {
526                 assert_buffer!(10, bytes, $t);
527                 let len = $cb(self, 10, bytes);
528                 &mut index_mut!(bytes[..len])
529             }
530 
531             #[cfg(feature = "radix")]
532             #[inline]
533             fn to_lexical_radix<'a>(self, radix: u8, bytes: &'a mut [u8])
534                 -> &'a mut [u8]
535             {
536                 assert_radix!(radix);
537                 assert_buffer!(radix, bytes, $t);
538                 let len = $cb(self, radix.as_u32(), bytes);
539                 &mut index_mut!(bytes[..len])
540             }
541         }
542     )
543 }
544