1 use common::{self, numeric_identifier, letters_numbers_dash_dot};
2 use version::Identifier;
3 use std::str::{FromStr, from_utf8};
4 use recognize::*;
5 
6 #[derive(Debug)]
7 pub struct VersionReq {
8     pub predicates: Vec<Predicate>,
9 }
10 
11 #[derive(PartialEq,Debug)]
12 pub enum WildcardVersion {
13     Major,
14     Minor,
15     Patch,
16 }
17 
18 #[derive(PartialEq,Debug)]
19 pub enum Op {
20     Ex, // Exact
21     Gt, // Greater than
22     GtEq, // Greater than or equal to
23     Lt, // Less than
24     LtEq, // Less than or equal to
25     Tilde, // e.g. ~1.0.0
26     Compatible, // compatible by definition of semver, indicated by ^
27     Wildcard(WildcardVersion), // x.y.*, x.*, *
28 }
29 
30 impl FromStr for Op {
31     type Err = String;
32 
from_str(s: &str) -> Result<Op, String>33     fn from_str(s: &str) -> Result<Op, String> {
34         match s {
35             "=" => Ok(Op::Ex),
36             ">" => Ok(Op::Gt),
37             ">=" => Ok(Op::GtEq),
38             "<" => Ok(Op::Lt),
39             "<=" => Ok(Op::LtEq),
40             "~" => Ok(Op::Tilde),
41             "^" => Ok(Op::Compatible),
42             _ => Err(String::from("Could not parse Op")),
43         }
44     }
45 }
46 
47 #[derive(PartialEq,Debug)]
48 pub struct Predicate {
49     pub op: Op,
50     pub major: u64,
51     pub minor: Option<u64>,
52     pub patch: Option<u64>,
53     pub pre: Vec<Identifier>,
54 }
55 
numeric_or_wild(s: &[u8]) -> Option<(Option<u64>, usize)>56 fn numeric_or_wild(s: &[u8]) -> Option<(Option<u64>, usize)> {
57     if let Some((val, len)) = numeric_identifier(s) {
58         Some((Some(val), len))
59     } else if let Some(len) = OneOf(b"*xX").p(s) {
60         Some((None, len))
61     } else {
62         None
63     }
64 }
65 
dot_numeric_or_wild(s: &[u8]) -> Option<(Option<u64>, usize)>66 fn dot_numeric_or_wild(s: &[u8]) -> Option<(Option<u64>, usize)> {
67     b'.'.p(s).and_then(|len|
68         numeric_or_wild(&s[len..]).map(|(val, len2)| (val, len + len2))
69     )
70 }
71 
operation(s: &[u8]) -> Option<(Op, usize)>72 fn operation(s: &[u8]) -> Option<(Op, usize)> {
73     if let Some(len) = "=".p(s) {
74         Some((Op::Ex, len))
75     } else if let Some(len) = ">=".p(s) {
76         Some((Op::GtEq, len))
77     } else if let Some(len) = ">".p(s) {
78         Some((Op::Gt, len))
79     } else if let Some(len) = "<=".p(s) {
80         Some((Op::LtEq, len))
81     } else if let Some(len) = "<".p(s) {
82         Some((Op::Lt, len))
83     } else if let Some(len) = "~".p(s) {
84         Some((Op::Tilde, len))
85     } else if let Some(len) = "^".p(s) {
86         Some((Op::Compatible, len))
87     } else {
88         None
89     }
90 }
91 
whitespace(s: &[u8]) -> Option<usize>92 fn whitespace(s: &[u8]) -> Option<usize> {
93     ZeroOrMore(OneOf(b"\t\r\n ")).p(s)
94 }
95 
parse_predicate(range: &str) -> Result<Predicate, String>96 pub fn parse_predicate(range: &str) -> Result<Predicate, String> {
97     let s = range.trim().as_bytes();
98     let mut i = 0;
99     let mut operation = if let Some((op, len)) = operation(&s[i..]) {
100         i += len;
101         op
102     } else {
103         // operations default to Compatible
104         Op::Compatible
105     };
106     if let Some(len) = whitespace.p(&s[i..]) {
107         i += len;
108     }
109     let major = if let Some((major, len)) = numeric_identifier(&s[i..]) {
110         i += len;
111         major
112     } else {
113         return Err("Error parsing major version number: ".to_string());
114     };
115     let minor = if let Some((minor, len)) = dot_numeric_or_wild(&s[i..]) {
116         i += len;
117         if minor.is_none() {
118             operation = Op::Wildcard(WildcardVersion::Minor);
119         }
120         minor
121     } else {
122         None
123     };
124     let patch = if let Some((patch, len)) = dot_numeric_or_wild(&s[i..]) {
125         i += len;
126         if patch.is_none() {
127             operation = Op::Wildcard(WildcardVersion::Patch);
128         }
129         patch
130     } else {
131         None
132     };
133     let (pre, pre_len) = common::parse_optional_meta(&s[i..], b'-')?;
134     i += pre_len;
135     if let Some(len) = (b'+', letters_numbers_dash_dot).p(&s[i..]) {
136         i += len;
137     }
138     if i != s.len() {
139         return Err("Extra junk after valid predicate: ".to_string() +
140             from_utf8(&s[i..]).unwrap());
141     }
142     Ok(Predicate {
143         op: operation,
144         major: major,
145         minor: minor,
146         patch: patch,
147         pre: pre,
148     })
149 }
150 
parse(ranges: &str) -> Result<VersionReq, String>151 pub fn parse(ranges: &str) -> Result<VersionReq, String> {
152     // null is an error
153     if ranges == "\0" {
154         return Err(String::from("Null is not a valid VersionReq"));
155     }
156 
157     // an empty range is a major version wildcard
158     // so is a lone * or x of either capitalization
159     if (ranges == "")
160     || (ranges == "*")
161     || (ranges == "x")
162     || (ranges == "X") {
163         return Ok(VersionReq {
164             predicates: vec![Predicate {
165                 op: Op::Wildcard(WildcardVersion::Major),
166                 major: 0,
167                 minor: None,
168                 patch: None,
169                 pre: Vec::new(),
170             }],
171         });
172     }
173 
174 
175     let ranges = ranges.trim();
176 
177     let predicates: Result<Vec<_>, String> = ranges
178         .split(",")
179         .map(|range| {
180             parse_predicate(range)
181         })
182         .collect();
183 
184     let predicates = try!(predicates);
185 
186     if predicates.len() == 0 {
187         return Err(String::from("VersionReq did not parse properly"));
188     }
189 
190     Ok(VersionReq {
191         predicates: predicates,
192     })
193 }
194 
195 #[cfg(test)]
196 mod tests {
197     use super::*;
198     use range;
199     use version::Identifier;
200 
201     #[test]
test_parsing_default()202     fn test_parsing_default() {
203         let r = range::parse("1.0.0").unwrap();
204 
205         assert_eq!(Predicate {
206                 op: Op::Compatible,
207                 major: 1,
208                 minor: Some(0),
209                 patch: Some(0),
210                 pre: Vec::new(),
211             },
212             r.predicates[0]
213         );
214     }
215 
216     #[test]
test_parsing_exact_01()217     fn test_parsing_exact_01() {
218         let r = range::parse("=1.0.0").unwrap();
219 
220         assert_eq!(Predicate {
221                 op: Op::Ex,
222                 major: 1,
223                 minor: Some(0),
224                 patch: Some(0),
225                 pre: Vec::new(),
226             },
227             r.predicates[0]
228         );
229     }
230 
231     #[test]
test_parsing_exact_02()232     fn test_parsing_exact_02() {
233         let r = range::parse("=0.9.0").unwrap();
234 
235         assert_eq!(Predicate {
236                 op: Op::Ex,
237                 major: 0,
238                 minor: Some(9),
239                 patch: Some(0),
240                 pre: Vec::new(),
241             },
242             r.predicates[0]
243         );
244     }
245 
246     #[test]
test_parsing_exact_03()247     fn test_parsing_exact_03() {
248         let r = range::parse("=0.1.0-beta2.a").unwrap();
249 
250         assert_eq!(Predicate {
251                 op: Op::Ex,
252                 major: 0,
253                 minor: Some(1),
254                 patch: Some(0),
255                 pre: vec![Identifier::AlphaNumeric(String::from("beta2")),
256                           Identifier::AlphaNumeric(String::from("a"))],
257             },
258             r.predicates[0]
259         );
260     }
261 
262     #[test]
test_parsing_greater_than()263     pub fn test_parsing_greater_than() {
264         let r = range::parse("> 1.0.0").unwrap();
265 
266         assert_eq!(Predicate {
267                 op: Op::Gt,
268                 major: 1,
269                 minor: Some(0),
270                 patch: Some(0),
271                 pre: Vec::new(),
272             },
273             r.predicates[0]
274         );
275     }
276 
277     #[test]
test_parsing_greater_than_01()278     pub fn test_parsing_greater_than_01() {
279         let r = range::parse(">= 1.0.0").unwrap();
280 
281         assert_eq!(Predicate {
282                 op: Op::GtEq,
283                 major: 1,
284                 minor: Some(0),
285                 patch: Some(0),
286                 pre: Vec::new(),
287             },
288             r.predicates[0]
289         );
290     }
291 
292     #[test]
test_parsing_greater_than_02()293     pub fn test_parsing_greater_than_02() {
294         let r = range::parse(">= 2.1.0-alpha2").unwrap();
295 
296         assert_eq!(Predicate {
297                 op: Op::GtEq,
298                 major: 2,
299                 minor: Some(1),
300                 patch: Some(0),
301                 pre: vec![Identifier::AlphaNumeric(String::from("alpha2"))],
302             },
303             r.predicates[0]
304         );
305     }
306 
307     #[test]
test_parsing_less_than()308     pub fn test_parsing_less_than() {
309         let r = range::parse("< 1.0.0").unwrap();
310 
311         assert_eq!(Predicate {
312                 op: Op::Lt,
313                 major: 1,
314                 minor: Some(0),
315                 patch: Some(0),
316                 pre: Vec::new(),
317             },
318             r.predicates[0]
319         );
320     }
321 
322     #[test]
test_parsing_less_than_eq()323     pub fn test_parsing_less_than_eq() {
324         let r = range::parse("<= 2.1.0-alpha2").unwrap();
325 
326         assert_eq!(Predicate {
327                 op: Op::LtEq,
328                 major: 2,
329                 minor: Some(1),
330                 patch: Some(0),
331                 pre: vec![Identifier::AlphaNumeric(String::from("alpha2"))],
332             },
333             r.predicates[0]
334         );
335     }
336 
337     #[test]
test_parsing_tilde()338     pub fn test_parsing_tilde() {
339         let r = range::parse("~1").unwrap();
340 
341         assert_eq!(Predicate {
342                 op: Op::Tilde,
343                 major: 1,
344                 minor: None,
345                 patch: None,
346                 pre: Vec::new(),
347             },
348             r.predicates[0]
349         );
350     }
351 
352     #[test]
test_parsing_compatible()353     pub fn test_parsing_compatible() {
354         let r = range::parse("^0").unwrap();
355 
356         assert_eq!(Predicate {
357                 op: Op::Compatible,
358                 major: 0,
359                 minor: None,
360                 patch: None,
361                 pre: Vec::new(),
362             },
363             r.predicates[0]
364         );
365     }
366 
367     #[test]
test_parsing_blank()368     fn test_parsing_blank() {
369         let r = range::parse("").unwrap();
370 
371         assert_eq!(Predicate {
372                 op: Op::Wildcard(WildcardVersion::Major),
373                 major: 0,
374                 minor: None,
375                 patch: None,
376                 pre: Vec::new(),
377             },
378             r.predicates[0]
379         );
380     }
381 
382     #[test]
test_parsing_wildcard()383     fn test_parsing_wildcard() {
384         let r = range::parse("*").unwrap();
385 
386         assert_eq!(Predicate {
387                 op: Op::Wildcard(WildcardVersion::Major),
388                 major: 0,
389                 minor: None,
390                 patch: None,
391                 pre: Vec::new(),
392             },
393             r.predicates[0]
394         );
395     }
396 
397     #[test]
test_parsing_x()398     fn test_parsing_x() {
399         let r = range::parse("x").unwrap();
400 
401         assert_eq!(Predicate {
402                 op: Op::Wildcard(WildcardVersion::Major),
403                 major: 0,
404                 minor: None,
405                 patch: None,
406                 pre: Vec::new(),
407             },
408             r.predicates[0]
409         );
410     }
411 
412     #[test]
test_parsing_capital_x()413     fn test_parsing_capital_x() {
414         let r = range::parse("X").unwrap();
415 
416         assert_eq!(Predicate {
417                 op: Op::Wildcard(WildcardVersion::Major),
418                 major: 0,
419                 minor: None,
420                 patch: None,
421                 pre: Vec::new(),
422             },
423             r.predicates[0]
424         );
425     }
426 
427     #[test]
test_parsing_minor_wildcard_star()428     fn test_parsing_minor_wildcard_star() {
429         let r = range::parse("1.*").unwrap();
430 
431         assert_eq!(Predicate {
432                 op: Op::Wildcard(WildcardVersion::Minor),
433                 major: 1,
434                 minor: None,
435                 patch: None,
436                 pre: Vec::new(),
437             },
438             r.predicates[0]
439         );
440     }
441 
442     #[test]
test_parsing_minor_wildcard_x()443     fn test_parsing_minor_wildcard_x() {
444         let r = range::parse("1.x").unwrap();
445 
446         assert_eq!(Predicate {
447                 op: Op::Wildcard(WildcardVersion::Minor),
448                 major: 1,
449                 minor: None,
450                 patch: None,
451                 pre: Vec::new(),
452             },
453             r.predicates[0]
454         );
455     }
456 
457     #[test]
test_parsing_minor_wildcard_capital_x()458     fn test_parsing_minor_wildcard_capital_x() {
459         let r = range::parse("1.X").unwrap();
460 
461         assert_eq!(Predicate {
462                 op: Op::Wildcard(WildcardVersion::Minor),
463                 major: 1,
464                 minor: None,
465                 patch: None,
466                 pre: Vec::new(),
467             },
468             r.predicates[0]
469         );
470     }
471 
472     #[test]
test_parsing_patch_wildcard_star()473     fn test_parsing_patch_wildcard_star() {
474         let r = range::parse("1.2.*").unwrap();
475 
476         assert_eq!(Predicate {
477                 op: Op::Wildcard(WildcardVersion::Patch),
478                 major: 1,
479                 minor: Some(2),
480                 patch: None,
481                 pre: Vec::new(),
482             },
483             r.predicates[0]
484         );
485     }
486 
487     #[test]
test_parsing_patch_wildcard_x()488     fn test_parsing_patch_wildcard_x() {
489         let r = range::parse("1.2.x").unwrap();
490 
491         assert_eq!(Predicate {
492                 op: Op::Wildcard(WildcardVersion::Patch),
493                 major: 1,
494                 minor: Some(2),
495                 patch: None,
496                 pre: Vec::new(),
497             },
498             r.predicates[0]
499         );
500     }
501 
502     #[test]
test_parsing_patch_wildcard_capital_x()503     fn test_parsing_patch_wildcard_capital_x() {
504         let r = range::parse("1.2.X").unwrap();
505 
506         assert_eq!(Predicate {
507                 op: Op::Wildcard(WildcardVersion::Patch),
508                 major: 1,
509                 minor: Some(2),
510                 patch: None,
511                 pre: Vec::new(),
512             },
513             r.predicates[0]
514         );
515     }
516 
517     #[test]
test_multiple_01()518     pub fn test_multiple_01() {
519         let r = range::parse("> 0.0.9, <= 2.5.3").unwrap();
520 
521         assert_eq!(Predicate {
522                 op: Op::Gt,
523                 major: 0,
524                 minor: Some(0),
525                 patch: Some(9),
526                 pre: Vec::new(),
527             },
528             r.predicates[0]
529         );
530 
531         assert_eq!(Predicate {
532                 op: Op::LtEq,
533                 major: 2,
534                 minor: Some(5),
535                 patch: Some(3),
536                 pre: Vec::new(),
537             },
538             r.predicates[1]
539         );
540     }
541 
542     #[test]
test_multiple_02()543     pub fn test_multiple_02() {
544         let r = range::parse("0.3.0, 0.4.0").unwrap();
545 
546         assert_eq!(Predicate {
547                 op: Op::Compatible,
548                 major: 0,
549                 minor: Some(3),
550                 patch: Some(0),
551                 pre: Vec::new(),
552             },
553             r.predicates[0]
554         );
555 
556         assert_eq!(Predicate {
557                 op: Op::Compatible,
558                 major: 0,
559                 minor: Some(4),
560                 patch: Some(0),
561                 pre: Vec::new(),
562             },
563             r.predicates[1]
564         );
565     }
566 
567     #[test]
test_multiple_03()568     pub fn test_multiple_03() {
569         let r = range::parse("<= 0.2.0, >= 0.5.0").unwrap();
570 
571         assert_eq!(Predicate {
572                 op: Op::LtEq,
573                 major: 0,
574                 minor: Some(2),
575                 patch: Some(0),
576                 pre: Vec::new(),
577             },
578             r.predicates[0]
579         );
580 
581         assert_eq!(Predicate {
582                 op: Op::GtEq,
583                 major: 0,
584                 minor: Some(5),
585                 patch: Some(0),
586                 pre: Vec::new(),
587             },
588             r.predicates[1]
589         );
590     }
591 
592     #[test]
test_multiple_04()593     pub fn test_multiple_04() {
594         let r = range::parse("0.1.0, 0.1.4, 0.1.6").unwrap();
595 
596         assert_eq!(Predicate {
597                 op: Op::Compatible,
598                 major: 0,
599                 minor: Some(1),
600                 patch: Some(0),
601                 pre: Vec::new(),
602             },
603             r.predicates[0]
604         );
605 
606         assert_eq!(Predicate {
607                 op: Op::Compatible,
608                 major: 0,
609                 minor: Some(1),
610                 patch: Some(4),
611                 pre: Vec::new(),
612             },
613             r.predicates[1]
614         );
615 
616         assert_eq!(Predicate {
617                 op: Op::Compatible,
618                 major: 0,
619                 minor: Some(1),
620                 patch: Some(6),
621                 pre: Vec::new(),
622             },
623             r.predicates[2]
624         );
625     }
626 
627     #[test]
test_multiple_05()628     pub fn test_multiple_05() {
629         let r = range::parse(">=0.5.1-alpha3, <0.6").unwrap();
630 
631         assert_eq!(Predicate {
632                 op: Op::GtEq,
633                 major: 0,
634                 minor: Some(5),
635                 patch: Some(1),
636                 pre: vec![Identifier::AlphaNumeric(String::from("alpha3"))],
637             },
638             r.predicates[0]
639         );
640 
641         assert_eq!(Predicate {
642                 op: Op::Lt,
643                 major: 0,
644                 minor: Some(6),
645                 patch: None,
646                 pre: Vec::new(),
647             },
648             r.predicates[1]
649         );
650     }
651 
652     #[test]
test_parse_build_metadata_with_predicate()653     fn test_parse_build_metadata_with_predicate() {
654         assert_eq!(range::parse("^1.2.3+meta").unwrap().predicates[0].op,
655                    Op::Compatible);
656         assert_eq!(range::parse("~1.2.3+meta").unwrap().predicates[0].op,
657                    Op::Tilde);
658         assert_eq!(range::parse("=1.2.3+meta").unwrap().predicates[0].op,
659                    Op::Ex);
660         assert_eq!(range::parse("<=1.2.3+meta").unwrap().predicates[0].op,
661                    Op::LtEq);
662         assert_eq!(range::parse(">=1.2.3+meta").unwrap().predicates[0].op,
663                    Op::GtEq);
664         assert_eq!(range::parse("<1.2.3+meta").unwrap().predicates[0].op,
665                    Op::Lt);
666         assert_eq!(range::parse(">1.2.3+meta").unwrap().predicates[0].op,
667                    Op::Gt);
668     }
669 
670     #[test]
test_parse_errors()671     pub fn test_parse_errors() {
672         assert!(range::parse("\0").is_err());
673         assert!(range::parse(">= >= 0.0.2").is_err());
674         assert!(range::parse(">== 0.0.2").is_err());
675         assert!(range::parse("a.0.0").is_err());
676         assert!(range::parse("1.0.0-").is_err());
677         assert!(range::parse(">=").is_err());
678         assert!(range::parse("> 0.1.0,").is_err());
679         assert!(range::parse("> 0.3.0, ,").is_err());
680     }
681 
682     #[test]
test_large_major_version()683     pub fn test_large_major_version() {
684         assert!(range::parse("18446744073709551617.0.0").is_err());
685     }
686 
687     #[test]
test_large_minor_version()688     pub fn test_large_minor_version() {
689         assert!(range::parse("0.18446744073709551617.0").is_err());
690     }
691 
692     #[test]
test_large_patch_version()693     pub fn test_large_patch_version() {
694         assert!(range::parse("0.0.18446744073709551617").is_err());
695     }
696 }
697