1 use version
::Identifier
;
2 use recognize
::{Recognize, Alt, OneOrMore, Inclusive, OneByte}
;
3 use std
::str::from_utf8
;
5 // by the time we get here, we know that it's all valid characters, so this doesn't need to return
6 // a result or anything
7 fn parse_meta(s
: &str) -> Vec
<Identifier
> {
8 // Originally, I wanted to implement this method via calling parse, but parse is tolerant of
9 // leading zeroes, and we want anything with leading zeroes to be considered alphanumeric, not
10 // numeric. So the strategy is to check with a recognizer first, and then call parse once
11 // we've determined that it's a number without a leading zero.
14 // another wrinkle: we made sure that any number starts with a
15 // non-zero. But there's a problem: an actual zero is a number, yet
16 // gets left out by this heuristic. So let's also check for the
18 if is_alpha_numeric(part
) {
19 Identifier
::AlphaNumeric(part
.to_string())
21 // we can unwrap here because we know it is only digits due to the regex
22 Identifier
::Numeric(part
.parse().unwrap())
27 // parse optional metadata (preceded by the prefix character)
28 pub fn parse_optional_meta(s
: &[u8], prefix_char
: u8)-> Result
<(Vec
<Identifier
>, usize), String
> {
29 if let Some(len
) = prefix_char
.p(s
) {
31 if let Some(len
) = letters_numbers_dash_dot(&s
[start
..]) {
32 let end
= start
+ len
;
33 Ok((parse_meta(from_utf8(&s
[start
..end
]).unwrap()), end
))
35 Err("Error parsing prerelease".to_string())
42 pub fn is_alpha_numeric(s
: &str) -> bool
{
43 if let Some((_val
, len
)) = numeric_identifier(s
.as_bytes()) {
44 // Return true for number with leading zero
45 // Note: doing it this way also handily makes overflow fail over.
52 // Note: could plumb overflow error up to return value as Result
53 pub fn numeric_identifier(s
: &[u8]) -> Option
<(u64, usize)> {
54 if let Some(len
) = Alt(b'
0'
, OneOrMore(Inclusive(b'
0'
..b'
9'
))).p(s
) {
55 from_utf8(&s
[0..len
]).unwrap().parse().ok().map(|val
| (val
, len
))
61 pub fn letters_numbers_dash_dot(s
: &[u8]) -> Option
<usize> {
62 OneOrMore(OneByte(|c
| c
== b'
-'
|| c
== b'
.'
||
63 (b'
0'
<= c
&& c
<= b'
9'
) ||
64 (b'a'
<= c
&& c
<= b'z'
) ||
65 (b'A'
<= c
&& c
<= b'Z'
))).p(s
)