1 | use crate::{Comparator, Op, Version, VersionReq}; |
2 | |
3 | pub(crate) fn matches_req(req: &VersionReq, ver: &Version) -> bool { |
4 | for cmp: &Comparator in &req.comparators { |
5 | if !matches_impl(cmp, ver) { |
6 | return false; |
7 | } |
8 | } |
9 | |
10 | if ver.pre.is_empty() { |
11 | return true; |
12 | } |
13 | |
14 | // If a version has a prerelease tag (for example, 1.2.3-alpha.3) then it |
15 | // will only be allowed to satisfy req if at least one comparator with the |
16 | // same major.minor.patch also has a prerelease tag. |
17 | for cmp: &Comparator in &req.comparators { |
18 | if pre_is_compatible(cmp, ver) { |
19 | return true; |
20 | } |
21 | } |
22 | |
23 | false |
24 | } |
25 | |
26 | pub(crate) fn matches_comparator(cmp: &Comparator, ver: &Version) -> bool { |
27 | matches_impl(cmp, ver) && (ver.pre.is_empty() || pre_is_compatible(cmp, ver)) |
28 | } |
29 | |
30 | fn matches_impl(cmp: &Comparator, ver: &Version) -> bool { |
31 | match cmp.op { |
32 | Op::Exact | Op::Wildcard => matches_exact(cmp, ver), |
33 | Op::Greater => matches_greater(cmp, ver), |
34 | Op::GreaterEq => matches_exact(cmp, ver) || matches_greater(cmp, ver), |
35 | Op::Less => matches_less(cmp, ver), |
36 | Op::LessEq => matches_exact(cmp, ver) || matches_less(cmp, ver), |
37 | Op::Tilde => matches_tilde(cmp, ver), |
38 | Op::Caret => matches_caret(cmp, ver), |
39 | #[cfg (no_non_exhaustive)] |
40 | Op::__NonExhaustive => unreachable!(), |
41 | } |
42 | } |
43 | |
44 | fn matches_exact(cmp: &Comparator, ver: &Version) -> bool { |
45 | if ver.major != cmp.major { |
46 | return false; |
47 | } |
48 | |
49 | if let Some(minor: u64) = cmp.minor { |
50 | if ver.minor != minor { |
51 | return false; |
52 | } |
53 | } |
54 | |
55 | if let Some(patch: u64) = cmp.patch { |
56 | if ver.patch != patch { |
57 | return false; |
58 | } |
59 | } |
60 | |
61 | ver.pre == cmp.pre |
62 | } |
63 | |
64 | fn matches_greater(cmp: &Comparator, ver: &Version) -> bool { |
65 | if ver.major != cmp.major { |
66 | return ver.major > cmp.major; |
67 | } |
68 | |
69 | match cmp.minor { |
70 | None => return false, |
71 | Some(minor) => { |
72 | if ver.minor != minor { |
73 | return ver.minor > minor; |
74 | } |
75 | } |
76 | } |
77 | |
78 | match cmp.patch { |
79 | None => return false, |
80 | Some(patch) => { |
81 | if ver.patch != patch { |
82 | return ver.patch > patch; |
83 | } |
84 | } |
85 | } |
86 | |
87 | ver.pre > cmp.pre |
88 | } |
89 | |
90 | fn matches_less(cmp: &Comparator, ver: &Version) -> bool { |
91 | if ver.major != cmp.major { |
92 | return ver.major < cmp.major; |
93 | } |
94 | |
95 | match cmp.minor { |
96 | None => return false, |
97 | Some(minor) => { |
98 | if ver.minor != minor { |
99 | return ver.minor < minor; |
100 | } |
101 | } |
102 | } |
103 | |
104 | match cmp.patch { |
105 | None => return false, |
106 | Some(patch) => { |
107 | if ver.patch != patch { |
108 | return ver.patch < patch; |
109 | } |
110 | } |
111 | } |
112 | |
113 | ver.pre < cmp.pre |
114 | } |
115 | |
116 | fn matches_tilde(cmp: &Comparator, ver: &Version) -> bool { |
117 | if ver.major != cmp.major { |
118 | return false; |
119 | } |
120 | |
121 | if let Some(minor: u64) = cmp.minor { |
122 | if ver.minor != minor { |
123 | return false; |
124 | } |
125 | } |
126 | |
127 | if let Some(patch: u64) = cmp.patch { |
128 | if ver.patch != patch { |
129 | return ver.patch > patch; |
130 | } |
131 | } |
132 | |
133 | ver.pre >= cmp.pre |
134 | } |
135 | |
136 | fn matches_caret(cmp: &Comparator, ver: &Version) -> bool { |
137 | if ver.major != cmp.major { |
138 | return false; |
139 | } |
140 | |
141 | let minor = match cmp.minor { |
142 | None => return true, |
143 | Some(minor) => minor, |
144 | }; |
145 | |
146 | let patch = match cmp.patch { |
147 | None => { |
148 | if cmp.major > 0 { |
149 | return ver.minor >= minor; |
150 | } else { |
151 | return ver.minor == minor; |
152 | } |
153 | } |
154 | Some(patch) => patch, |
155 | }; |
156 | |
157 | if cmp.major > 0 { |
158 | if ver.minor != minor { |
159 | return ver.minor > minor; |
160 | } else if ver.patch != patch { |
161 | return ver.patch > patch; |
162 | } |
163 | } else if minor > 0 { |
164 | if ver.minor != minor { |
165 | return false; |
166 | } else if ver.patch != patch { |
167 | return ver.patch > patch; |
168 | } |
169 | } else if ver.minor != minor || ver.patch != patch { |
170 | return false; |
171 | } |
172 | |
173 | ver.pre >= cmp.pre |
174 | } |
175 | |
176 | fn pre_is_compatible(cmp: &Comparator, ver: &Version) -> bool { |
177 | cmp.major == ver.major |
178 | && cmp.minor == Some(ver.minor) |
179 | && cmp.patch == Some(ver.patch) |
180 | && !cmp.pre.is_empty() |
181 | } |
182 | |