use quickcheck::{Arbitrary, Gen};
use std::fmt::{Debug, Display, Formatter};
use std::hash::Hash;
use std::iter::FromIterator;
use smallvec::SmallVec;
use crate::datatypes::error::ChoiceError;
use crate::prelude::traits::*;
#[repr(transparent)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Choice<T> {
values: SmallVec<[T; 8]>,
}
impl<T> Choice<T> {
#[inline]
pub fn new_empty() -> Self {
Self {
values: SmallVec::new(),
}
}
#[inline]
pub fn new<I>(item: T, alternatives: I) -> Self
where
I: IntoIterator<Item = T>,
I::IntoIter: Iterator,
{
let alternatives_iter = alternatives.into_iter();
let (lower, upper) = alternatives_iter.size_hint();
let capacity = match upper {
Some(exact) if exact == lower => exact + 1, Some(upper_bound) if upper_bound <= 8 => upper_bound + 1, _ => std::cmp::max(lower + 1, 8), };
let mut values = SmallVec::<[T; 8]>::with_capacity(capacity);
values.push(item);
values.extend(alternatives_iter);
Self { values }
}
#[inline]
pub fn first(&self) -> Option<&T> {
self.values.first()
}
#[inline]
pub fn alternatives(&self) -> &[T] {
if self.values.len() <= 1 {
&[]
} else {
&self.values[1..]
}
}
#[inline]
pub fn len(&self) -> usize {
self.values.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.values.is_empty()
}
#[inline]
pub fn remove_alternative(self, index: usize) -> Self
where
T: Clone,
{
if self.values.len() <= 1 {
panic!("Cannot remove alternative from Choice with no alternatives");
}
if index >= self.alternatives().len() {
panic!(
"Index out of bounds: the len is {} but the index is {}",
self.alternatives().len(),
index
);
}
let mut new_values = self.values;
new_values.remove(index + 1); Self { values: new_values }
}
pub fn flatten<I>(&self) -> Choice<I>
where
T: IntoIterator<Item = I> + Clone,
I: Clone,
{
if self.values.is_empty() {
return Choice::new_empty();
}
let primary = self.first().unwrap().clone();
let mut primary_iter = primary.into_iter();
match primary_iter.next() {
Some(first_item) => {
let alternatives = primary_iter
.chain(
self.values
.iter()
.skip(1) .flat_map(|val| val.clone().into_iter()),
)
.collect::<SmallVec<[I; 8]>>();
Choice::new(first_item, alternatives)
},
None => panic!("Primary value was an empty iterator in Choice::flatten"),
}
}
#[inline]
pub fn of_many<I>(many: I) -> Self
where
I: IntoIterator<Item = T>,
T: Clone,
{
let values: SmallVec<[T; 8]> = many.into_iter().collect();
if values.is_empty() {
Self::new_empty()
} else {
Self { values }
}
}
#[inline]
pub fn filter_values<F>(&self, predicate: F) -> Self
where
T: Clone,
F: Fn(&T) -> bool,
{
let filtered: SmallVec<[T; 8]> = self
.values
.iter()
.filter(|v| predicate(v))
.cloned()
.collect();
match filtered.len() {
0 => Self::new_empty(),
_ => Self { values: filtered },
}
}
#[inline]
pub fn iter(&self) -> impl Iterator<Item = &T> {
self.values.iter()
}
#[inline]
pub fn iter_alternatives(&self) -> impl Iterator<Item = &T> {
self.values.iter().skip(1)
}
fn generate_apply_alternatives<A, B>(
func_values: &SmallVec<[T; 8]>, val_values: &SmallVec<[A; 8]>,
) -> SmallVec<[B; 8]>
where
T: Fn(A) -> B,
A: Clone,
{
val_values
.iter()
.enumerate()
.flat_map(|(i, val)| {
func_values.iter().enumerate().filter_map(move |(j, func)| {
if i == 0 && j == 0 {
None
} else {
Some(func(val.clone()))
}
})
})
.collect()
}
#[inline]
pub fn try_first(&self) -> Result<&T, ChoiceError> {
self.first().ok_or(ChoiceError::EmptyChoice)
}
pub fn try_remove_alternative(self, index: usize) -> Result<Self, ChoiceError>
where
T: Clone,
{
if self.values.len() <= 1 {
return Err(ChoiceError::NoAlternatives);
}
let alt_len = self.alternatives().len();
if index >= alt_len {
return Err(ChoiceError::index_out_of_bounds(index, alt_len));
}
let mut new_values = self.values;
new_values.remove(index + 1);
Ok(Self { values: new_values })
}
pub fn try_flatten<I>(&self) -> Result<Choice<I>, ChoiceError>
where
T: IntoIterator<Item = I> + Clone,
I: Clone,
{
if self.values.is_empty() {
return Ok(Choice::new_empty());
}
let primary = self.first().unwrap().clone();
let mut primary_iter = primary.into_iter();
match primary_iter.next() {
Some(first_item) => {
let alternatives = primary_iter
.chain(
self.values
.iter()
.skip(1)
.flat_map(|val| val.clone().into_iter()),
)
.collect::<SmallVec<[I; 8]>>();
Ok(Choice::new(first_item, alternatives))
},
None => Err(ChoiceError::EmptyPrimaryIterator),
}
}
pub fn try_swap_with_alternative(self, alt_index: usize) -> Result<Self, ChoiceError>
where
T: Clone,
{
if self.values.len() <= 1 {
return Err(ChoiceError::NoAlternatives);
}
let alt_len = self.alternatives().len();
if alt_index >= alt_len {
return Err(ChoiceError::index_out_of_bounds(alt_index, alt_len));
}
let actual_alt_index = alt_index + 1;
let mut new_values = self.values;
new_values.swap(0, actual_alt_index);
Ok(Self { values: new_values })
}
}
impl<T> HKT for Choice<T> {
type Source = T;
type Output<U> = Choice<U>;
}
impl<T> Pure for Choice<T> {
fn pure<A: Clone>(value: &A) -> Self::Output<A> {
Choice::from_iter([value.clone()])
}
fn pure_owned<A: Clone>(value: A) -> Self::Output<A> {
Choice::from_iter([value])
}
}
impl<T: Clone> Functor for Choice<T> {
#[inline]
fn fmap<B, F>(&self, f: F) -> Self::Output<B>
where
F: Fn(&T) -> B,
B: Clone,
{
if self.values.is_empty() {
return Choice::new_empty();
}
let values = &self.values;
let primary = f(&values[0]);
let alternatives: SmallVec<[B; 8]> = values[1..].iter().map(f).collect();
Choice::new(primary, alternatives)
}
fn fmap_owned<B, F>(self, f: F) -> Self::Output<B>
where
F: FnMut(T) -> B,
{
if self.values.is_empty() {
return Choice::new_empty();
}
let mut values = self.values;
let mut f = f;
let primary = f(values.remove(0));
let alternatives: SmallVec<[B; 8]> = values.into_iter().map(f).collect();
Choice::new(primary, alternatives)
}
}
impl<T: Clone> Monad for Choice<T> {
#[inline]
fn bind<U, F>(&self, f: F) -> Self::Output<U>
where
F: Fn(&T) -> Self::Output<U>,
U: Clone,
{
if self.values.is_empty() {
return Choice::new_empty();
}
let self_values = &self.values;
let first_choice = f(&self_values[0]);
if first_choice.values.is_empty() {
return Choice::new_empty();
}
let first_choice_values = &first_choice.values;
let first = first_choice_values[0].clone();
let mut alternatives =
Vec::with_capacity(first_choice_values.len() - 1 + self_values.len() - 1);
alternatives.extend_from_slice(&first_choice_values[1..]);
for alt in &self_values[1..] {
let alt_choice = f(alt);
alternatives.extend_from_slice(alt_choice.values.as_ref());
}
Choice::new(first, alternatives)
}
fn bind_owned<U, F>(self, mut f: F) -> Self::Output<U>
where
F: FnMut(Self::Source) -> Self::Output<U>,
U: Clone,
{
if self.values.is_empty() {
return Choice::new_empty();
}
let mut values = self.values;
let primary_choice = f(values.remove(0));
if primary_choice.values.is_empty() {
return Choice::new_empty();
}
let primary_choice_values = &primary_choice.values;
let first = primary_choice_values[0].clone();
let mut alternatives = Vec::with_capacity(primary_choice_values.len() - 1 + values.len());
alternatives.extend_from_slice(&primary_choice_values[1..]);
for alt in values {
let alt_choice = f(alt);
alternatives.extend(alt_choice.values);
}
Choice::new(first, alternatives)
}
#[inline]
fn join<U>(&self) -> Self::Output<U>
where
T: Into<Self::Output<U>> + Clone,
U: Clone,
{
if self.values.is_empty() {
return Choice::new_empty();
}
let primary_value = self.first().unwrap().clone();
let primary_choice: Self::Output<U> = primary_value.into();
if primary_choice.values.is_empty() {
return Choice::new_empty();
}
let first = primary_choice.first().unwrap().clone();
let mut alternatives =
Vec::with_capacity(primary_choice.alternatives().len() + self.alternatives().len());
alternatives.extend_from_slice(primary_choice.alternatives());
for alt in self.alternatives() {
let alt_choice: Self::Output<U> = alt.clone().into();
alternatives.extend_from_slice(alt_choice.values.as_ref());
}
Choice::new(first, alternatives)
}
#[inline]
fn join_owned<U>(self) -> Self::Output<U>
where
T: Into<Self::Output<U>> + Clone,
U: Clone,
{
if self.values.is_empty() {
return Choice::new_empty();
}
let mut values = self.values;
let primary_value = values.remove(0);
let primary_choice: Self::Output<U> = primary_value.into();
if primary_choice.values.is_empty() {
return Choice::new_empty();
}
let first = primary_choice.first().unwrap().clone();
let mut alternatives =
Vec::with_capacity(primary_choice.alternatives().len() + values.len());
alternatives.extend_from_slice(primary_choice.alternatives());
for alt in values {
let alt_choice: Self::Output<U> = alt.into();
alternatives.extend_from_slice(&alt_choice.values);
}
Choice::new(first, alternatives)
}
}
impl<T: Clone> Semigroup for Choice<T> {
fn combine(&self, other: &Self) -> Self {
if self.values.is_empty() {
return other.clone();
}
if other.values.is_empty() {
return self.clone();
}
let self_values = &self.values;
let other_values = &other.values;
let primary = self_values[0].clone();
Choice::new(
primary,
self_values[1..]
.iter()
.cloned()
.chain(other_values.iter().cloned()),
)
}
fn combine_owned(self, other: Self) -> Self {
if self.values.is_empty() {
return other;
}
if other.values.is_empty() {
return self;
}
let mut self_values = self.values;
let primary = self_values.remove(0);
Choice::new(primary, self_values.into_iter().chain(other.values))
}
}
impl<T: Clone> Monoid for Choice<T> {
fn empty() -> Self {
Self::new_empty()
}
}
impl<T: Clone> Applicative for Choice<T> {
#[inline]
fn apply<A, B>(&self, value: &Self::Output<A>) -> Self::Output<B>
where
Self::Source: Fn(&A) -> B,
B: Clone,
{
if self.values.is_empty() || value.values.is_empty() {
return Choice::new_empty();
}
let func_values = &self.values;
let val_values = &value.values;
let func_first = &func_values[0];
let primary = func_first(&val_values[0]);
let alternatives: SmallVec<[B; 8]> = func_values[1..]
.iter()
.map(|f_alt| f_alt(&val_values[0]))
.chain(val_values[1..].iter().flat_map(|val_alt| {
std::iter::once(func_first(val_alt))
.chain(func_values[1..].iter().map(move |f_alt| f_alt(val_alt)))
}))
.collect();
Choice::new(primary, alternatives)
}
fn apply_owned<A, B>(self, value: Self::Output<A>) -> Self::Output<B>
where
Self::Source: Fn(A) -> B,
A: Clone,
{
if self.values.is_empty() || value.values.is_empty() {
return Choice::new_empty();
}
let func_values = self.values;
let val_values = value.values;
let primary = func_values[0](val_values[0].clone());
let alternatives = Self::generate_apply_alternatives(&func_values, &val_values);
Choice::new(primary, alternatives)
}
fn lift2<A, B, C, F>(f: F, fa: &Self::Output<A>, fb: &Self::Output<B>) -> Self::Output<C>
where
F: Fn(&A, &B) -> C,
A: Clone,
B: Clone,
C: Clone,
Self: Sized,
{
if fa.values.is_empty() || fb.values.is_empty() {
return Choice::new_empty();
}
let fa_values = fa.values.as_ref();
let fb_values = fb.values.as_ref();
let primary = f(&fa_values[0], &fb_values[0]);
let capacity = fa_values.len() * fb_values.len() - 1;
let mut alternatives = SmallVec::<[C; 8]>::with_capacity(capacity);
for (i, fa_val) in fa_values.iter().enumerate() {
for (j, fb_val) in fb_values.iter().enumerate() {
if i == 0 && j == 0 {
continue; }
alternatives.push(f(fa_val, fb_val));
}
}
Choice::new(primary, alternatives)
}
fn lift2_owned<A, B, C, F>(f: F, fa: Self::Output<A>, fb: Self::Output<B>) -> Self::Output<C>
where
F: Fn(A, B) -> C,
A: Clone,
B: Clone,
C: Clone,
Self: Sized,
{
if fa.values.is_empty() || fb.values.is_empty() {
return Choice::new_empty();
}
let primary = f(fa.values[0].clone(), fb.values[0].clone());
let capacity = fa.len() * fb.len() - 1;
let mut alternatives = Vec::with_capacity(capacity);
for (i, a) in fa.values.iter().enumerate() {
for (j, b_val) in fb.values.iter().enumerate() {
if i == 0 && j == 0 {
continue; }
alternatives.push(f(a.clone(), b_val.clone()));
}
}
Choice::new(primary, alternatives)
}
fn lift3<A, B, C, D, F>(
f: F, fa: &Self::Output<A>, fb: &Self::Output<B>, fc: &Self::Output<C>,
) -> Self::Output<D>
where
F: Fn(&A, &B, &C) -> D,
A: Clone,
B: Clone,
C: Clone,
D: Clone,
Self: Sized,
{
if fa.values.is_empty() || fb.values.is_empty() || fc.values.is_empty() {
return Choice::new_empty();
}
let fa_values = &fa.values;
let fb_values = &fb.values;
let fc_values = &fc.values;
let primary = f(&fa_values[0], &fb_values[0], &fc_values[0]);
let capacity = fa_values.len() * fb_values.len() * fc_values.len() - 1;
let mut alternatives = SmallVec::<[D; 8]>::with_capacity(capacity);
for (i, fa_val) in fa_values.iter().enumerate() {
for (j, fb_val) in fb_values.iter().enumerate() {
for (k, fc_val) in fc_values.iter().enumerate() {
if i == 0 && j == 0 && k == 0 {
continue; }
alternatives.push(f(fa_val, fb_val, fc_val));
}
}
}
Choice::new(primary, alternatives)
}
fn lift3_owned<A, B, C, D, F>(
f: F, fa: Self::Output<A>, fb: Self::Output<B>, fc: Self::Output<C>,
) -> Self::Output<D>
where
F: Fn(A, B, C) -> D,
A: Clone,
B: Clone,
C: Clone,
D: Clone,
Self: Sized,
{
if fa.values.is_empty() || fb.values.is_empty() || fc.values.is_empty() {
return Choice::new_empty();
}
let primary = f(
fa.values[0].clone(),
fb.values[0].clone(),
fc.values[0].clone(),
);
let capacity = fa.len() * fb.len() * fc.len() - 1;
let mut alternatives = SmallVec::<[D; 8]>::with_capacity(capacity);
for (i, a) in fa.values.iter().enumerate() {
for (j, b_val) in fb.values.iter().enumerate() {
for (k, c_val) in fc.values.iter().enumerate() {
if i == 0 && j == 0 && k == 0 {
continue; }
alternatives.push(f(a.clone(), b_val.clone(), c_val.clone()));
}
}
}
Choice::new(primary, alternatives)
}
}
impl<T: Clone> Alternative for Choice<T> {
fn alt(&self, other: &Self) -> Self
where
Self: Sized + Clone,
{
if self.values.is_empty() {
return other.clone();
}
if other.values.is_empty() {
return self.clone();
}
let primary = self.values[0].clone();
Choice::new(
primary,
self.values[1..]
.iter()
.cloned()
.chain(other.values.iter().cloned()),
)
}
fn empty_alt<B>() -> Self::Output<B> {
Choice::new_empty()
}
fn guard(condition: bool) -> Self::Output<()> {
if condition {
Self::pure(&())
} else {
Self::empty_alt()
}
}
fn many(&self) -> Self::Output<Vec<Self::Source>>
where
Self::Source: Clone,
{
if self.is_empty() {
Choice::new_empty()
} else {
let primary = vec![self.first().unwrap().clone()];
Choice::new(primary, vec![])
}
}
}
impl<T: Clone> Choice<Option<T>> {
pub fn sequence(self) -> Option<Choice<T>> {
let sequenced_values: Option<SmallVec<[T; 8]>> = self.values.iter().cloned().collect();
sequenced_values.map(|values| Choice { values })
}
}
impl<'a, T> IntoIterator for &'a Choice<T> {
type Item = &'a T;
type IntoIter = std::slice::Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.values.iter()
}
}
impl<T: Clone> IntoIterator for Choice<T> {
type Item = T;
type IntoIter = smallvec::IntoIter<[T; 8]>;
fn into_iter(self) -> Self::IntoIter {
self.values.into_iter()
}
}
impl<T: Clone + Display> Display for Choice<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
if let Some(first) = self.first() {
write!(f, "{first}")?;
let alternatives_slice = self.alternatives();
if !alternatives_slice.is_empty() {
let alternatives_str = alternatives_slice
.iter()
.map(|alt| alt.to_string())
.collect::<Vec<_>>()
.join(", ");
write!(f, " | {alternatives_str}")?;
}
Ok(())
} else {
Ok(())
}
}
}
impl<T> Foldable for Choice<T> {
fn fold_left<B, F>(&self, initial: &B, f: F) -> B
where
F: Fn(&B, &Self::Source) -> B,
B: Clone,
{
self.iter()
.fold(initial.clone(), |acc, value| f(&acc, value))
}
fn fold_right<B, F>(&self, initial: &B, f: F) -> B
where
F: Fn(&Self::Source, &B) -> B,
B: Clone,
{
self.values
.iter()
.rev()
.fold(initial.clone(), |acc, value| f(value, &acc))
}
}
impl<T> FromIterator<T> for Choice<T> {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
let collected: SmallVec<[T; 8]> = iter.into_iter().collect();
match collected.len() {
0 => Self::new_empty(),
_ => Self { values: collected },
}
}
}
impl<T: Clone> FromIterator<Choice<T>> for Choice<T> {
fn from_iter<I: IntoIterator<Item = Choice<T>>>(iter: I) -> Self {
let values: SmallVec<[T; 8]> = iter.into_iter().flat_map(|choice| choice.values).collect();
match values.len() {
0 => Self::new_empty(),
_ => Self { values },
}
}
}
impl<T: Clone> From<Vec<T>> for Choice<T> {
fn from(v: Vec<T>) -> Self {
if v.is_empty() {
return Choice::new_empty();
}
let mut iter = v.into_iter();
let primary = iter.next().unwrap();
let alternatives: Vec<T> = iter.collect();
Choice::new(primary, alternatives)
}
}
impl<T: Clone> From<&[T]> for Choice<T> {
fn from(slice: &[T]) -> Self {
if slice.is_empty() {
return Choice::new_empty();
}
let primary = slice[0].clone();
let alternatives: Vec<T> = slice[1..].to_vec();
Choice::new(primary, alternatives)
}
}
impl<T: Clone> From<Choice<T>> for Vec<T> {
fn from(choice: Choice<T>) -> Self {
choice.values.to_vec()
}
}
impl<T: Clone + Default> Default for Choice<T> {
fn default() -> Self {
Self::new_empty()
}
}
impl<T: Clone> std::iter::Sum for Choice<T> {
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.fold(Self::new_empty(), |acc, choice| {
let combined: SmallVec<[T; 8]> = acc.values.into_iter().chain(choice.values).collect();
Choice { values: combined }
})
}
}
impl<T: Arbitrary + 'static> Arbitrary for Choice<T> {
fn arbitrary(g: &mut Gen) -> Self {
let items: Vec<T> = Arbitrary::arbitrary(g);
Choice::of_many(items)
}
}