use std::fmt::{self, Display, Formatter};
use std::{slice, vec};
#[derive(Debug, Clone, Ord, PartialOrd, Eq)]
pub enum OneOrMany<T> {
One(T),
Many(Vec<T>),
}
impl<T> OneOrMany<T> {
pub fn is_many(&self) -> bool {
match self {
Self::One(_) => false,
Self::Many(_) => true,
}
}
pub fn iter(&self) -> Iter<'_, T> {
match self {
Self::One(item) => Iter { inner_one: Some(item), inner_many: None },
Self::Many(items) => Iter { inner_one: None, inner_many: Some(items.iter()) },
}
}
pub fn len(&self) -> usize {
match self {
Self::One(_) => 1,
Self::Many(v) => v.len(),
}
}
pub fn as_ref(&self) -> OneOrMany<&T> {
match self {
Self::One(o) => OneOrMany::<&T>::One(o),
Self::Many(v) => OneOrMany::<&T>::Many(v.iter().collect()),
}
}
}
impl<T> OneOrMany<T>
where
T: Ord + Clone,
{
pub fn canonicalize(&mut self) {
let mut replace_with = None;
match self {
OneOrMany::One(_) => {}
OneOrMany::Many(many) => {
if many.len() == 1 {
replace_with = Some(many.first().unwrap().clone());
} else {
many.sort();
}
}
}
if let Some(t) = replace_with {
*self = OneOrMany::One(t);
}
}
}
impl<T> OneOrMany<T>
where
T: PartialEq,
{
pub fn contains(&self, e: &T) -> bool {
match self {
Self::One(item) => item == e,
Self::Many(items) => items.contains(e),
}
}
}
impl<T> PartialEq for OneOrMany<T>
where
T: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.iter().eq(other.into_iter())
}
}
impl<'a, T> IntoIterator for &'a OneOrMany<T> {
type Item = &'a T;
type IntoIter = Iter<'a, T>;
fn into_iter(self) -> Iter<'a, T> {
self.iter()
}
}
impl<T> IntoIterator for OneOrMany<T> {
type Item = T;
type IntoIter = IntoIter<T>;
fn into_iter(self) -> IntoIter<T> {
match self {
OneOrMany::One(item) => IntoIter { inner_one: Some(item), inner_many: None },
OneOrMany::Many(items) => {
IntoIter { inner_one: None, inner_many: Some(items.into_iter()) }
}
}
}
}
impl<T> FromIterator<T> for OneOrMany<T> {
fn from_iter<I>(iter: I) -> Self
where
I: IntoIterator<Item = T> + Sized,
{
let mut iter = iter.into_iter();
if let Some(first) = iter.next() {
let rest: Vec<_> = iter.collect();
if rest.is_empty() {
Self::One(first)
} else {
let mut out = vec![first];
out.extend(rest);
Self::Many(out)
}
} else {
Self::Many(vec![])
}
}
}
impl<T> From<T> for OneOrMany<T> {
fn from(item: T) -> Self {
Self::One(item)
}
}
impl<'a, T: Display> Display for OneOrMany<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
OneOrMany::One(item) => Display::fmt(item, f),
OneOrMany::Many(items) => {
let mut iter = items.iter();
if let Some(first_item) = iter.next() {
Display::fmt(first_item, f)?;
}
for item in iter {
f.write_str(", ")?;
Display::fmt(item, f)?;
}
Ok(())
}
}
}
}
pub struct Iter<'a, T> {
inner_one: Option<&'a T>,
inner_many: Option<slice::Iter<'a, T>>,
}
impl<'a, T> Iterator for Iter<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
if let Some(item) = self.inner_one.take() {
Some(item)
} else if let Some(ref mut iter) = &mut self.inner_many {
iter.next()
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
if let Some(_) = self.inner_one {
(1, Some(1))
} else if let Some(iter) = &self.inner_many {
iter.size_hint()
} else {
(0, Some(0))
}
}
}
impl<'a, T> ExactSizeIterator for Iter<'a, T> {}
pub struct IntoIter<T> {
inner_one: Option<T>,
inner_many: Option<vec::IntoIter<T>>,
}
impl<T> Iterator for IntoIter<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
if let Some(item) = self.inner_one.take() {
Some(item)
} else if let Some(ref mut iter) = &mut self.inner_many {
iter.next()
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
if let Some(_) = self.inner_one {
(1, Some(1))
} else if let Some(iter) = &self.inner_many {
iter.size_hint()
} else {
(0, Some(0))
}
}
}
impl<T> ExactSizeIterator for IntoIter<T> {}
#[cfg(test)]
mod tests {
use super::*;
use assert_matches::assert_matches;
#[test]
fn test_iter_one() {
let v = OneOrMany::One(34);
let mut iter = v.iter();
assert_matches!(iter.next(), Some(&34));
assert_matches!(iter.next(), None);
}
#[test]
fn test_iter_many() {
let v = OneOrMany::Many(vec![1, 2, 3]);
let mut iter = v.iter();
assert_matches!(iter.next(), Some(&1));
assert_matches!(iter.next(), Some(&2));
assert_matches!(iter.next(), Some(&3));
assert_matches!(iter.next(), None);
}
#[test]
fn test_is_many() {
let v = OneOrMany::One(34);
assert_eq!(v.is_many(), false);
let v = OneOrMany::Many(vec![1, 2, 3]);
assert_eq!(v.is_many(), true);
}
#[test]
fn test_from_iter() {
let o: OneOrMany<i64> = [34].into_iter().collect();
assert_eq!(o, OneOrMany::One(34));
let o: OneOrMany<i64> = [1, 2, 3].into_iter().collect();
assert_eq!(o, OneOrMany::Many(vec![1, 2, 3]));
let o: OneOrMany<i64> = [].into_iter().collect();
assert_eq!(o, OneOrMany::Many(vec![]));
}
#[test]
fn test_display() {
let val = 34;
let v = OneOrMany::One(val);
assert_eq!(v.to_string(), "34");
let val = vec![1, 2, 3];
let v = OneOrMany::Many(val);
assert_eq!(v.to_string(), "1, 2, 3");
}
}