pub fn parse_release_version(s: &str) -> Option<(u32, u32, u32)> {
let mut parts = s.split('.');
let major = parts.next()?.parse::<u32>().ok()?;
let minor = parts.next()?.parse::<u32>().ok()?;
let patch = match parts.next() {
Some(raw) => {
let digits: String = raw.chars().take_while(|c| c.is_ascii_digit()).collect();
if digits.is_empty() {
return None;
}
digits.parse::<u32>().ok()?
}
None => 0,
};
Some((major, minor, patch))
}
pub fn supports_at_least(parsed: (u32, u32, u32), major: u32, minor: u32) -> bool {
(parsed.0, parsed.1) >= (major, minor)
}
pub fn supports_native_parquet_import(v: (u32, u32, u32)) -> bool {
v >= (2025, 1, 11)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_two_and_three_component_versions() {
assert_eq!(parse_release_version("7.1"), Some((7, 1, 0)));
assert_eq!(parse_release_version("2025.1.11"), Some((2025, 1, 11)));
assert_eq!(parse_release_version("8.31.0"), Some((8, 31, 0)));
}
#[test]
fn test_parse_rejects_garbage_strings() {
assert_eq!(parse_release_version(""), None);
assert_eq!(parse_release_version("foo.bar"), None);
assert_eq!(parse_release_version("2025"), None);
}
#[test]
fn test_parse_trailing_suffix_tolerated() {
assert_eq!(parse_release_version("2025.1.11-rc1"), Some((2025, 1, 11)));
assert_eq!(parse_release_version("8.31.0+build"), Some((8, 31, 0)));
}
#[test]
fn test_supports_native_parquet_import_threshold_boundaries() {
assert!(!supports_native_parquet_import((2025, 1, 10)));
assert!(supports_native_parquet_import((2025, 1, 11)));
assert!(supports_native_parquet_import((2025, 2, 0)));
assert!(supports_native_parquet_import((2026, 0, 0)));
assert!(!supports_native_parquet_import((7, 1, 0)));
assert!(!supports_native_parquet_import((8, 31, 0)));
}
}