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 crate::{AnyRef, ContextSpanned};
6use std::fmt::{self, Display, Formatter};
7use std::{slice, vec};
8
9/// Represents either a single value, or multiple values of T.
10/// Useful for differentiating between an array of length 1 and a single value.
11#[derive(Debug, Clone, Ord, PartialOrd, Eq)]
12pub enum OneOrMany<T> {
13    /// A single instance of T.
14    One(T),
15    /// One or more instances of T.
16    Many(Vec<T>),
17}
18
19impl<T> OneOrMany<T> {
20    /// Returns `true` if this `OneOrMany<T>` is a `Many` value.
21    pub fn is_many(&self) -> bool {
22        match self {
23            Self::One(_) => false,
24            Self::Many(_) => true,
25        }
26    }
27
28    /// Returns an [`Iter`] over the values of `OneOrMany<T>`.
29    pub fn iter(&self) -> Iter<'_, T> {
30        match self {
31            Self::One(item) => Iter { inner_one: Some(item), inner_many: None },
32            Self::Many(items) => Iter { inner_one: None, inner_many: Some(items.iter()) },
33        }
34    }
35
36    /// Returns the number of values in this `OneOrMany<T>`.
37    pub fn len(&self) -> usize {
38        match self {
39            Self::One(_) => 1,
40            Self::Many(v) => v.len(),
41        }
42    }
43
44    /// Returns a `OneOrMany<&T>` that references this `OneOrMany<T>`.
45    pub fn as_ref<S>(&self) -> OneOrMany<&S>
46    where
47        T: AsRef<S>,
48        S: ?Sized,
49    {
50        match self {
51            Self::One(o) => OneOrMany::<&S>::One(o.as_ref()),
52            Self::Many(v) => OneOrMany::<&S>::Many(v.iter().map(|o| o.as_ref()).collect()),
53        }
54    }
55}
56
57impl<T> OneOrMany<T>
58where
59    T: Ord + Clone,
60{
61    /// Canonicalizes self by:
62    /// * Transforming to ::One() if is_many() but len() == 1
63    /// * Sorting items if is_many()
64    pub fn canonicalize(&mut self) {
65        let mut replace_with = None;
66        match self {
67            OneOrMany::One(_) => {}
68            OneOrMany::Many(many) => {
69                if many.len() == 1 {
70                    replace_with = Some(many.first().unwrap().clone());
71                } else {
72                    many.sort();
73                }
74            }
75        }
76        if let Some(t) = replace_with {
77            *self = OneOrMany::One(t);
78        }
79    }
80}
81
82impl<T> OneOrMany<T>
83where
84    T: Ord + Clone,
85{
86    /// Canonicalizes self by:
87    /// * Transforming to ::One() if is_many() but len() == 1
88    /// * Sorting items if is_many()
89    pub fn canonicalize_context(&mut self) {
90        let mut replace_with = None;
91        match self {
92            OneOrMany::One(_) => {}
93            OneOrMany::Many(many) => {
94                if many.len() == 1 {
95                    replace_with = Some(many.first().unwrap().clone());
96                } else {
97                    many.sort();
98                }
99            }
100        }
101        if let Some(t) = replace_with {
102            *self = OneOrMany::One(t);
103        }
104    }
105}
106
107impl<T> OneOrMany<T>
108where
109    T: PartialEq,
110{
111    /// Returns true if this `OneOrMany<T>` contains the given element.
112    pub fn contains(&self, e: &T) -> bool {
113        match self {
114            Self::One(item) => item == e,
115            Self::Many(items) => items.contains(e),
116        }
117    }
118}
119
120impl<T> PartialEq for OneOrMany<T>
121where
122    T: PartialEq,
123{
124    fn eq(&self, other: &Self) -> bool {
125        self.iter().eq(other.into_iter())
126    }
127}
128
129impl<'a, T> IntoIterator for &'a OneOrMany<T> {
130    type Item = &'a T;
131    type IntoIter = Iter<'a, T>;
132
133    fn into_iter(self) -> Iter<'a, T> {
134        self.iter()
135    }
136}
137
138impl<T> IntoIterator for OneOrMany<T> {
139    type Item = T;
140    type IntoIter = IntoIter<T>;
141
142    fn into_iter(self) -> IntoIter<T> {
143        match self {
144            OneOrMany::One(item) => IntoIter { inner_one: Some(item), inner_many: None },
145            OneOrMany::Many(items) => {
146                IntoIter { inner_one: None, inner_many: Some(items.into_iter()) }
147            }
148        }
149    }
150}
151
152impl<T> FromIterator<T> for OneOrMany<T> {
153    fn from_iter<I>(iter: I) -> Self
154    where
155        I: IntoIterator<Item = T> + Sized,
156    {
157        let mut iter = iter.into_iter();
158        if let Some(first) = iter.next() {
159            let rest: Vec<_> = iter.collect();
160            if rest.is_empty() {
161                Self::One(first)
162            } else {
163                let mut out = vec![first];
164                out.extend(rest);
165                Self::Many(out)
166            }
167        } else {
168            Self::Many(vec![])
169        }
170    }
171}
172
173impl<T> From<T> for OneOrMany<T> {
174    fn from(item: T) -> Self {
175        Self::One(item)
176    }
177}
178
179impl<'a, T: Display> Display for OneOrMany<T> {
180    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
181        match self {
182            OneOrMany::One(item) => Display::fmt(item, f),
183            OneOrMany::Many(items) => {
184                let mut iter = items.iter();
185                if let Some(first_item) = iter.next() {
186                    Display::fmt(first_item, f)?;
187                }
188                for item in iter {
189                    f.write_str(", ")?;
190                    Display::fmt(item, f)?;
191                }
192                Ok(())
193            }
194        }
195    }
196}
197
198/// Immutable iterator over a `OneOrMany`.
199/// This `struct` is created by [`OneOrMany::iter`].
200///
201/// [`OneOrMany::iter`]: struct.OneOrMany.html#method.iter
202pub struct Iter<'a, T> {
203    inner_one: Option<&'a T>,
204    inner_many: Option<slice::Iter<'a, T>>,
205}
206
207impl<'a, T> Iterator for Iter<'a, T> {
208    type Item = &'a T;
209
210    fn next(&mut self) -> Option<Self::Item> {
211        if let Some(item) = self.inner_one.take() {
212            Some(item)
213        } else if let Some(iter) = &mut self.inner_many {
214            iter.next()
215        } else {
216            None
217        }
218    }
219
220    fn size_hint(&self) -> (usize, Option<usize>) {
221        if let Some(_) = self.inner_one {
222            (1, Some(1))
223        } else if let Some(iter) = &self.inner_many {
224            iter.size_hint()
225        } else {
226            (0, Some(0))
227        }
228    }
229}
230
231impl<'a, T> ExactSizeIterator for Iter<'a, T> {}
232
233/// An iterator that moves out of a `OneOrMany`.
234/// This `struct` is created by the `into_iter` method on [`OneOrMany`] (provided by the [`IntoIterator`] trait).
235///
236/// [`OneOrMany`]: struct.OneOrMany.html
237/// [`IntoIterator`]: https://doc.rust-lang.org/std/iter/trait.IntoIterator.html
238pub struct IntoIter<T> {
239    inner_one: Option<T>,
240    inner_many: Option<vec::IntoIter<T>>,
241}
242
243impl<T> Iterator for IntoIter<T> {
244    type Item = T;
245
246    fn next(&mut self) -> Option<Self::Item> {
247        if let Some(item) = self.inner_one.take() {
248            Some(item)
249        } else if let Some(iter) = &mut self.inner_many {
250            iter.next()
251        } else {
252            None
253        }
254    }
255
256    fn size_hint(&self) -> (usize, Option<usize>) {
257        if let Some(_) = self.inner_one {
258            (1, Some(1))
259        } else if let Some(iter) = &self.inner_many {
260            iter.size_hint()
261        } else {
262            (0, Some(0))
263        }
264    }
265}
266
267impl<T> ExactSizeIterator for IntoIter<T> {}
268
269pub(crate) fn always_one<T>(o: Option<OneOrMany<T>>) -> Option<T> {
270    o.map(|o| match o {
271        OneOrMany::One(o) => o,
272        OneOrMany::Many(_) => panic!("many is impossible"),
273    })
274}
275
276pub(crate) fn always_one_context<T>(
277    o: Option<ContextSpanned<OneOrMany<T>>>,
278) -> Option<ContextSpanned<T>> {
279    o.map(|spanned| {
280        let single_val = match spanned.value {
281            OneOrMany::One(val) => val,
282            OneOrMany::Many(_) => panic!("many is impossible"),
283        };
284
285        ContextSpanned { value: single_val, origin: spanned.origin }
286    })
287}
288
289pub(crate) fn option_one_or_many_as_ref<T, S: ?Sized>(
290    o: &Option<OneOrMany<T>>,
291) -> Option<OneOrMany<&S>>
292where
293    T: AsRef<S>,
294{
295    o.as_ref().map(|o| o.as_ref())
296}
297
298pub(crate) fn one_or_many_from_impl<'a, T>(from: &'a OneOrMany<T>) -> OneOrMany<AnyRef<'a>>
299where
300    AnyRef<'a>: From<&'a T>,
301    T: 'a,
302{
303    let r = match from {
304        OneOrMany::One(r) => OneOrMany::One(r.into()),
305        OneOrMany::Many(v) => OneOrMany::Many(v.into_iter().map(|r| r.into()).collect()),
306    };
307    r.into()
308}
309
310pub(crate) fn one_or_many_from_context<'a, T>(
311    from: &'a ContextSpanned<OneOrMany<T>>,
312) -> ContextSpanned<OneOrMany<AnyRef<'a>>>
313where
314    AnyRef<'a>: From<&'a T>,
315    T: 'a,
316{
317    let origin = from.origin.clone();
318
319    let converted_value = match &from.value {
320        OneOrMany::One(r) => OneOrMany::One(r.into()),
321        OneOrMany::Many(v) => {
322            let converted_vec = v.iter().map(|r| r.into()).collect();
323            OneOrMany::Many(converted_vec)
324        }
325    };
326
327    ContextSpanned { value: converted_value, origin }
328}
329
330#[cfg(test)]
331mod tests {
332    use super::*;
333    use assert_matches::assert_matches;
334
335    #[test]
336    fn test_iter_one() {
337        let v = OneOrMany::One(34);
338        let mut iter = v.iter();
339        assert_matches!(iter.next(), Some(&34));
340        assert_matches!(iter.next(), None);
341    }
342
343    #[test]
344    fn test_iter_many() {
345        let v = OneOrMany::Many(vec![1, 2, 3]);
346        let mut iter = v.iter();
347        assert_matches!(iter.next(), Some(&1));
348        assert_matches!(iter.next(), Some(&2));
349        assert_matches!(iter.next(), Some(&3));
350        assert_matches!(iter.next(), None);
351    }
352
353    #[test]
354    fn test_is_many() {
355        let v = OneOrMany::One(34);
356        assert_eq!(v.is_many(), false);
357
358        let v = OneOrMany::Many(vec![1, 2, 3]);
359        assert_eq!(v.is_many(), true);
360    }
361
362    #[test]
363    fn test_from_iter() {
364        let o: OneOrMany<i64> = [34].into_iter().collect();
365        assert_eq!(o, OneOrMany::One(34));
366
367        let o: OneOrMany<i64> = [1, 2, 3].into_iter().collect();
368        assert_eq!(o, OneOrMany::Many(vec![1, 2, 3]));
369
370        let o: OneOrMany<i64> = [].into_iter().collect();
371        assert_eq!(o, OneOrMany::Many(vec![]));
372    }
373
374    #[test]
375    fn test_display() {
376        let val = 34;
377        let v = OneOrMany::One(val);
378        assert_eq!(v.to_string(), "34");
379
380        let val = vec![1, 2, 3];
381        let v = OneOrMany::Many(val);
382        assert_eq!(v.to_string(), "1, 2, 3");
383    }
384}