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