You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
leanify-many/src/maybe_single.rs

121 lines
2.2 KiB

//! A one-or-more iterator type
use std::{
iter::{self, Once,FromIterator,Extend},
};
pub enum IntoIter<T>
{
Many(std::vec::IntoIter<T>),
Single(Once<T>),
}
/// A type that might hold once or more values
pub enum MaybeSingle<T> {
Single(Option<T>),
Many(Vec<T>),
}
impl<T> Extend<T> for MaybeSingle<T>
{
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I)
{
match self {
Self::Single(single) => {
*self = Self::Many(iter::once(single.take().unwrap()).chain(iter).collect());
},
Self::Many(ref mut many) => {
many.extend(iter);
},
}
}
}
impl<T> MaybeSingle<T> {
pub fn is_single(&self) -> bool
{
if let Self::Single(_) = &self {
true
} else {
false
}
}
pub fn push(&mut self, value: T)
{
match self {
Self::Single(single) => {
let first = single.take().unwrap();
*self = Self::Many(vec![first, value]);
},
Self::Many(ref mut many) => {
many.push(value);
}
}
}
pub const fn single(from: T) -> Self
{
Self::Single(Some(from))
}
}
impl<T> FromIterator<T> for MaybeSingle<T>
{
fn from_iter<I: IntoIterator<Item=T>>(iter: I) -> Self
{
let iter = iter.into_iter();
let mut vec = match iter.size_hint() {
(0, None) => Vec::new(),
(_, Some(value)) | (value, None) => Vec::with_capacity(value),
};
vec.extend(iter);
Self::Many(vec)
}
}
impl<T> ExactSizeIterator for IntoIter<T>{}
impl<T> From<Vec<T>> for MaybeSingle<T>
{
fn from(from: Vec<T>) -> Self
{
Self::Many(from)
}
}
impl<T> IntoIterator for MaybeSingle<T>
{
type Item = T;
type IntoIter = IntoIter<T>;
fn into_iter(self) -> Self::IntoIter
{
match self {
Self::Single(Some(single)) => IntoIter::Single(iter::once(single)),
Self::Many(many) => IntoIter::Many(many.into_iter()),
_ => panic!("Invalid state"),
}
}
}
impl<T> Iterator for IntoIter<T>
{
type Item = T;
fn next(&mut self) -> Option<Self::Item>
{
match self {
Self::Many(ref mut many) => many.next(),
Self::Single(ref mut once) => once.next(),
}
}
fn size_hint(&self) -> (usize, Option<usize>)
{
match self {
Self::Many(many) => many.size_hint(),
Self::Single(_) => (0, Some(1)),
}
}
}