1 // Copyright 2018 Brian Smith.
2 //
3 // Permission to use, copy, modify, and/or distribute this software for any
4 // purpose with or without fee is hereby granted, provided that the above
5 // copyright notice and this permission notice appear in all copies.
6 //
7 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
8 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
10 // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 
15 //! Serialization and deserialization.
16 
17 use crate::error;
18 
19 /// A serialized positive integer.
20 #[derive(Copy, Clone)]
21 pub struct Positive<'a>(untrusted::Input<'a>);
22 
23 impl<'a> Positive<'a> {
24     #[inline]
from_be_bytes(input: untrusted::Input<'a>) -> Result<Self, error::Unspecified>25     pub(crate) fn from_be_bytes(input: untrusted::Input<'a>) -> Result<Self, error::Unspecified> {
26         // Empty inputs are not allowed.
27         let &first_byte = input
28             .as_slice_less_safe()
29             .first()
30             .ok_or(error::Unspecified)?;
31         // Zero isn't allowed and leading zeros aren't allowed.
32         if first_byte == 0 {
33             return Err(error::Unspecified);
34         }
35         Ok(Self(input))
36     }
37 
38     /// Returns the value, ordered from significant byte to least significant
39     /// byte, without any leading zeros. The result is guaranteed to be
40     /// non-empty.
41     #[inline]
big_endian_without_leading_zero(&self) -> &'a [u8]42     pub fn big_endian_without_leading_zero(&self) -> &'a [u8] {
43         self.big_endian_without_leading_zero_as_input()
44             .as_slice_less_safe()
45     }
46 
47     #[inline]
big_endian_without_leading_zero_as_input(&self) -> untrusted::Input<'a>48     pub(crate) fn big_endian_without_leading_zero_as_input(&self) -> untrusted::Input<'a> {
49         self.0
50     }
51 }
52 
53 impl Positive<'_> {
54     /// Returns the first byte.
55     ///
56     /// Will not panic because the value is guaranteed to have at least one
57     /// byte.
first_byte(&self) -> u858     pub fn first_byte(&self) -> u8 {
59         // This won't panic because
60         self.0.as_slice_less_safe()[0]
61     }
62 }
63 
64 #[cfg(test)]
65 mod tests {
66     use super::*;
67 
68     #[test]
test_from_be_bytes()69     fn test_from_be_bytes() {
70         static TEST_CASES: &[(&[u8], Result<&[u8], error::Unspecified>)] = &[
71             // An empty input isn't a number.
72             (&[], Err(error::Unspecified)),
73             // Zero is not positive.
74             (&[0x00], Err(error::Unspecified)),
75             // Minimum value. No leading zero required or allowed.
76             (&[0x00, 0x01], Err(error::Unspecified)),
77             (&[0x01], Ok(&[0x01])),
78             // Maximum first byte. No leading zero required or allowed.
79             (&[0xff], Ok(&[0xff])),
80             (&[0x00, 0xff], Err(error::Unspecified)),
81             // The last byte can be zero.
82             (&[0x01, 0x00], Ok(&[0x01, 0x00])),
83             (&[0x01, 0x00, 0x00], Ok(&[0x01, 0x00, 0x00])),
84             // Having no zero bytes are also allowed.
85             (&[0x01, 0x01], Ok(&[0x01, 0x01])),
86             // A middle byte can be zero.
87             (&[0x01, 0x00, 0x01], Ok(&[0x01, 0x00, 0x01])),
88             (&[0x01, 0x01, 0x01], Ok(&[0x01, 0x01, 0x01])),
89         ];
90         for &(input, result) in TEST_CASES {
91             let input = untrusted::Input::from(input);
92             assert_eq!(
93                 Positive::from_be_bytes(input).map(|p| p.big_endian_without_leading_zero()),
94                 result
95             );
96         }
97     }
98 }
99