Skip to main content

rust_toolchain/
component.rs

1use std::borrow::Cow;
2use std::collections::BTreeSet;
3use std::slice;
4use std::sync::Arc;
5
6/// A toolchain component
7///
8/// # Reading materials
9///
10/// - [`rustup component history`]
11///
12/// [`rustup concepts: components`]: https://rust-lang.github.io/rustup/concepts/components.html
13/// [`rustup component history`]: https://rust-lang.github.io/rustup-components-history/
14#[derive(Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
15pub struct Component {
16    name: Cow<'static, str>,
17}
18
19impl Component {
20    /// Create a new Component instance
21    pub fn new(name: impl Into<Cow<'static, str>>) -> Self {
22        Self { name: name.into() }
23    }
24
25    /// The name of the component
26    pub fn name(&self) -> &str {
27        self.name.as_ref()
28    }
29}
30
31/// A set of unique [`Component`]s, ordered by name.
32///
33/// The components are held behind an [`Arc`], so cloning a set, and with it cloning
34/// the [`Toolchain`] which holds it, does not copy its components. Two toolchains
35/// which ship the same components can share a single set.
36///
37/// [`Toolchain`]: crate::Toolchain
38#[derive(Clone, Debug, Eq)]
39pub struct ComponentSet {
40    components: Arc<[Component]>,
41}
42
43impl ComponentSet {
44    /// The amount of components in the set.
45    pub fn len(&self) -> usize {
46        self.components.len()
47    }
48
49    /// Returns true if the set holds no components, and false otherwise.
50    pub fn is_empty(&self) -> bool {
51        self.components.is_empty()
52    }
53
54    /// Returns true if the given component is a member of the set.
55    pub fn contains(&self, component: &Component) -> bool {
56        self.components.contains(component)
57    }
58
59    /// Iterate over the components of the set.
60    pub fn iter(&self) -> slice::Iter<'_, Component> {
61        self.components.iter()
62    }
63
64    /// The components of the set, as a slice ordered by name.
65    pub fn as_slice(&self) -> &[Component] {
66        &self.components
67    }
68}
69
70impl Default for ComponentSet {
71    fn default() -> Self {
72        Self {
73            components: Vec::new().into(),
74        }
75    }
76}
77
78impl PartialEq for ComponentSet {
79    fn eq(&self, other: &Self) -> bool {
80        Arc::ptr_eq(&self.components, &other.components) || self.components == other.components
81    }
82}
83
84impl FromIterator<Component> for ComponentSet {
85    fn from_iter<I: IntoIterator<Item = Component>>(iter: I) -> Self {
86        let unique = iter.into_iter().collect::<BTreeSet<_>>();
87
88        Self {
89            components: unique.into_iter().collect(),
90        }
91    }
92}
93
94impl From<Vec<Component>> for ComponentSet {
95    fn from(components: Vec<Component>) -> Self {
96        components.into_iter().collect()
97    }
98}
99
100impl<'a> IntoIterator for &'a ComponentSet {
101    type Item = &'a Component;
102    type IntoIter = slice::Iter<'a, Component>;
103
104    fn into_iter(self) -> Self::IntoIter {
105        self.components.iter()
106    }
107}
108
109#[cfg(test)]
110mod tests {
111    use super::*;
112
113    #[test]
114    fn new_instance() {
115        let c = Component::new("sample");
116        assert_eq!(c.name(), "sample");
117    }
118
119    mod component_set {
120        use super::*;
121        use std::ptr;
122
123        #[test]
124        fn an_empty_set() {
125            let set = ComponentSet::default();
126
127            assert!(set.is_empty());
128            assert_eq!(set.len(), 0);
129        }
130
131        #[test]
132        fn a_set_is_ordered_by_name() {
133            let set = [Component::new("rustc"), Component::new("cargo")]
134                .into_iter()
135                .collect::<ComponentSet>();
136
137            let names = set.iter().map(|c| c.name()).collect::<Vec<_>>();
138
139            assert_eq!(names, ["cargo", "rustc"]);
140        }
141
142        #[test]
143        fn a_set_holds_every_component_once() {
144            let set = [Component::new("cargo"), Component::new("cargo")]
145                .into_iter()
146                .collect::<ComponentSet>();
147
148            assert_eq!(set.len(), 1);
149            assert!(set.contains(&Component::new("cargo")));
150        }
151
152        #[test]
153        fn a_set_is_equal_regardless_of_the_order_it_was_built_in() {
154            let left = [Component::new("rustc"), Component::new("cargo")]
155                .into_iter()
156                .collect::<ComponentSet>();
157            let right = [Component::new("cargo"), Component::new("rustc")]
158                .into_iter()
159                .collect::<ComponentSet>();
160
161            assert_eq!(left, right);
162        }
163
164        #[test]
165        fn a_clone_shares_the_components_of_the_set_it_was_cloned_from() {
166            let set = [Component::new("cargo")]
167                .into_iter()
168                .collect::<ComponentSet>();
169            let clone = set.clone();
170
171            assert!(ptr::eq(set.as_slice(), clone.as_slice()));
172        }
173    }
174}