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}