fast_version_core/
version_req.rs

1use crate::version::Version;
2#[cfg(feature = "serde")]
3use serde::{Deserialize, Serialize};
4#[cfg(feature = "nightly")]
5use core::simd::u64x4;
6
7/// The variants in which a version requirenment can be constructed.
8#[non_exhaustive]
9#[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone, Copy)]
10#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
11pub enum VersionReqVariant {
12    /// Equivalent of "1.2.3" where `1.2.3` is the only version this requirenment will match to.
13    Strict(Version),
14    /// Composition of an lower and an upper bound.
15    Compound(VersionReqVariantLowerBound, VersionReqVariantUpperBound),
16    /// Equivalent of ">1"
17    MajorGreater { major: u64 },
18    /// Equivalent of ">1.2"
19    MinorGreater { major: u64, minor: u64 },
20    /// Equivalent of ">1.2.3"
21    PatchGreater { major: u64, minor: u64, patch: u64 },
22    /// Equivalent of ">=1"
23    MajorGreaterEqual { major: u64 },
24    /// Equivalent of ">=1.2"
25    MinorGreaterEqual { major: u64, minor: u64 },
26    /// Equivalent of ">=1.2.3"
27    PatchGreaterEqual { major: u64, minor: u64, patch: u64 },
28    /// Equivalent of "<1"
29    MajorLess { major: u64 },
30    /// Equivalent of "<1.2"
31    MinorLess { major: u64, minor: u64 },
32    /// Equivalent of "<1.2.3"
33    PatchLess { major: u64, minor: u64, patch: u64 },
34    /// Equivalent of "<=1"
35    MajorLessEqual { major: u64 },
36    /// Equivalent of "<=1.2"
37    MinorLessEqual { major: u64, minor: u64 },
38    /// Equivalent of "<=1.2.3"
39    PatchLessEqual { major: u64, minor: u64, patch: u64 },
40}
41
42/// Lower bound part of [VersionReqVariant::Compound]
43#[non_exhaustive]
44#[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone, Copy)]
45#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
46pub enum VersionReqVariantLowerBound {
47    /// Equivalent of ">1"
48    MajorGreater { major: u64 },
49    /// Equivalent of ">1.2"
50    MinorGreater { major: u64, minor: u64 },
51    /// Equivalent of ">1.2.3"
52    PatchGreater { major: u64, minor: u64, patch: u64 },
53    /// Equivalent of ">=1"
54    MajorGreaterEqual { major: u64 },
55    /// Equivalent of ">=1.2"
56    MinorGreaterEqual { major: u64, minor: u64 },
57    /// Equivalent of ">=1.2.3"
58    PatchGreaterEqual { major: u64, minor: u64, patch: u64 },
59}
60
61/// Lower bound part of [VersionReqVariant::Compound]
62#[non_exhaustive]
63#[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone, Copy)]
64#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
65pub enum VersionReqVariantUpperBound {
66    /// Equivalent of "<1"
67    MajorLess { major: u64 },
68    /// Equivalent of "<1.2"
69    MinorLess { major: u64, minor: u64 },
70    /// Equivalent of "<1.2.3"
71    PatchLess { major: u64, minor: u64, patch: u64 },
72    /// Equivalent of "<=1"
73    MajorLessEqual { major: u64 },
74    /// Equivalent of "<=1.2"
75    MinorLessEqual { major: u64, minor: u64 },
76    /// Equivalent of "<=1.2.3"
77    PatchLessEqual { major: u64, minor: u64, patch: u64 },
78}
79
80/// Representing an actual version requirenment, normally constructed through [VersionReq::new].
81#[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    /// Equivalent of "*"
94    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    /// checks wether the Version Requirenment matches with the version. Returns true if the
110    /// Requirenments are met.
111    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    /// checks wether the version requirenment matches with the version. Returns true if the
122    /// Requirenments are met.
123    /// This comparison works with SIMD, thus maybe faster.
124    ///
125    /// ```
126    /// # use fast_version_core::{version::Version, version_req::VersionReq};
127    ///
128    /// const VERSION_REQ: VersionReq = VersionReq::STAR;
129    /// const VERSION: Version = Version::new(1, 2, 3);
130    ///
131    /// assert_eq!(VERSION_REQ.matches(&VERSION), VERSION_REQ.simd_matches(&VERSION));
132    /// ```
133    #[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    /// Normal constructer of the Version Requirenment.
142    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}