收录版本号比较方法
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
//! ## Modules
|
||||
//!
|
||||
//! - [`websocket`] - WebSocket client and server implementations
|
||||
//! - [`version`] - Version string comparison utilities
|
||||
//!
|
||||
//! ## Quick Start
|
||||
//!
|
||||
@@ -27,7 +28,19 @@
|
||||
//! client.connect().await;
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! ## Version Comparison
|
||||
//!
|
||||
//! ```rust
|
||||
//! use cube_lib::version::{version_less_than, needs_update};
|
||||
//!
|
||||
//! // Check if update is needed
|
||||
//! assert!(version_less_than("1.0.0", "1.0.1"));
|
||||
//! assert!(needs_update("1.0.0", "1.0.1"));
|
||||
//! ```
|
||||
|
||||
pub mod websocket;
|
||||
pub mod version;
|
||||
|
||||
pub use websocket::{WebSocketClient, WebSocketConfig, WebSocketMessage, OutgoingMessage, ConnectionStatus, ReconnectedCallback, MessageSender};
|
||||
pub use version::{version_less_than, compare_versions, needs_update, parse_version};
|
||||
|
||||
139
Windows/Rust/CubeLib/src/version.rs
Normal file
139
Windows/Rust/CubeLib/src/version.rs
Normal file
@@ -0,0 +1,139 @@
|
||||
//! # Version utilities
|
||||
//!
|
||||
//! Provides version string comparison utilities for semver-like version strings.
|
||||
|
||||
use std::cmp::Ordering;
|
||||
|
||||
/// Parse a version string into a vector of unsigned integers.
|
||||
///
|
||||
/// "1.2.3" → [1, 2, 3]
|
||||
/// "1.2" → [1, 2]
|
||||
/// "1.2.3.4.5" → [1, 2, 3, 4, 5]
|
||||
/// "" or invalid parts are skipped.
|
||||
pub fn parse_version(version: &str) -> Vec<u32> {
|
||||
version
|
||||
.split('.')
|
||||
.filter(|s| !s.is_empty())
|
||||
.filter_map(|s| s.parse().ok())
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Compare two version strings.
|
||||
///
|
||||
/// Returns `true` if `current < required` (i.e. current needs to be updated).
|
||||
///
|
||||
/// Comparison is done part-by-part (split by `.`).
|
||||
/// Missing parts are treated as `0`.
|
||||
/// Examples:
|
||||
/// - `"1.0.0"` < `"1.0.1"` → true
|
||||
/// - `"1.0.0"` < `"1.1.0"` → true
|
||||
/// - `"1.0.0"` < `"2.0.0"` → true
|
||||
/// - `"1.0.0"` < `"1.0.0"` → false (equal)
|
||||
/// - `"1.0.1"` < `"1.0.0"` → false
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `current` - The current/local version string
|
||||
/// * `required` - The required/server version string
|
||||
pub fn version_less_than(current: &str, required: &str) -> bool {
|
||||
compare_versions(current, required) == Ordering::Less
|
||||
}
|
||||
|
||||
/// Compare two version strings, returning the standard `Ordering` result.
|
||||
///
|
||||
/// This is the canonical comparison function. Use [`version_less_than`] if you
|
||||
/// only need a boolean upgrade check.
|
||||
pub fn compare_versions(a: &str, b: &str) -> Ordering {
|
||||
let a_parts = parse_version(a);
|
||||
let b_parts = parse_version(b);
|
||||
|
||||
let max_len = a_parts.len().max(b_parts.len());
|
||||
|
||||
for i in 0..max_len {
|
||||
let av = a_parts.get(i).copied().unwrap_or(0);
|
||||
let bv = b_parts.get(i).copied().unwrap_or(0);
|
||||
|
||||
match av.cmp(&bv) {
|
||||
Ordering::Less => return Ordering::Less,
|
||||
Ordering::Greater => return Ordering::Greater,
|
||||
Ordering::Equal => continue,
|
||||
}
|
||||
}
|
||||
|
||||
Ordering::Equal
|
||||
}
|
||||
|
||||
/// Check if a local version is outdated compared to a server version.
|
||||
///
|
||||
/// Returns `true` if:
|
||||
/// - local is "0.0.0" / empty (file does not exist)
|
||||
/// - local version < server version
|
||||
pub fn needs_update(local_version: &str, server_version: &str) -> bool {
|
||||
local_version == "0.0.0"
|
||||
|| local_version.is_empty()
|
||||
|| version_less_than(local_version, server_version)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_parse_version() {
|
||||
assert_eq!(parse_version("1.2.3"), vec![1, 2, 3]);
|
||||
assert_eq!(parse_version("1.2"), vec![1, 2]);
|
||||
assert_eq!(parse_version("1.2.3.4.5"), vec![1, 2, 3, 4, 5]);
|
||||
assert_eq!(parse_version(""), Vec::<u32>::new());
|
||||
assert_eq!(parse_version("1..3"), vec![1, 3]);
|
||||
assert_eq!(parse_version("abc"), Vec::<u32>::new());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_version_less_than() {
|
||||
// Basic comparisons
|
||||
assert!(version_less_than("1.0.0", "1.0.1"));
|
||||
assert!(version_less_than("1.0.0", "1.1.0"));
|
||||
assert!(version_less_than("1.0.0", "2.0.0"));
|
||||
assert!(version_less_than("0.0.1", "0.0.2"));
|
||||
|
||||
// Equal versions
|
||||
assert!(!version_less_than("1.0.0", "1.0.0"));
|
||||
assert!(!version_less_than("1.2.3", "1.2.3"));
|
||||
|
||||
// Newer local version
|
||||
assert!(!version_less_than("1.0.1", "1.0.0"));
|
||||
assert!(!version_less_than("2.0.0", "1.0.0"));
|
||||
|
||||
// Different part counts
|
||||
assert!(version_less_than("1.0", "1.0.1"));
|
||||
assert!(version_less_than("1", "1.0.1"));
|
||||
assert!(version_less_than("1.0.0", "1.0.0.1"));
|
||||
assert!(version_less_than("1", "2"));
|
||||
|
||||
// Treats missing parts as 0
|
||||
assert!(version_less_than("1", "1.0.1"));
|
||||
assert!(!version_less_than("1.0.0", "1"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_compare_versions() {
|
||||
use std::cmp::Ordering;
|
||||
assert_eq!(compare_versions("1.0.0", "1.0.1"), Ordering::Less);
|
||||
assert_eq!(compare_versions("1.0.1", "1.0.0"), Ordering::Greater);
|
||||
assert_eq!(compare_versions("1.0.0", "1.0.0"), Ordering::Equal);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_needs_update() {
|
||||
// Missing local
|
||||
assert!(needs_update("0.0.0", "1.0.0"));
|
||||
assert!(needs_update("", "1.0.0"));
|
||||
|
||||
// Needs update
|
||||
assert!(needs_update("1.0.0", "1.0.1"));
|
||||
assert!(needs_update("1.0.0", "2.0.0"));
|
||||
|
||||
// Already up to date
|
||||
assert!(!needs_update("1.0.0", "1.0.0"));
|
||||
assert!(!needs_update("1.0.1", "1.0.0"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user