1use crate::version::Version;
2#[cfg(feature = "serde")]
3use serde::{Deserialize, Serialize};
4#[cfg(feature = "nightly")]
5use core::simd::u64x4;
6
7#[non_exhaustive]
9#[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone, Copy)]
10#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
11pub enum VersionReqVariant {
12 Strict(Version),
14 Compound(VersionReqVariantLowerBound, VersionReqVariantUpperBound),
16 MajorGreater { major: u64 },
18 MinorGreater { major: u64, minor: u64 },
20 PatchGreater { major: u64, minor: u64, patch: u64 },
22 MajorGreaterEqual { major: u64 },
24 MinorGreaterEqual { major: u64, minor: u64 },
26 PatchGreaterEqual { major: u64, minor: u64, patch: u64 },
28 MajorLess { major: u64 },
30 MinorLess { major: u64, minor: u64 },
32 PatchLess { major: u64, minor: u64, patch: u64 },
34 MajorLessEqual { major: u64 },
36 MinorLessEqual { major: u64, minor: u64 },
38 PatchLessEqual { major: u64, minor: u64, patch: u64 },
40}
41
42#[non_exhaustive]
44#[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone, Copy)]
45#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
46pub enum VersionReqVariantLowerBound {
47 MajorGreater { major: u64 },
49 MinorGreater { major: u64, minor: u64 },
51 PatchGreater { major: u64, minor: u64, patch: u64 },
53 MajorGreaterEqual { major: u64 },
55 MinorGreaterEqual { major: u64, minor: u64 },
57 PatchGreaterEqual { major: u64, minor: u64, patch: u64 },
59}
60
61#[non_exhaustive]
63#[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone, Copy)]
64#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
65pub enum VersionReqVariantUpperBound {
66 MajorLess { major: u64 },
68 MinorLess { major: u64, minor: u64 },
70 PatchLess { major: u64, minor: u64, patch: u64 },
72 MajorLessEqual { major: u64 },
74 MinorLessEqual { major: u64, minor: u64 },
76 PatchLessEqual { major: u64, minor: u64, patch: u64 },
78}
79
80#[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone, Copy, Debug)]
82#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
83pub struct VersionReq {
84 pub(crate) major_lower: u64,
85 pub(crate) minor_lower: u64,
86 pub(crate) patch_lower: u64,
87 pub(crate) major_higher: u64,
88 pub(crate) minor_higher: u64,
89 pub(crate) patch_higher: u64,
90}
91
92impl VersionReq {
93 pub const STAR: Self = Self::star();
95
96 const fn star() -> Self {
97 const MAX: u64 = u64::MAX;
98 const MIN: u64 = u64::MIN;
99 Self {
100 major_lower: MIN,
101 minor_lower: MIN,
102 patch_lower: MIN,
103 major_higher: MAX,
104 minor_higher: MAX,
105 patch_higher: MAX,
106 }
107 }
108
109 pub const fn matches(&self, version: &Version) -> bool {
112 let lower_match = self.major_lower <= version.major
113 && self.minor_lower <= version.minor
114 && self.patch_lower <= version.patch;
115 let higher_match = self.major_higher >= version.major
116 && self.minor_higher >= version.minor
117 && self.patch_higher >= version.patch;
118 lower_match && higher_match
119 }
120
121 #[cfg(feature = "nightly")]
134 pub fn simd_matches(&self, version: &Version) -> bool {
135 let simd_version: u64x4 = u64x4::from_array([version.major, version.minor, version.patch, 0]);
136 let simd_req_lower: u64x4 = u64x4::from_array([self.major_lower, self.minor_lower, self.patch_lower, 0]);
137 let simd_req_higher = u64x4::from_array([self.major_higher, self.minor_higher, self.patch_higher, 0]);
138 simd_req_lower.lanes_le(simd_version).all() && simd_req_higher.lanes_ge(simd_version).all()
139 }
140
141 pub const fn new(version_req: &VersionReqVariant) -> Self {
143 match version_req {
144 VersionReqVariant::Strict(d) => Self::new_strict(d),
145 VersionReqVariant::Compound(lower, upper) => Self::new_compound(lower, upper),
146 VersionReqVariant::MajorGreater { major } => {
147 let major_geq = major.saturating_add(1);
148 Self::new_lower_bounded_equal(major_geq, 0, 0)
149 }
150 VersionReqVariant::MinorGreater { major, minor } => {
151 let major_geq = major.saturating_add(1);
152 let minor_geq = minor.saturating_add(1);
153 Self::new_lower_bounded_equal(major_geq, minor_geq, 0)
154 }
155 VersionReqVariant::PatchGreater {
156 major,
157 minor,
158 patch,
159 } => {
160 let major_geq = major.saturating_add(1);
161 let minor_geq = minor.saturating_add(1);
162 let patch_geq = patch.saturating_add(1);
163 Self::new_lower_bounded_equal(major_geq, minor_geq, patch_geq)
164 }
165 VersionReqVariant::MajorGreaterEqual { major } => {
166 Self::new_lower_bounded_equal(*major, 0, 0)
167 }
168 VersionReqVariant::MinorGreaterEqual { major, minor } => {
169 Self::new_lower_bounded_equal(*major, *minor, 0)
170 }
171 VersionReqVariant::PatchGreaterEqual {
172 major,
173 minor,
174 patch,
175 } => Self::new_lower_bounded_equal(*major, *minor, *patch),
176 VersionReqVariant::MajorLess { major } => {
177 let major_leq = major.saturating_sub(1);
178 Self::new_upper_bounded_equal(major_leq, u64::MAX, u64::MAX)
179 }
180 VersionReqVariant::MinorLess { major, minor } => {
181 let major_leq = major.saturating_sub(1);
182 let minor_leq = minor.saturating_sub(1);
183 Self::new_upper_bounded_equal(major_leq, minor_leq, u64::MAX)
184 }
185 VersionReqVariant::PatchLess {
186 major,
187 minor,
188 patch,
189 } => {
190 let major_leq = major.saturating_sub(1);
191 let minor_leq = minor.saturating_sub(1);
192 let patch_leq = patch.saturating_sub(1);
193 Self::new_upper_bounded_equal(major_leq, minor_leq, patch_leq)
194 }
195 VersionReqVariant::MajorLessEqual { major } => {
196 Self::new_upper_bounded_equal(*major, u64::MAX, u64::MAX)
197 }
198 VersionReqVariant::MinorLessEqual { major, minor } => {
199 Self::new_upper_bounded_equal(*major, *minor, u64::MAX)
200 }
201 VersionReqVariant::PatchLessEqual {
202 major,
203 minor,
204 patch,
205 } => Self::new_upper_bounded_equal(*major, *minor, *patch),
206 }
207 }
208
209 #[inline]
210 const fn new_upper_bounded_equal(major: u64, minor: u64, patch: u64) -> Self {
211 Self {
212 major_lower: 0,
213 minor_lower: 0,
214 patch_lower: 0,
215 major_higher: major,
216 minor_higher: minor,
217 patch_higher: patch,
218 }
219 }
220
221 #[inline]
222 const fn new_lower_bounded_equal(major: u64, minor: u64, patch: u64) -> Self {
223 Self {
224 major_lower: major,
225 minor_lower: minor,
226 patch_lower: patch,
227 major_higher: u64::MAX,
228 minor_higher: u64::MAX,
229 patch_higher: u64::MAX,
230 }
231 }
232
233 #[inline]
234 const fn new_strict(version: &Version) -> Self {
235 let major = version.major;
236 let minor = version.minor;
237 let patch = version.patch;
238 VersionReq {
239 major_lower: major,
240 minor_lower: minor,
241 patch_lower: patch,
242 major_higher: major,
243 minor_higher: minor,
244 patch_higher: patch,
245 }
246 }
247
248 #[inline]
249 const fn new_compound(
250 lower_bound: &VersionReqVariantLowerBound,
251 upper_bound: &VersionReqVariantUpperBound,
252 ) -> Self {
253 let (major_lower, minor_lower, patch_lower) = Self::new_lower_bound(lower_bound);
254 let (major_higher, minor_higher, patch_higher) = Self::new_upper_bound(upper_bound);
255 Self {
256 major_lower,
257 minor_lower,
258 patch_lower,
259 major_higher,
260 minor_higher,
261 patch_higher,
262 }
263 }
264
265 #[inline]
266 const fn new_lower_bound(lower_bound: &VersionReqVariantLowerBound) -> (u64, u64, u64) {
267 match lower_bound {
268 VersionReqVariantLowerBound::MajorGreater { major } => {
269 let major_geq = major.saturating_add(1);
270 (major_geq, 0, 0)
271 }
272 VersionReqVariantLowerBound::MinorGreater { major, minor } => {
273 let major_geq = major.saturating_add(1);
274 let minor_geq = minor.saturating_add(1);
275 (major_geq, minor_geq, 0)
276 }
277 VersionReqVariantLowerBound::PatchGreater {
278 major,
279 minor,
280 patch,
281 } => {
282 let major_geq = major.saturating_add(1);
283 let minor_geq = minor.saturating_add(1);
284 let patch_geq = patch.saturating_add(1);
285 (major_geq, minor_geq, patch_geq)
286 }
287 VersionReqVariantLowerBound::MajorGreaterEqual { major } => (*major, 0, 0),
288 VersionReqVariantLowerBound::MinorGreaterEqual { major, minor } => (*major, *minor, 0),
289 VersionReqVariantLowerBound::PatchGreaterEqual {
290 major,
291 minor,
292 patch,
293 } => (*major, *minor, *patch),
294 }
295 }
296
297 #[inline]
298 const fn new_upper_bound(upper_bound: &VersionReqVariantUpperBound) -> (u64, u64, u64) {
299 match upper_bound {
300 VersionReqVariantUpperBound::MajorLess { major } => {
301 let major_leq = major.saturating_sub(1);
302 (major_leq, u64::MAX, u64::MAX)
303 }
304 VersionReqVariantUpperBound::MinorLess { major, minor } => {
305 let major_leq = major.saturating_sub(1);
306 let minor_leq = minor.saturating_sub(1);
307 (major_leq, minor_leq, u64::MAX)
308 }
309 VersionReqVariantUpperBound::PatchLess {
310 major,
311 minor,
312 patch,
313 } => {
314 let major_leq = major.saturating_sub(1);
315 let minor_leq = minor.saturating_sub(1);
316 let patch_leq = patch.saturating_sub(1);
317 (major_leq, minor_leq, patch_leq)
318 }
319 VersionReqVariantUpperBound::MajorLessEqual { major } => (*major, u64::MAX, u64::MAX),
320 VersionReqVariantUpperBound::MinorLessEqual { major, minor } => {
321 (*major, *minor, u64::MAX)
322 }
323 VersionReqVariantUpperBound::PatchLessEqual {
324 major,
325 minor,
326 patch,
327 } => (*major, *minor, *patch),
328 }
329 }
330}