semver_parser/
range_set.rs1use crate::*;
2use pest::Parser;
3
4use std::str::FromStr;
5
6#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
7pub struct RangeSet {
8 pub ranges: Vec<Range>,
9 pub compat: Compat,
10}
11
12#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
13pub enum Compat {
14 Cargo, Npm,
16}
17
18impl RangeSet {
19 fn new() -> RangeSet {
20 RangeSet {
21 ranges: Vec::new(),
22 compat: Compat::Cargo, }
24 }
25
26 pub fn parse(input: &str, compat: Compat) -> Result<Self, String> {
27 let range_set = match SemverParser::parse(Rule::range_set, input) {
28 Ok(mut parsed) => match parsed.next() {
29 Some(parsed) => parsed,
30 None => return Err(String::from("Could not parse a range set")),
31 },
32 Err(e) => return Err(e.to_string()),
33 };
34
35 from_pair_iterator(range_set, compat)
36 }
37}
38
39impl FromStr for RangeSet {
40 type Err = String;
41
42 fn from_str(input: &str) -> Result<Self, Self::Err> {
43 RangeSet::parse(input, Compat::Cargo)
45 }
46}
47
48fn from_pair_iterator(
50 parsed_range_set: pest::iterators::Pair<'_, Rule>,
51 compat: Compat,
52) -> Result<RangeSet, String> {
53 if parsed_range_set.as_rule() != Rule::range_set {
55 return Err(String::from("Error parsing range set"));
56 }
57
58 let mut range_set = RangeSet::new();
60 range_set.compat = compat;
61
62 for record in parsed_range_set.into_inner() {
64 match record.as_rule() {
65 Rule::range => {
67 range_set
69 .ranges
70 .push(range::from_pair_iterator(record, compat)?);
71 }
72
73 Rule::logical_or => (),
75
76 Rule::EOI => (),
78
79 _ => unreachable!(),
81 }
82 }
83
84 Ok(range_set)
86}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91
92 macro_rules! range_set_test {
93 ( $name:ident: $input:expr, $($x:tt)* ) => {
94 #[test]
95 fn $name() {
96 let expected_sets = vec![$($x)*];
97
98 let range_set: RangeSet = $input.parse().expect("parse failed");
99
100 assert_eq!(range_set.ranges.len(), expected_sets.len());
101 for it in range_set.ranges.iter().zip(expected_sets.iter()) {
102 let (ai, bi ) = it;
103 assert_eq!(ai.comparator_set.len(), *bi);
104 }
105 }
106 };
107 }
108
109 macro_rules! range_set_nodecompat {
110 ( $name:ident: $input:expr, $($x:tt)* ) => {
111 #[test]
112 fn $name() {
113 let expected_sets = vec![$($x)*];
114
115 let range_set = RangeSet::parse($input, Compat::Npm).expect("parse failed");
116
117 assert_eq!(range_set.ranges.len(), expected_sets.len());
118 for it in range_set.ranges.iter().zip(expected_sets.iter()) {
119 let (ai, bi ) = it;
120 assert_eq!(ai.comparator_set.len(), *bi);
121 }
122 }
123 };
124 }
125
126 macro_rules! should_error {
127 ( $( $name:ident: $value:expr, )* ) => {
128 $(
129 #[test]
130 fn $name() {
131 assert!($value.parse::<RangeSet>().is_err());
132 }
133 )*
134 };
135 }
136
137 range_set_test!( one_range: "=1.2.3", 1 );
138 range_set_test!( one_range_cargo: "1.2.3", 2 ); range_set_test!( one_range_with_space: " =1.2.3 ", 1 );
140 range_set_test!( two_ranges: ">1.2.3 || =4.5.6", 1, 1 );
141 range_set_test!( two_ranges_with_space: " >1.2.3 || =4.5.6 ", 1, 1 );
142 range_set_test!( two_ranges_with_two_comparators: ">1.2.3 <2.3.4 || >4.5.6 <5.6.7", 2, 2 );
143 range_set_test!( caret_range: "^1.2.3", 2 );
144 range_set_test!( two_empty_ranges: "||", 1, 1 );
145 range_set_test!( two_xranges: "1.2.* || 2.*", 2, 2 );
146 range_set_test!( see_issue_88: "=1.2.3+meta", 1 );
147
148 range_set_nodecompat!( node_one_range: "1.2.3", 1 ); should_error! {
151 err_only_gt: ">",
152 err_only_lt: "<",
153 err_only_lte: "<=",
154 err_only_gte: ">=",
155 err_only_eq: "=",
156 err_only_tilde: "~",
157 err_only_caret: "^",
158 err_leading_0_major: "01.2.3",
159 err_leading_0_minor: "1.02.3",
160 err_leading_0_patch: "1.2.03",
161 err_hyphen_with_gt: "1.2.3 - >3.4.5",
162 err_hyphen_no_2nd_version: "1.2.3 - ",
163 err_no_pre_hyphen: "~1.2.3beta",
164 }
165}