diff options
Diffstat (limited to 'semver-parser/src/common.rs')
-rw-r--r-- | semver-parser/src/common.rs | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/semver-parser/src/common.rs b/semver-parser/src/common.rs new file mode 100644 index 0000000..267b4d9 --- /dev/null +++ b/semver-parser/src/common.rs @@ -0,0 +1,66 @@ +use version::Identifier; +use recognize::{Recognize, Alt, OneOrMore, Inclusive, OneByte}; +use std::str::from_utf8; + +// by the time we get here, we know that it's all valid characters, so this doesn't need to return +// a result or anything +fn parse_meta(s: &str) -> Vec<Identifier> { + // Originally, I wanted to implement this method via calling parse, but parse is tolerant of + // leading zeroes, and we want anything with leading zeroes to be considered alphanumeric, not + // numeric. So the strategy is to check with a recognizer first, and then call parse once + // we've determined that it's a number without a leading zero. + s.split(".") + .map(|part| { + // another wrinkle: we made sure that any number starts with a + // non-zero. But there's a problem: an actual zero is a number, yet + // gets left out by this heuristic. So let's also check for the + // single, lone zero. + if is_alpha_numeric(part) { + Identifier::AlphaNumeric(part.to_string()) + } else { + // we can unwrap here because we know it is only digits due to the regex + Identifier::Numeric(part.parse().unwrap()) + } + }).collect() +} + +// parse optional metadata (preceded by the prefix character) +pub fn parse_optional_meta(s: &[u8], prefix_char: u8)-> Result<(Vec<Identifier>, usize), String> { + if let Some(len) = prefix_char.p(s) { + let start = len; + if let Some(len) = letters_numbers_dash_dot(&s[start..]) { + let end = start + len; + Ok((parse_meta(from_utf8(&s[start..end]).unwrap()), end)) + } else { + Err("Error parsing prerelease".to_string()) + } + } else { + Ok((Vec::new(), 0)) + } +} + +pub fn is_alpha_numeric(s: &str) -> bool { + if let Some((_val, len)) = numeric_identifier(s.as_bytes()) { + // Return true for number with leading zero + // Note: doing it this way also handily makes overflow fail over. + len != s.len() + } else { + true + } +} + +// Note: could plumb overflow error up to return value as Result +pub fn numeric_identifier(s: &[u8]) -> Option<(u64, usize)> { + if let Some(len) = Alt(b'0', OneOrMore(Inclusive(b'0'..b'9'))).p(s) { + from_utf8(&s[0..len]).unwrap().parse().ok().map(|val| (val, len)) + } else { + None + } +} + +pub fn letters_numbers_dash_dot(s: &[u8]) -> Option<usize> { + OneOrMore(OneByte(|c| c == b'-' || c == b'.' || + (b'0' <= c && c <= b'9') || + (b'a' <= c && c <= b'z') || + (b'A' <= c && c <= b'Z'))).p(s) +} |