use std::fmt::{Display, Formatter, Result as FmtResult};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Hash, PartialOrd, Ord)]
pub enum ArticleVersion {
#[default]
Latest,
Num(u8),
}
impl From<u8> for ArticleVersion {
fn from(val: u8) -> Self {
Self::Num(val)
}
}
impl Display for ArticleVersion {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
match self {
Self::Latest => f.write_str(""),
Self::Num(v) => write!(f, "v{v}"),
}
}
}
pub(crate) fn parse_numbervv(s: &str) -> Option<(&str, ArticleVersion)> {
if s.len() < 4 {
return None;
}
let first4 = &s[..4];
let are_digits = first4.chars().all(|c| c.is_ascii_digit());
if !are_digits {
return None;
}
let mut peek = s[4..].chars().peekable();
let number = match peek.next_if(|c| c.is_ascii_digit()) {
Some(_) => &s[..5],
None => &s[..4],
};
let mut version = ArticleVersion::Latest;
if s.len() > number.len() {
let after_number = &mut s[number.len()..].chars().peekable();
if after_number.next_if(|c| *c == 'v').is_some() {
let consume = after_number
.take_while(|c| c.is_ascii_digit())
.collect::<String>();
let version_u8 = consume.parse::<u8>().ok()?;
version = ArticleVersion::Num(version_u8);
}
}
Some((number, version))
}
#[cfg(test)]
mod test_parse_numbervv {
use crate::{parse_numbervv, ArticleVersion};
#[test]
fn is_fine() {
let parsed = parse_numbervv("0001v1").unwrap();
assert_eq!(parsed.0, "0001");
assert_eq!(parsed.1, ArticleVersion::Num(1));
}
}