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