//! Release version. Releases are named vYYYYMM-NNNNN (a counter per month, from 00001); //! the release build sets CODECRAFT_VERSION (without the leading "v"). Builds without it //! (development) fall back to the crate version. pub const VERSION: &str = match option_env!("CODECRAFT_VERSION") { Some(v) if !v.is_empty() => v, _ => env!("CARGO_PKG_VERSION"), }; /// Sort key: monthly releases (YYYYMM-NNNNN) come after the old semantic versions. fn key(v: &str) -> (u8, Vec) { let v = v.trim().trim_start_matches('v'); if let Some((month, n)) = v.split_once('-') && month.len() == 6 && month.chars().all(|c| c.is_ascii_digit()) && !n.is_empty() && n.chars().all(|c| c.is_ascii_digit()) { return (1, vec![month.parse().unwrap_or(0), n.parse().unwrap_or(0)]); } (0, v.split(['.', '-']).take(3).map(|x| x.parse::().unwrap_or(0)).collect()) } /// Is version `a` newer than `b`? Accepts both schemes, with or without "v". pub fn newer(a: &str, b: &str) -> bool { key(a) > key(b) } #[cfg(test)] mod tests { use super::newer; #[test] fn compares_monthly_and_semver() { assert!(newer("v202611-00002", "202611-00001")); assert!(newer("v202612-00001", "v202611-00042")); assert!(!newer("v202611-00001", "202611-00001")); assert!(newer("v202611-00001", "0.1.0")); assert!(!newer("0.9.9", "v202611-00001")); assert!(newer("v0.2.0", "0.1.9")); assert!(newer("1.0.0", "0.9.9")); } }