pubgrub/version_set.rs
1// SPDX-License-Identifier: MPL-2.0
2
3use std::fmt::{Debug, Display};
4
5use crate::Ranges;
6
7/// A set of versions.
8///
9/// See [`Ranges`] for an implementation.
10///
11/// The methods with default implementations can be overwritten for better performance, but their
12/// output must be equal to the default implementation.
13///
14/// # Equality
15///
16/// It is important that the `Eq` trait is implemented so that if two sets contain the same
17/// versions, they are equal under `Eq`. In particular, you can only use `#[derive(Eq, PartialEq)]`
18/// if `Eq` is strictly equivalent to the structural equality, i.e. if version sets are always
19/// stored in a canonical representations. Such problems may arise if your implementations of
20/// `complement()` and `intersection()` do not return canonical representations.
21///
22/// For example, `>=1,<4 || >=2,<5` and `>=1,<4 || >=3,<5` are equal, because they can both be
23/// normalized to `>=1,<5`.
24///
25/// Note that pubgrub does not know which versions actually exist for a package, the contract
26/// is about upholding the mathematical properties of set operations, assuming all versions are
27/// possible. This is required for the solver to determine the relationship of version sets to each
28/// other.
29pub trait VersionSet: Debug + Display + Clone + Eq {
30 /// Version type associated with the sets manipulated.
31 type V: Debug + Display + Clone + Ord;
32
33 // Constructors
34
35 /// An empty set containing no version.
36 fn empty() -> Self;
37
38 /// A set containing only the given version.
39 fn singleton(v: Self::V) -> Self;
40
41 // Operations
42
43 /// The set of all version that are not in this set.
44 fn complement(&self) -> Self;
45
46 /// The set of all versions that are in both sets.
47 fn intersection(&self, other: &Self) -> Self;
48
49 /// Whether the version is part of this set.
50 fn contains(&self, v: &Self::V) -> bool;
51
52 // Automatically implemented functions
53
54 /// The set containing all versions.
55 ///
56 /// The default implementation is the complement of the empty set.
57 fn full() -> Self {
58 Self::empty().complement()
59 }
60
61 /// The set of all versions that are either (or both) of the sets.
62 ///
63 /// The default implementation is complement of the intersection of the complements of both sets
64 /// (De Morgan's law).
65 fn union(&self, other: &Self) -> Self {
66 self.complement()
67 .intersection(&other.complement())
68 .complement()
69 }
70
71 /// Whether the ranges have no overlapping segments.
72 fn is_disjoint(&self, other: &Self) -> bool {
73 self.intersection(other) == Self::empty()
74 }
75
76 /// Whether all ranges of `self` are contained in `other`.
77 fn subset_of(&self, other: &Self) -> bool {
78 self == &self.intersection(other)
79 }
80}
81
82/// [`Ranges`] contains optimized implementations of all operations.
83impl<T: Debug + Display + Clone + Eq + Ord> VersionSet for Ranges<T> {
84 type V = T;
85
86 fn empty() -> Self {
87 Ranges::empty()
88 }
89
90 fn singleton(v: Self::V) -> Self {
91 Ranges::singleton(v)
92 }
93
94 fn complement(&self) -> Self {
95 Ranges::complement(self)
96 }
97
98 fn intersection(&self, other: &Self) -> Self {
99 Ranges::intersection(self, other)
100 }
101
102 fn contains(&self, v: &Self::V) -> bool {
103 Ranges::contains(self, v)
104 }
105
106 fn full() -> Self {
107 Ranges::full()
108 }
109
110 fn union(&self, other: &Self) -> Self {
111 Ranges::union(self, other)
112 }
113
114 fn is_disjoint(&self, other: &Self) -> bool {
115 Ranges::is_disjoint(self, other)
116 }
117
118 fn subset_of(&self, other: &Self) -> bool {
119 Ranges::subset_of(self, other)
120 }
121}