version_number/parsers/original/
parser.rs1use 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 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
63pub struct Parser<'slice> {
77 pub(crate) slice: &'slice [u8],
78}
79
80impl<'slice> Parser<'slice> {
81 pub fn from_slice(slice: &'slice [u8]) -> Self {
91 Parser { slice }
92 }
93
94 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 return Ok(crate::Version::Base(crate::BaseVersion {
116 major: first.as_value(),
117 minor: second.as_value(),
118 }));
119 }
120
121 self.parse_dot(&mut cursor)?;
123 let third = self.parse_number(&mut cursor)?;
124
125 if self.is_done(cursor) {
126 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}