cml/
one_or_many.rs

1// Copyright 2020 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use std::fmt::{self, Display, Formatter};
6use std::{slice, vec};
7
8/// Represents either a single value, or multiple values of T.
9/// Useful for differentiating between an array of length 1 and a single value.
10#[derive(Debug, Clone, Ord, PartialOrd, Eq)]
11pub enum OneOrMany<T> {
12    /// A single instance of T.
13    One(T),
14    /// One or more instances of T.
15    Many(Vec<T>),
16}
17
18impl<T> OneOrMany<T> {
19    /// Returns `true` if this `OneOrMany<T>` is a `Many` value.
20    pub fn is_many(&self) -> bool {
21        match self {
22            Self::One(_) => false,
23            Self::Many(_) => true,
24        }
25    }
26
27    /// Returns an [`Iter`] over the values of `OneOrMany<T>`.
28    pub fn iter(&self) -> Iter<'_, T> {
29        match self {
30            Self::One(item) => Iter { inner_one: Some(item), inner_many: None },
31            Self::Many(items) => Iter { inner_one: None, inner_many: Some(items.iter()) },
32        }
33    }
34
35    /// Returns the number of values in this `OneOrMany<T>`.
36    pub fn len(&self) -> usize {
37        match self {
38            Self::One(_) => 1,
39            Self::Many(v) => v.len(),
40        }
41    }
42
43    /// Returns a `OneOrMany<&T>` that references this `OneOrMany<T>`.
44    pub fn as_ref<S>(&self) -> OneOrMany<&S>
45    where
46        T: AsRef<S>,
47        S: ?Sized,
48    {
49        match self {
50            Self::One(o) => OneOrMany::<&S>::One(o.as_ref()),
51            Self::Many(v) => OneOrMany::<&S>::Many(v.iter().map(|o| o.as_ref()).collect()),
52        }
53    }
54}
55
56impl<T> OneOrMany<T>
57where
58    T: Ord + Clone,
59{
60    /// Canonicalizes self by:
61    /// * Transforming to ::One() if is_many() but len() == 1
62    /// * Sorting items if is_many()
63    pub fn canonicalize(&mut self) {
64        let mut replace_with = None;
65        match self {
66            OneOrMany::One(_) => {}
67            OneOrMany::Many(many) => {
68                if many.len() == 1 {
69                    replace_with = Some(many.first().unwrap().clone());
70                } else {
71                    many.sort();
72                }
73            }
74        }
75        if let Some(t) = replace_with {
76            *self = OneOrMany::One(t);
77        }
78    }
79}
80
81impl<T> OneOrMany<T>
82where
83    T: PartialEq,
84{
85    /// Returns true if this `OneOrMany<T>` contains the given element.
86    pub fn contains(&self, e: &T) -> bool {
87        match self {
88            Self::One(item) => item == e,
89            Self::Many(items) => items.contains(e),
90        }
91    }
92}
93
94impl<T> PartialEq for OneOrMany<T>
95where
96    T: PartialEq,
97{
98    fn eq(&self, other: &Self) -> bool {
99        self.iter().eq(other.into_iter())
100    }
101}
102
103impl<'a, T> IntoIterator for &'a OneOrMany<T> {
104    type Item = &'a T;
105    type IntoIter = Iter<'a, T>;
106
107    fn into_iter(self) -> Iter<'a, T> {
108        self.iter()
109    }
110}
111
112impl<T> IntoIterator for OneOrMany<T> {
113    type Item = T;
114    type IntoIter = IntoIter<T>;
115
116    fn into_iter(self) -> IntoIter<T> {
117        match self {
118            OneOrMany::One(item) => IntoIter { inner_one: Some(item), inner_many: None },
119            OneOrMany::Many(items) => {
120                IntoIter { inner_one: None, inner_many: Some(items.into_iter()) }
121            }
122        }
123    }
124}
125
126impl<T> FromIterator<T> for OneOrMany<T> {
127    fn from_iter<I>(iter: I) -> Self
128    where
129        I: IntoIterator<Item = T> + Sized,
130    {
131        let mut iter = iter.into_iter();
132        if let Some(first) = iter.next() {
133            let rest: Vec<_> = iter.collect();
134            if rest.is_empty() {
135                Self::One(first)
136            } else {
137                let mut out = vec![first];
138                out.extend(rest);
139                Self::Many(out)
140            }
141        } else {
142            Self::Many(vec![])
143        }
144    }
145}
146
147impl<T> From<T> for OneOrMany<T> {
148    fn from(item: T) -> Self {
149        Self::One(item)
150    }
151}
152
153impl<'a, T: Display> Display for OneOrMany<T> {
154    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
155        match self {
156            OneOrMany::One(item) => Display::fmt(item, f),
157            OneOrMany::Many(items) => {
158                let mut iter = items.iter();
159                if let Some(first_item) = iter.next() {
160                    Display::fmt(first_item, f)?;
161                }
162                for item in iter {
163                    f.write_str(", ")?;
164                    Display::fmt(item, f)?;
165                }
166                Ok(())
167            }
168        }
169    }
170}
171
172/// Immutable iterator over a `OneOrMany`.
173/// This `struct` is created by [`OneOrMany::iter`].
174///
175/// [`OneOrMany::iter`]: struct.OneOrMany.html#method.iter
176pub struct Iter<'a, T> {
177    inner_one: Option<&'a T>,
178    inner_many: Option<slice::Iter<'a, T>>,
179}
180
181impl<'a, T> Iterator for Iter<'a, T> {
182    type Item = &'a T;
183
184    fn next(&mut self) -> Option<Self::Item> {
185        if let Some(item) = self.inner_one.take() {
186            Some(item)
187        } else if let Some(iter) = &mut self.inner_many {
188            iter.next()
189        } else {
190            None
191        }
192    }
193
194    fn size_hint(&self) -> (usize, Option<usize>) {
195        if let Some(_) = self.inner_one {
196            (1, Some(1))
197        } else if let Some(iter) = &self.inner_many {
198            iter.size_hint()
199        } else {
200            (0, Some(0))
201        }
202    }
203}
204
205impl<'a, T> ExactSizeIterator for Iter<'a, T> {}
206
207/// An iterator that moves out of a `OneOrMany`.
208/// This `struct` is created by the `into_iter` method on [`OneOrMany`] (provided by the [`IntoIterator`] trait).
209///
210/// [`OneOrMany`]: struct.OneOrMany.html
211/// [`IntoIterator`]: https://doc.rust-lang.org/std/iter/trait.IntoIterator.html
212pub struct IntoIter<T> {
213    inner_one: Option<T>,
214    inner_many: Option<vec::IntoIter<T>>,
215}
216
217impl<T> Iterator for IntoIter<T> {
218    type Item = T;
219
220    fn next(&mut self) -> Option<Self::Item> {
221        if let Some(item) = self.inner_one.take() {
222            Some(item)
223        } else if let Some(iter) = &mut self.inner_many {
224            iter.next()
225        } else {
226            None
227        }
228    }
229
230    fn size_hint(&self) -> (usize, Option<usize>) {
231        if let Some(_) = self.inner_one {
232            (1, Some(1))
233        } else if let Some(iter) = &self.inner_many {
234            iter.size_hint()
235        } else {
236            (0, Some(0))
237        }
238    }
239}
240
241impl<T> ExactSizeIterator for IntoIter<T> {}
242
243#[cfg(test)]
244mod tests {
245    use super::*;
246    use assert_matches::assert_matches;
247
248    #[test]
249    fn test_iter_one() {
250        let v = OneOrMany::One(34);
251        let mut iter = v.iter();
252        assert_matches!(iter.next(), Some(&34));
253        assert_matches!(iter.next(), None);
254    }
255
256    #[test]
257    fn test_iter_many() {
258        let v = OneOrMany::Many(vec![1, 2, 3]);
259        let mut iter = v.iter();
260        assert_matches!(iter.next(), Some(&1));
261        assert_matches!(iter.next(), Some(&2));
262        assert_matches!(iter.next(), Some(&3));
263        assert_matches!(iter.next(), None);
264    }
265
266    #[test]
267    fn test_is_many() {
268        let v = OneOrMany::One(34);
269        assert_eq!(v.is_many(), false);
270
271        let v = OneOrMany::Many(vec![1, 2, 3]);
272        assert_eq!(v.is_many(), true);
273    }
274
275    #[test]
276    fn test_from_iter() {
277        let o: OneOrMany<i64> = [34].into_iter().collect();
278        assert_eq!(o, OneOrMany::One(34));
279
280        let o: OneOrMany<i64> = [1, 2, 3].into_iter().collect();
281        assert_eq!(o, OneOrMany::Many(vec![1, 2, 3]));
282
283        let o: OneOrMany<i64> = [].into_iter().collect();
284        assert_eq!(o, OneOrMany::Many(vec![]));
285    }
286
287    #[test]
288    fn test_display() {
289        let val = 34;
290        let v = OneOrMany::One(val);
291        assert_eq!(v.to_string(), "34");
292
293        let val = vec![1, 2, 3];
294        let v = OneOrMany::Many(val);
295        assert_eq!(v.to_string(), "1, 2, 3");
296    }
297}