use std::{cmp::Ordering, str::FromStr}; #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub struct Version { major: u16, minor: u16, patch: Option, } impl Ord for Version { fn cmp(&self, other: &Self) -> Ordering { let score = |v: &Version| v.major * 100 + v.minor * 10 + v.patch.unwrap_or(0); score(self).cmp(&score(other)) } } impl PartialOrd for Version { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } fn parse_number(s: &str) -> Option { s.chars() .take_while(|c| c.is_digit(10)) .collect::() .parse::() .ok() } fn parse_version(s: &str) -> Option { let mut parts = s.split('.'); let major = parse_number(parts.next()?)?; let minor = parse_number(parts.next()?)?; let patch = parts.next().map(|p| parse_number(p)).flatten(); Some(Version { major, minor, patch, }) } impl FromStr for Version { type Err = (); fn from_str(s: &str) -> Result { parse_version(s).ok_or(()) } } #[non_exhaustive] pub struct SessionInfo { nix_version: Version, } impl SessionInfo { pub fn from_version(nix_version: Version) -> Self { Self { nix_version } } pub fn version(&self) -> &Version { &self.nix_version } } #[cfg(test)] mod tests { use super::*; #[test] fn parse_trivial() { let v = "1.6.1".parse::().ok(); assert!(v.is_some()) } #[test] fn parse() { let v = "2.4pre20211006_53e4794".parse::().ok(); assert!(v.is_some()) } #[test] fn compare_trivial() { let v1 = "1.6.1".parse::().ok(); let v2 = "1.7.2".parse::().ok(); assert!(v2 > v1); } #[test] fn compare() { let v1 = "1.7".parse::().ok(); let v2 = "2.4pre20211006_53e4794".parse::().ok(); assert!(v2 >= v1); } }