Skip to main content

xds_core/
version.rs

1//! Resource version tracking for xDS.
2//!
3//! This module provides [`ResourceVersion`], a type for tracking versions
4//! of xDS resources. Versions are used to detect changes and avoid
5//! sending unchanged resources.
6
7use std::fmt;
8
9/// Version identifier for xDS resources.
10///
11/// `ResourceVersion` wraps a version string and provides ordering and
12/// comparison operations. An empty version represents the initial state
13/// (no version received yet).
14///
15/// # Example
16///
17/// ```rust
18/// use xds_core::ResourceVersion;
19///
20/// let v1 = ResourceVersion::new("v1");
21/// let v2 = ResourceVersion::new("v2");
22/// let empty = ResourceVersion::empty();
23///
24/// assert!(!v1.is_empty());
25/// assert!(empty.is_empty());
26/// assert_ne!(v1, v2);
27/// ```
28#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
29pub struct ResourceVersion(String);
30
31impl ResourceVersion {
32    /// Create a new resource version from a string.
33    #[must_use]
34    pub fn new(version: impl Into<String>) -> Self {
35        Self(version.into())
36    }
37
38    /// Create an empty resource version (initial state).
39    #[must_use]
40    pub fn empty() -> Self {
41        Self(String::new())
42    }
43
44    /// Check if the version is empty (initial state).
45    #[must_use]
46    pub fn is_empty(&self) -> bool {
47        self.0.is_empty()
48    }
49
50    /// Get the version as a string slice.
51    #[must_use]
52    pub fn as_str(&self) -> &str {
53        &self.0
54    }
55
56    /// Consume and return the inner string.
57    #[must_use]
58    pub fn into_inner(self) -> String {
59        self.0
60    }
61}
62
63impl fmt::Display for ResourceVersion {
64    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65        write!(f, "{}", self.0)
66    }
67}
68
69impl From<String> for ResourceVersion {
70    fn from(s: String) -> Self {
71        Self(s)
72    }
73}
74
75impl From<&str> for ResourceVersion {
76    fn from(s: &str) -> Self {
77        Self(s.to_string())
78    }
79}
80
81impl From<ResourceVersion> for String {
82    fn from(v: ResourceVersion) -> Self {
83        v.0
84    }
85}
86
87impl AsRef<str> for ResourceVersion {
88    fn as_ref(&self) -> &str {
89        &self.0
90    }
91}
92
93#[cfg(test)]
94mod tests {
95    use super::*;
96
97    #[test]
98    fn test_version_creation() {
99        let v = ResourceVersion::new("v1");
100        assert_eq!(v.as_str(), "v1");
101        assert!(!v.is_empty());
102    }
103
104    #[test]
105    fn test_empty_version() {
106        let v = ResourceVersion::empty();
107        assert!(v.is_empty());
108        assert_eq!(v.as_str(), "");
109    }
110
111    #[test]
112    fn test_version_equality() {
113        let v1 = ResourceVersion::new("v1");
114        let v1_copy = ResourceVersion::new("v1");
115        let v2 = ResourceVersion::new("v2");
116
117        assert_eq!(v1, v1_copy);
118        assert_ne!(v1, v2);
119    }
120
121    #[test]
122    fn test_version_from_string() {
123        let v: ResourceVersion = "v1".into();
124        assert_eq!(v.as_str(), "v1");
125
126        let v: ResourceVersion = String::from("v2").into();
127        assert_eq!(v.as_str(), "v2");
128    }
129
130    #[test]
131    fn test_version_display() {
132        let v = ResourceVersion::new("v1.2.3");
133        assert_eq!(format!("{v}"), "v1.2.3");
134    }
135}