1 use crate::{Comparator, Op, Version, VersionReq};
2 
matches_req(req: &VersionReq, ver: &Version) -> bool3 pub(crate) fn matches_req(req: &VersionReq, ver: &Version) -> bool {
4     for cmp 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 in &req.comparators {
18         if pre_is_compatible(cmp, ver) {
19             return true;
20         }
21     }
22 
23     false
24 }
25 
matches_comparator(cmp: &Comparator, ver: &Version) -> bool26 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 
matches_impl(cmp: &Comparator, ver: &Version) -> bool30 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 
matches_exact(cmp: &Comparator, ver: &Version) -> bool44 fn matches_exact(cmp: &Comparator, ver: &Version) -> bool {
45     if ver.major != cmp.major {
46         return false;
47     }
48 
49     if let Some(minor) = cmp.minor {
50         if ver.minor != minor {
51             return false;
52         }
53     }
54 
55     if let Some(patch) = cmp.patch {
56         if ver.patch != patch {
57             return false;
58         }
59     }
60 
61     ver.pre == cmp.pre
62 }
63 
matches_greater(cmp: &Comparator, ver: &Version) -> bool64 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 
matches_less(cmp: &Comparator, ver: &Version) -> bool90 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 
matches_tilde(cmp: &Comparator, ver: &Version) -> bool116 fn matches_tilde(cmp: &Comparator, ver: &Version) -> bool {
117     if ver.major != cmp.major {
118         return false;
119     }
120 
121     if let Some(minor) = cmp.minor {
122         if ver.minor != minor {
123             return false;
124         }
125     }
126 
127     if let Some(patch) = cmp.patch {
128         if ver.patch != patch {
129             return ver.patch > patch;
130         }
131     }
132 
133     ver.pre >= cmp.pre
134 }
135 
matches_caret(cmp: &Comparator, ver: &Version) -> bool136 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 
pre_is_compatible(cmp: &Comparator, ver: &Version) -> bool176 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