rust_toolchain/
component.rs1use std::borrow::Cow;
2use std::collections::BTreeSet;
3use std::slice;
4use std::sync::Arc;
5
6#[derive(Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
15pub struct Component {
16 name: Cow<'static, str>,
17}
18
19impl Component {
20 pub fn new(name: impl Into<Cow<'static, str>>) -> Self {
22 Self { name: name.into() }
23 }
24
25 pub fn name(&self) -> &str {
27 self.name.as_ref()
28 }
29}
30
31#[derive(Clone, Debug, Eq)]
39pub struct ComponentSet {
40 components: Arc<[Component]>,
41}
42
43impl ComponentSet {
44 pub fn len(&self) -> usize {
46 self.components.len()
47 }
48
49 pub fn is_empty(&self) -> bool {
51 self.components.is_empty()
52 }
53
54 pub fn contains(&self, component: &Component) -> bool {
56 self.components.contains(component)
57 }
58
59 pub fn iter(&self) -> slice::Iter<'_, Component> {
61 self.components.iter()
62 }
63
64 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}