1use std::cmp::Ordering;
10use std::cmp::max;
11use std::fmt;
12use std::result;
13use crate::serde::de;
14use crate::serde::de::Visitor;
15use crate::serde::Deserialize;
16use crate::serde::Deserializer;
17use crate::serde::Serialize;
18use crate::serde::Serializer;
19use crate::error::*;
20
21#[derive(Clone, Debug)]
23pub enum PreReleaseIdent
24{
25 Numeric(u32),
27 Alphanumeric(String),
29}
30
31impl Eq for PreReleaseIdent
32{}
33
34impl PartialEq for PreReleaseIdent
35{
36 fn eq(&self, other: &Self) -> bool
37 { self.cmp(other) == Ordering::Equal }
38}
39
40impl Ord for PreReleaseIdent
41{
42 fn cmp(&self, other: &Self) -> Ordering
43 {
44 match (self, other) {
45 (PreReleaseIdent::Numeric(n), PreReleaseIdent::Numeric(m)) => n.cmp(&m),
46 (PreReleaseIdent::Alphanumeric(_), PreReleaseIdent::Numeric(_)) => Ordering::Greater,
47 (PreReleaseIdent::Numeric(_), PreReleaseIdent::Alphanumeric(_)) => Ordering::Less,
48 (PreReleaseIdent::Alphanumeric(s), PreReleaseIdent::Alphanumeric(t)) => s.cmp(&t),
49 }
50 }
51}
52
53impl PartialOrd for PreReleaseIdent
54{
55 fn partial_cmp(&self, other: &Self) -> Option<Ordering>
56 { Some(self.cmp(other)) }
57}
58
59impl fmt::Display for PreReleaseIdent
60{
61 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
62 {
63 match self {
64 PreReleaseIdent::Numeric(n) => write!(f, "{}", n),
65 PreReleaseIdent::Alphanumeric(s) => write!(f, "{}", s),
66 }
67 }
68}
69
70#[derive(Clone, Debug)]
75pub struct Version
76{
77 version: String,
78 numeric_idents: Vec<u32>,
79 pre_release_idents: Option<Vec<PreReleaseIdent>>,
80 build_idents: Option<Vec<String>>,
81}
82
83impl Version
84{
85 pub fn new(version: String, numeric_idents: Vec<u32>, pre_release_idents: Option<Vec<PreReleaseIdent>>, build_idents: Option<Vec<String>>) -> Self
87 { Version { version, numeric_idents, pre_release_idents, build_idents, } }
88
89 pub fn parse(s: &str) -> Result<Self>
91 {
92 let (pair_s, build) = match s.split_once('+') {
93 Some(pair) => pair,
94 None => (s, ""),
95 };
96 let (version_core, pre_release) = match pair_s.split_once('-') {
97 Some(pair) => pair,
98 None => (pair_s, ""),
99 };
100 let mut numeric_idents: Vec<u32> = Vec::new();
101 for t in version_core.split('.') {
102 match t.parse::<u32>() {
103 Ok(n) => numeric_idents.push(n),
104 Err(_) => return Err(Error::InvalidVersion),
105 }
106 }
107 let pre_release_idents = if !pre_release.is_empty() {
108 let mut tmp_pre_release_idents: Vec<PreReleaseIdent> = Vec::new();
109 for t in pre_release.split('.') {
110 match t.parse::<u32>() {
111 Ok(n) => tmp_pre_release_idents.push(PreReleaseIdent::Numeric(n)),
112 Err(_) => {
113 if t.is_empty() || t.contains('/') || t.contains('\\') {
114 return Err(Error::InvalidVersion);
115 }
116 tmp_pre_release_idents.push(PreReleaseIdent::Alphanumeric(String::from(t)))
117 },
118 }
119 }
120 Some(tmp_pre_release_idents)
121 } else {
122 None
123 };
124 let build_idents = if !build.is_empty() {
125 let mut tmp_build_idents: Vec<String> = Vec::new();
126 for t in build.split('.') {
127 if t.is_empty() || t.contains('/') || t.contains('\\') {
128 return Err(Error::InvalidVersion);
129 }
130 tmp_build_idents.push(String::from(t));
131 }
132 Some(tmp_build_idents)
133 } else {
134 None
135 };
136 Ok(Self::new(String::from(s), numeric_idents, pre_release_idents, build_idents))
137 }
138
139 pub fn version(&self) -> &str
141 { self.version.as_str() }
142
143 pub fn numeric_idents(&self) -> &[u32]
145 { self.numeric_idents.as_slice() }
146
147 pub fn pre_release_idents(&self) -> Option<&[PreReleaseIdent]>
149 {
150 match &self.pre_release_idents {
151 Some(pre_release_idents) => Some(pre_release_idents.as_slice()),
152 None => None,
153 }
154 }
155
156 pub fn build_idents(&self) -> Option<&[String]>
158 {
159 match &self.build_idents {
160 Some(build_idents) => Some(build_idents.as_slice()),
161 None => None,
162 }
163 }
164
165 pub fn eq_numeric_idents(&self, version: &Version, count: usize) -> bool
168 {
169 for i in 0..count {
170 let n = if i < self.numeric_idents.len() {
171 self.numeric_idents[i]
172 } else {
173 0
174 };
175 let m = if i < version.numeric_idents.len() {
176 version.numeric_idents[i]
177 } else {
178 0
179 };
180 if n != m {
181 return false;
182 }
183 }
184 true
185 }
186}
187
188impl Eq for Version
189{}
190
191impl PartialEq for Version
192{
193 fn eq(&self, other: &Self) -> bool
194 { self.cmp(other) == Ordering::Equal }
195}
196
197impl Ord for Version
198{
199 fn cmp(&self, other: &Self) -> Ordering
200 {
201 let len = max(self.numeric_idents.len(), other.numeric_idents.len());
202 for i in 0..len {
203 let n = if i < self.numeric_idents.len() {
204 self.numeric_idents[i]
205 } else {
206 0
207 };
208 let m = if i < other.numeric_idents.len() {
209 other.numeric_idents[i]
210 } else {
211 0
212 };
213 match n.cmp(&m) {
214 Ordering::Equal => (),
215 ordering => return ordering,
216 }
217 }
218 match (&self.pre_release_idents, &other.pre_release_idents) {
219 (Some(pre_release_idents), Some(pre_release_idents2)) => pre_release_idents.cmp(&pre_release_idents2),
220 (Some(_), None) => Ordering::Less,
221 (None, Some(_)) => Ordering::Greater,
222 (None, None) => Ordering::Equal,
223 }
224 }
225}
226
227impl PartialOrd for Version
228{
229 fn partial_cmp(&self, other: &Self) -> Option<Ordering>
230 { Some(self.cmp(other)) }
231}
232
233impl fmt::Display for Version
234{
235 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
236 { write!(f, "{}", self.version) }
237}
238
239impl Serialize for Version
240{
241 fn serialize<S>(&self, serializer: S) -> result::Result<S::Ok, S::Error>
242 where S: Serializer
243 { serializer.serialize_str(format!("{}", self).as_str()) }
244}
245
246struct VersionVisitor;
247
248impl<'de> Visitor<'de> for VersionVisitor
249{
250 type Value = Version;
251
252 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result
253 { write!(formatter, "a version") }
254
255 fn visit_str<E>(self, v: &str) -> result::Result<Self::Value, E>
256 where E: de::Error
257 {
258 match Version::parse(v) {
259 Ok(version) => Ok(version),
260 Err(err) => Err(E::custom(format!("{}", err))),
261 }
262 }
263}
264
265impl<'de> Deserialize<'de> for Version
266{
267 fn deserialize<D>(deserializer: D) -> result::Result<Self, D::Error>
268 where D: Deserializer<'de>
269 { deserializer.deserialize_str(VersionVisitor) }
270}
271
272#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
274pub enum VersionOp
275{
276 Eq,
278 Ne,
280 Lt,
282 Ge,
284 Gt,
286 Le,
288 Default,
290 Tilde,
292}
293
294impl fmt::Display for VersionOp
295{
296 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
297 {
298 match self {
299 VersionOp::Eq => write!(f, "="),
300 VersionOp::Ne => write!(f, "!="),
301 VersionOp::Lt => write!(f, "<"),
302 VersionOp::Ge => write!(f, ">="),
303 VersionOp::Gt => write!(f, ">"),
304 VersionOp::Le => write!(f, "<="),
305 VersionOp::Default => write!(f, "^"),
306 VersionOp::Tilde => write!(f, "~"),
307 }
308 }
309}
310
311#[derive(Clone, Debug)]
317pub enum SingleVersionReq
318{
319 Wildcard,
321 Pair(VersionOp, Version),
323}
324
325impl SingleVersionReq
326{
327 pub fn parse(s: &str) -> Result<Self>
329 {
330 let trimmed_s = s.trim();
331 if trimmed_s != "*" {
332 let (op, t) = if trimmed_s.starts_with("=") {
333 (VersionOp::Eq, &trimmed_s[1..])
334 } else if trimmed_s.starts_with("!=") {
335 (VersionOp::Ne, &trimmed_s[2..])
336 } else if trimmed_s.starts_with("<=") {
337 (VersionOp::Le, &trimmed_s[2..])
338 } else if trimmed_s.starts_with("<") {
339 (VersionOp::Lt, &trimmed_s[1..])
340 } else if trimmed_s.starts_with(">=") {
341 (VersionOp::Ge, &trimmed_s[2..])
342 } else if trimmed_s.starts_with(">") {
343 (VersionOp::Gt, &trimmed_s[1..])
344 } else if trimmed_s.starts_with("^") {
345 (VersionOp::Default, &trimmed_s[1..])
346 } else if trimmed_s.starts_with("~") {
347 (VersionOp::Tilde, &trimmed_s[1..])
348 } else {
349 (VersionOp::Default, trimmed_s)
350 };
351 let trimmed_t = t.trim();
352 let version = Version::parse(trimmed_t)?;
353 Ok(SingleVersionReq::Pair(op, version))
354 } else {
355 Ok(SingleVersionReq::Wildcard)
356 }
357 }
358
359 pub fn matches(&self, version: &Version) -> bool
364 {
365 match self {
366 SingleVersionReq::Wildcard => true,
367 SingleVersionReq::Pair(op, version2) => {
368 match op {
369 VersionOp::Eq => version == version2,
370 VersionOp::Ne => version != version2,
371 VersionOp::Lt => version < version2,
372 VersionOp::Ge => version >= version2,
373 VersionOp::Gt => version > version2,
374 VersionOp::Le => version <= version2,
375 VersionOp::Default => {
376 let mut count = 0usize;
377 if !version2.numeric_idents.is_empty() {
378 count += 1;
379 for i in 0..version2.numeric_idents.len() {
380 match version2.numeric_idents.get(i) {
381 Some(0) if version2.numeric_idents.len() >= i + 2 => count += 1,
382 _ => break,
383 }
384 }
385 }
386 version >= version2 && version.eq_numeric_idents(version2, count)
387 },
388 VersionOp::Tilde => {
389 let count = if !version2.numeric_idents.is_empty() {
390 if version2.numeric_idents.len() >= 2 {
391 2
392 } else {
393 1
394 }
395 } else {
396 0
397 };
398 version >= version2 && version.eq_numeric_idents(version2, count)
399 },
400 }
401 },
402 }
403 }
404}
405
406impl fmt::Display for SingleVersionReq
407{
408 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
409 {
410 match self {
411 SingleVersionReq::Wildcard => write!(f, "*"),
412 SingleVersionReq::Pair(op, version) => write!(f, "{}{}", op, version),
413 }
414 }
415}
416
417#[derive(Clone, Debug)]
423pub struct VersionReq
424{
425 single_reqs: Vec<SingleVersionReq>,
426}
427
428impl VersionReq
429{
430 pub fn new(single_reqs: Vec<SingleVersionReq>) -> Self
432 { VersionReq { single_reqs, } }
433
434 pub fn parse(s: &str) -> Result<Self>
436 {
437 let mut single_reqs: Vec<SingleVersionReq> = Vec::new();
438 for t in s.split(',') {
439 single_reqs.push(SingleVersionReq::parse(t)?);
440 }
441 Ok(VersionReq::new(single_reqs))
442 }
443
444 pub fn single_reqs(&self) -> &[SingleVersionReq]
446 { self.single_reqs.as_slice() }
447
448 pub fn matches(&self, version: &Version) -> bool
453 { self.single_reqs.iter().all(|sr| sr.matches(version)) }
454}
455
456impl fmt::Display for VersionReq
457{
458 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
459 {
460 let mut is_first = true;
461 for single_req in &self.single_reqs {
462 if !is_first {
463 write!(f, ",")?;
464 }
465 write!(f, "{}", single_req)?;
466 is_first = false;
467 }
468 Ok(())
469 }
470}
471
472impl Serialize for VersionReq
473{
474 fn serialize<S>(&self, serializer: S) -> result::Result<S::Ok, S::Error>
475 where S: Serializer
476 { serializer.serialize_str(format!("{}", self).as_str()) }
477}
478
479struct VersionReqVisitor;
480
481impl<'de> Visitor<'de> for VersionReqVisitor
482{
483 type Value = VersionReq;
484
485 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result
486 { write!(formatter, "a version requirement") }
487
488 fn visit_str<E>(self, v: &str) -> result::Result<Self::Value, E>
489 where E: de::Error
490 {
491 match VersionReq::parse(v) {
492 Ok(req) => Ok(req),
493 Err(err) => Err(E::custom(format!("{}", err))),
494 }
495 }
496}
497
498impl<'de> Deserialize<'de> for VersionReq
499{
500 fn deserialize<D>(deserializer: D) -> result::Result<Self, D::Error>
501 where D: Deserializer<'de>
502 { deserializer.deserialize_str(VersionReqVisitor) }
503}
504
505#[cfg(test)]
506mod tests;