alpm_ll/
version.rs

1use std::cmp::Ordering;
2use std::ffi::CStr;
3use std::ffi::CString;
4use std::fmt;
5use std::ops::Deref;
6use std::os::raw::c_char;
7
8use alpm_sys_ll::*;
9
10use crate::LIBRARY;
11use crate::Library;
12
13pub fn vercmp<S: Into<Vec<u8>>>(a: S, b: S) -> Ordering {
14    let a = Version::new(a);
15    let b = Version::new(b);
16    a.vercmp(b)
17}
18
19#[repr(transparent)]
20#[derive(Debug, Eq)]
21pub struct Ver(CStr);
22
23impl Ver {
24    pub fn new(s: &CStr) -> &Ver {
25        unsafe { &*(s as *const CStr as *const Ver) }
26    }
27
28    pub fn as_str(&self) -> &str {
29        self
30    }
31
32    pub fn vercmp<V: AsRef<Ver>>(&self, other: V) -> Ordering {
33        unsafe { LIBRARY.force_load().alpm_pkg_vercmp(self.0.as_ptr(), other.as_ref().0.as_ptr()).cmp(&0) }
34    }
35
36    pub(crate) unsafe fn from_ptr<'a>(s: *const c_char) -> &'a Ver {
37        Ver::new(CStr::from_ptr(s))
38    }
39}
40
41impl<'a> From<&'a CStr> for &'a Ver {
42    fn from(s: &'a CStr) -> Self {
43        Ver::new(s)
44    }
45}
46
47impl AsRef<Ver> for Ver {
48    fn as_ref(&self) -> &Ver {
49        self
50    }
51}
52
53impl Deref for Ver {
54    type Target = str;
55    fn deref(&self) -> &Self::Target {
56        self.0.to_str().unwrap()
57    }
58}
59
60impl fmt::Display for Ver {
61    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
62        fmt.write_str(self)
63    }
64}
65
66impl PartialOrd for Ver {
67    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
68        unsafe { LIBRARY.force_load().alpm_pkg_vercmp(self.0.as_ptr(), other.0.as_ptr()).partial_cmp(&0) }
69    }
70}
71
72impl PartialOrd<Version> for &Ver {
73    fn partial_cmp(&self, other: &Version) -> Option<Ordering> {
74        self.partial_cmp(&other.as_ver())
75    }
76}
77
78impl AsRef<str> for Ver {
79    fn as_ref(&self) -> &str {
80        self
81    }
82}
83
84impl PartialEq for Ver {
85    fn eq(&self, other: &Self) -> bool {
86        unsafe { LIBRARY.force_load().alpm_pkg_vercmp(self.0.as_ptr(), other.0.as_ptr()) == 0 }
87    }
88}
89
90impl PartialEq<Version> for &Ver {
91    fn eq(&self, other: &Version) -> bool {
92        unsafe { LIBRARY.force_load().alpm_pkg_vercmp(self.0.as_ptr(), other.0.as_ptr()) == 0 }
93    }
94}
95
96#[derive(Debug, Eq, Clone)]
97pub struct Version(CString);
98
99impl Version {
100    pub fn new<S: Into<Vec<u8>>>(s: S) -> Self {
101        let s = CString::new(s).unwrap();
102        Version(s)
103    }
104
105    pub fn as_ver(&self) -> &Ver {
106        self
107    }
108}
109
110impl fmt::Display for Version {
111    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
112        fmt.write_str(self.as_ver())
113    }
114}
115
116impl Deref for Version {
117    type Target = Ver;
118    fn deref(&self) -> &Self::Target {
119        Ver::new(&self.0)
120    }
121}
122
123impl PartialOrd for Version {
124    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
125        unsafe { LIBRARY.force_load().alpm_pkg_vercmp(self.0.as_ptr(), other.0.as_ptr()).partial_cmp(&0) }
126    }
127}
128
129impl PartialOrd<&Ver> for Version {
130    fn partial_cmp(&self, other: &&Ver) -> Option<Ordering> {
131        unsafe { LIBRARY.force_load().alpm_pkg_vercmp(self.0.as_ptr(), other.0.as_ptr()).partial_cmp(&0) }
132    }
133}
134
135impl AsRef<Ver> for Version {
136    fn as_ref(&self) -> &Ver {
137        self.as_ver()
138    }
139}
140
141impl PartialEq for Version {
142    fn eq(&self, other: &Self) -> bool {
143        unsafe { LIBRARY.force_load().alpm_pkg_vercmp(self.0.as_ptr(), other.0.as_ptr()) == 0 }
144    }
145}
146
147impl PartialEq<&Ver> for Version {
148    fn eq(&self, other: &&Ver) -> bool {
149        unsafe { LIBRARY.force_load().alpm_pkg_vercmp(self.0.as_ptr(), other.0.as_ptr()) == 0 }
150    }
151}
152
153impl PartialEq<str> for Ver {
154    fn eq(&self, other: &str) -> bool {
155        self.as_str().eq(other)
156    }
157}
158
159impl PartialEq<String> for Ver {
160    fn eq(&self, other: &String) -> bool {
161        self.as_str().eq(other)
162    }
163}
164
165impl PartialEq<&str> for Version {
166    fn eq(&self, other: &&str) -> bool {
167        self.as_str() == *other
168    }
169}
170
171impl PartialEq<String> for Version {
172    fn eq(&self, other: &String) -> bool {
173        self.as_str().eq(other)
174    }
175}
176
177impl PartialEq<Ver> for str {
178    fn eq(&self, other: &Ver) -> bool {
179        self == other.as_str()
180    }
181}
182
183impl PartialEq<&Ver> for String {
184    fn eq(&self, other: &&Ver) -> bool {
185        self == other.as_str()
186    }
187}
188
189impl PartialEq<Version> for &str {
190    fn eq(&self, other: &Version) -> bool {
191        *self == other.as_str()
192    }
193}
194
195impl PartialEq<Version> for String {
196    fn eq(&self, other: &Version) -> bool {
197        self == other.as_str()
198    }
199}
200
201#[cfg(test)]
202mod tests {
203    use super::*;
204
205    use crate::Depend;
206
207    #[test]
208    fn test_version() {
209        assert!(Version::new("0") <= Version::new("1"));
210        assert!(Version::new("2") <= Version::new("2"));
211        assert!(Version::new("2") > Version::new("1"));
212        assert!(Version::new("2") < Version::new("3"));
213        assert!(Version::new("2") >= Version::new("1"));
214        assert!(Version::new("2") >= Version::new("2"));
215        assert!(Version::new("2") == Version::new("2"));
216
217        assert!(Version::new("2") == "2");
218        assert!("2" == Version::new("2"));
219
220        let dep1 = Depend::new("foo=20");
221        let dep2 = Depend::new("foo=34");
222
223        assert!(Version::new("1").vercmp(&Version::new("2")) == Ordering::Less);
224        assert!(Version::new("2-1").vercmp(&Version::new("2")) == Ordering::Equal);
225
226        assert!(dep1.version() != dep2.version());
227        assert!(dep1.version() < dep2.version());
228        assert!(Version::new("34") == dep2.version().unwrap());
229        assert!(Version::new("34") >= dep2.version().unwrap());
230        assert!(dep2.version().unwrap() == Version::new("34"));
231        assert!(dep2.version().unwrap() >= Version::new("34"));
232        assert!(Version::new("1.9.3-2") < Version::new("1.10.2-1"));
233    }
234}