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: PartialEq,
85{
86    /// Returns true if this `OneOrMany<T>` contains the given element.
87    pub fn contains(&self, e: &T) -> bool {
88        match self {
89            Self::One(item) => item == e,
90            Self::Many(items) => items.contains(e),
91        }
92    }
93}
94
95impl<T> PartialEq for OneOrMany<T>
96where
97    T: PartialEq,
98{
99    fn eq(&self, other: &Self) -> bool {
100        self.iter().eq(other.into_iter())
101    }
102}
103
104impl<'a, T> IntoIterator for &'a OneOrMany<T> {
105    type Item = &'a T;
106    type IntoIter = Iter<'a, T>;
107
108    fn into_iter(self) -> Iter<'a, T> {
109        self.iter()
110    }
111}
112
113impl<T> IntoIterator for OneOrMany<T> {
114    type Item = T;
115    type IntoIter = IntoIter<T>;
116
117    fn into_iter(self) -> IntoIter<T> {
118        match self {
119            OneOrMany::One(item) => IntoIter { inner_one: Some(item), inner_many: None },
120            OneOrMany::Many(items) => {
121                IntoIter { inner_one: None, inner_many: Some(items.into_iter()) }
122            }
123        }
124    }
125}
126
127impl<T> FromIterator<T> for OneOrMany<T> {
128    fn from_iter<I>(iter: I) -> Self
129    where
130        I: IntoIterator<Item = T> + Sized,
131    {
132        let mut iter = iter.into_iter();
133        if let Some(first) = iter.next() {
134            let rest: Vec<_> = iter.collect();
135            if rest.is_empty() {
136                Self::One(first)
137            } else {
138                let mut out = vec![first];
139                out.extend(rest);
140                Self::Many(out)
141            }
142        } else {
143            Self::Many(vec![])
144        }
145    }
146}
147
148impl<T> From<T> for OneOrMany<T> {
149    fn from(item: T) -> Self {
150        Self::One(item)
151    }
152}
153
154impl<'a, T: Display> Display for OneOrMany<T> {
155    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
156        match self {
157            OneOrMany::One(item) => Display::fmt(item, f),
158            OneOrMany::Many(items) => {
159                let mut iter = items.iter();
160                if let Some(first_item) = iter.next() {
161                    Display::fmt(first_item, f)?;
162                }
163                for item in iter {
164                    f.write_str(", ")?;
165                    Display::fmt(item, f)?;
166                }
167                Ok(())
168            }
169        }
170    }
171}
172
173/// Immutable iterator over a `OneOrMany`.
174/// This `struct` is created by [`OneOrMany::iter`].
175///
176/// [`OneOrMany::iter`]: struct.OneOrMany.html#method.iter
177pub struct Iter<'a, T> {
178    inner_one: Option<&'a T>,
179    inner_many: Option<slice::Iter<'a, T>>,
180}
181
182impl<'a, T> Iterator for Iter<'a, T> {
183    type Item = &'a T;
184
185    fn next(&mut self) -> Option<Self::Item> {
186        if let Some(item) = self.inner_one.take() {
187            Some(item)
188        } else if let Some(iter) = &mut self.inner_many {
189            iter.next()
190        } else {
191            None
192        }
193    }
194
195    fn size_hint(&self) -> (usize, Option<usize>) {
196        if let Some(_) = self.inner_one {
197            (1, Some(1))
198        } else if let Some(iter) = &self.inner_many {
199            iter.size_hint()
200        } else {
201            (0, Some(0))
202        }
203    }
204}
205
206impl<'a, T> ExactSizeIterator for Iter<'a, T> {}
207
208/// An iterator that moves out of a `OneOrMany`.
209/// This `struct` is created by the `into_iter` method on [`OneOrMany`] (provided by the [`IntoIterator`] trait).
210///
211/// [`OneOrMany`]: struct.OneOrMany.html
212/// [`IntoIterator`]: https://doc.rust-lang.org/std/iter/trait.IntoIterator.html
213pub struct IntoIter<T> {
214    inner_one: Option<T>,
215    inner_many: Option<vec::IntoIter<T>>,
216}
217
218impl<T> Iterator for IntoIter<T> {
219    type Item = T;
220
221    fn next(&mut self) -> Option<Self::Item> {
222        if let Some(item) = self.inner_one.take() {
223            Some(item)
224        } else if let Some(iter) = &mut self.inner_many {
225            iter.next()
226        } else {
227            None
228        }
229    }
230
231    fn size_hint(&self) -> (usize, Option<usize>) {
232        if let Some(_) = self.inner_one {
233            (1, Some(1))
234        } else if let Some(iter) = &self.inner_many {
235            iter.size_hint()
236        } else {
237            (0, Some(0))
238        }
239    }
240}
241
242impl<T> ExactSizeIterator for IntoIter<T> {}
243
244pub(crate) fn always_one<T>(o: Option<OneOrMany<T>>) -> Option<T> {
245    o.map(|o| match o {
246        OneOrMany::One(o) => o,
247        OneOrMany::Many(_) => panic!("many is impossible"),
248    })
249}
250
251pub(crate) fn option_one_or_many_as_ref<T, S: ?Sized>(
252    o: &Option<OneOrMany<T>>,
253) -> Option<OneOrMany<&S>>
254where
255    T: AsRef<S>,
256{
257    o.as_ref().map(|o| o.as_ref())
258}
259
260pub(crate) fn one_or_many_from_impl<'a, T>(from: &'a OneOrMany<T>) -> OneOrMany<AnyRef<'a>>
261where
262    AnyRef<'a>: From<&'a T>,
263    T: 'a,
264{
265    let r = match from {
266        OneOrMany::One(r) => OneOrMany::One(r.into()),
267        OneOrMany::Many(v) => OneOrMany::Many(v.into_iter().map(|r| r.into()).collect()),
268    };
269    r.into()
270}
271
272pub(crate) fn one_or_many_from_context<'a, T>(
273    from: &'a ContextSpanned<OneOrMany<T>>,
274) -> ContextSpanned<OneOrMany<AnyRef<'a>>>
275where
276    AnyRef<'a>: From<&'a T>,
277    T: 'a,
278{
279    let origin = from.origin.clone();
280
281    let converted_value = match &from.value {
282        OneOrMany::One(r) => OneOrMany::One(r.into()),
283        OneOrMany::Many(v) => {
284            let converted_vec = v.iter().map(|r| r.into()).collect();
285            OneOrMany::Many(converted_vec)
286        }
287    };
288
289    ContextSpanned { value: converted_value, origin }
290}
291
292#[cfg(test)]
293mod tests {
294    use super::*;
295    use assert_matches::assert_matches;
296
297    #[test]
298    fn test_iter_one() {
299        let v = OneOrMany::One(34);
300        let mut iter = v.iter();
301        assert_matches!(iter.next(), Some(&34));
302        assert_matches!(iter.next(), None);
303    }
304
305    #[test]
306    fn test_iter_many() {
307        let v = OneOrMany::Many(vec![1, 2, 3]);
308        let mut iter = v.iter();
309        assert_matches!(iter.next(), Some(&1));
310        assert_matches!(iter.next(), Some(&2));
311        assert_matches!(iter.next(), Some(&3));
312        assert_matches!(iter.next(), None);
313    }
314
315    #[test]
316    fn test_is_many() {
317        let v = OneOrMany::One(34);
318        assert_eq!(v.is_many(), false);
319
320        let v = OneOrMany::Many(vec![1, 2, 3]);
321        assert_eq!(v.is_many(), true);
322    }
323
324    #[test]
325    fn test_from_iter() {
326        let o: OneOrMany<i64> = [34].into_iter().collect();
327        assert_eq!(o, OneOrMany::One(34));
328
329        let o: OneOrMany<i64> = [1, 2, 3].into_iter().collect();
330        assert_eq!(o, OneOrMany::Many(vec![1, 2, 3]));
331
332        let o: OneOrMany<i64> = [].into_iter().collect();
333        assert_eq!(o, OneOrMany::Many(vec![]));
334    }
335
336    #[test]
337    fn test_display() {
338        let val = 34;
339        let v = OneOrMany::One(val);
340        assert_eq!(v.to_string(), "34");
341
342        let val = vec![1, 2, 3];
343        let v = OneOrMany::Many(val);
344        assert_eq!(v.to_string(), "1, 2, 3");
345    }
346}