use std::hash::Hash;
use std::str::FromStr;
use indexmap::IndexSet;
use itertools::Itertools;
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
pub enum TriState<T> {
Set(T),
Add(T),
Remove(T),
}
impl<T: Ord + Clone + Hash> TriState<T> {
pub fn enabled<I>(enabled: &mut IndexSet<T>, selected: I)
where
I: IntoIterator<Item = TriState<T>>,
{
let selected: Vec<_> = selected.into_iter().sorted().collect();
if let Some(TriState::Set(_)) = selected.first() {
std::mem::take(enabled);
}
for x in selected {
match x {
TriState::Set(value) => enabled.insert(value),
TriState::Add(value) => enabled.insert(value),
TriState::Remove(value) => enabled.swap_remove(&value),
};
}
enabled.sort_unstable();
}
}
impl<T: FromStr> FromStr for TriState<T> {
type Err = T::Err;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if let Some(value) = s.strip_prefix('+') {
value.parse().map(Self::Add)
} else if let Some(value) = s.strip_prefix('-') {
value.parse().map(Self::Remove)
} else {
s.parse().map(Self::Set)
}
}
}
#[cfg(test)]
mod tests {
use crate::test::*;
use super::*;
#[test]
fn tri_state() {
let empty: [i32; 0] = [];
let mut enabled = IndexSet::<i32>::new();
let selected = IndexSet::new();
TriState::enabled(&mut enabled, selected);
assert_ordered_eq!(enabled, empty);
let mut enabled: IndexSet<i32> = [1].into_iter().collect();
let selected = IndexSet::new();
TriState::enabled(&mut enabled, selected);
assert_ordered_eq!(enabled, [1]);
let mut enabled: IndexSet<i32> = [1].into_iter().collect();
let selected: IndexSet<_> = ["2"].iter().map(|s| s.parse()).try_collect().unwrap();
TriState::enabled(&mut enabled, selected);
assert_ordered_eq!(enabled, [2]);
let mut enabled: IndexSet<i32> = [1].into_iter().collect();
let selected: IndexSet<_> =
["2", "-2"].iter().map(|s| s.parse()).try_collect().unwrap();
TriState::enabled(&mut enabled, selected);
assert_ordered_eq!(enabled, empty);
let mut enabled: IndexSet<_> = [1].into_iter().collect();
let selected: IndexSet<_> = ["+2"].iter().map(|s| s.parse()).try_collect().unwrap();
TriState::enabled(&mut enabled, selected);
assert_ordered_eq!(enabled, [1, 2]);
}
}