version_number/parsers/original/
parser.rs

1use crate::parsers::original::{ErrorReason, NumberError, OriginalParserError};
2
3macro_rules! to_number {
4    ($initial:expr) => {
5        Ok(u64::from($initial - b'0'))
6    };
7    ($current:expr, $next:expr) => {{
8        $current
9            .checked_mul(10)
10            .and_then(|c| c.checked_add(u64::from($next - b'0')))
11            .ok_or_else(|| NumberError::Overflow)
12    }};
13}
14
15type Number = u64;
16
17#[derive(Copy, Clone)]
18struct NumberConstructor(Number);
19
20impl NumberConstructor {
21    fn try_new(digit: u8) -> Result<Self, NumberError> {
22        to_number!(digit).map(NumberConstructor)
23    }
24
25    fn append_digit(&mut self, digit: u8) -> Result<(), NumberError> {
26        if self.0 == 0 {
27            return Err(NumberError::LeadingZero);
28        }
29
30        self.0 = to_number!(self.0, digit)?;
31
32        Ok(())
33    }
34
35    fn as_value(&self) -> Number {
36        self.0
37    }
38}
39
40struct NumberComponent(Option<NumberConstructor>);
41
42impl NumberComponent {
43    fn new() -> Self {
44        Self(None)
45    }
46
47    fn insert_digit(&mut self, token: u8) -> Result<(), NumberError> {
48        if let Some(num) = &mut self.0 {
49            // A digit was already pushed
50            num.append_digit(token)
51        } else {
52            let number = NumberConstructor::try_new(token)?;
53            self.0 = Some(number);
54            Ok(())
55        }
56    }
57
58    fn get(&self) -> Option<NumberConstructor> {
59        self.0
60    }
61}
62
63/// The _orignal parser_ Parser 😊.
64///
65/// # Example
66///
67/// ```
68/// use version_number::parsers::original::Parser;
69/// use version_number::Version;
70///
71/// let parser = Parser::from_slice("1.2.3".as_bytes());
72/// let version = parser.parse().unwrap();
73///
74/// assert_eq!(version, Version::new_full_version(1, 2,3));
75/// ```
76pub struct Parser<'slice> {
77    pub(crate) slice: &'slice [u8],
78}
79
80impl<'slice> Parser<'slice> {
81    /// Construct a new [`Parser`] from a slice of bytes.
82    ///
83    /// # Example
84    ///
85    /// ```
86    /// use version_number::parsers::original::Parser;
87    ///
88    /// let _parser = Parser::from_slice("1.2".as_bytes());
89    /// ```
90    pub fn from_slice(slice: &'slice [u8]) -> Self {
91        Parser { slice }
92    }
93
94    /// Parse a two- or three component version number from the given input.
95    ///
96    /// # Example
97    ///
98    /// ```
99    /// use version_number::parsers::original::Parser;
100    /// use version_number::Version;
101    ///
102    /// let parser = Parser::from_slice("1.2".as_bytes());
103    /// let version = parser.parse().unwrap();
104    ///
105    /// assert_eq!(version, Version::new_base_version(1, 2));
106    pub fn parse(&self) -> Result<crate::Version, OriginalParserError> {
107        let mut cursor = 0;
108
109        let first = self.parse_number(&mut cursor)?;
110        self.parse_dot(&mut cursor)?;
111        let second = self.parse_number(&mut cursor)?;
112
113        if self.is_done(cursor) {
114            // is_done = true
115            return Ok(crate::Version::Base(crate::BaseVersion {
116                major: first.as_value(),
117                minor: second.as_value(),
118            }));
119        }
120
121        // is_done = false
122        self.parse_dot(&mut cursor)?;
123        let third = self.parse_number(&mut cursor)?;
124
125        if self.is_done(cursor) {
126            // is_done = true
127            return Ok(crate::Version::Full(crate::FullVersion {
128                major: first.as_value(),
129                minor: second.as_value(),
130                patch: third.as_value(),
131            }));
132        }
133
134        Err(OriginalParserError::from_parser_with_cursor(
135            self,
136            cursor,
137            ErrorReason::ExpectedEndOfInput {
138                extra_input: self.slice[cursor..].to_vec(),
139            },
140        ))
141    }
142
143    fn parse_number(&self, cursor: &mut usize) -> Result<NumberConstructor, OriginalParserError> {
144        let mut value = NumberComponent::new();
145
146        while let Some(&b) = self.slice.get(*cursor) {
147            if !b.is_ascii_digit() {
148                break;
149            }
150
151            value
152                .insert_digit(b)
153                .map_err(|error| OriginalParserError::from_parser(self, error.into()))?;
154
155            *cursor += 1;
156        }
157
158        value.get().ok_or_else(|| {
159            OriginalParserError::from_parser_with_cursor(
160                self,
161                *cursor,
162                ErrorReason::ExpectedNumericToken { got: None },
163            )
164        })
165    }
166
167    fn parse_dot(&self, cursor: &mut usize) -> Result<(), OriginalParserError> {
168        match self.slice.get(*cursor) {
169            Some(&b'.') => {
170                *cursor += 1;
171                Ok(())
172            }
173            Some(&b) => Err(OriginalParserError::from_parser_with_cursor(
174                self,
175                *cursor,
176                ErrorReason::ExpectedSeparator { got: Some(b) },
177            )),
178            None => Err(OriginalParserError::from_parser_with_cursor(
179                self,
180                *cursor,
181                ErrorReason::ExpectedSeparator { got: None },
182            )),
183        }
184    }
185
186    fn is_done(&self, cursor: usize) -> bool {
187        cursor >= self.slice.len()
188    }
189}
190
191impl<'b, T> From<T> for Parser<'b>
192where
193    T: Into<&'b [u8]>,
194{
195    fn from(item: T) -> Self {
196        Parser { slice: item.into() }
197    }
198}