use std::collections::HashSet;
use gui::Id;
use gui::Mergeable;
pub use termion::event::Key;
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Ids<T = Id> {
One(T),
Two(T, T),
Three(T, T, T),
Any(Vec<T>),
}
impl<T> Ids<T>
where
T: Clone,
{
pub fn merge_with(self, other: Self) -> Self {
match (self, other) {
(Ids::One(a), Ids::One(b)) => Ids::Two(a, b),
(Ids::One(a), Ids::Two(b, c)) => Ids::Three(a, b, c),
(Ids::One(a), Ids::Three(b, c, d)) => Ids::Any(vec![a, b, c, d]),
(Ids::One(a), Ids::Any(mut b)) => {
let () = b.extend_from_slice(&[a]);
Ids::Any(b)
},
(Ids::Two(a, b), Ids::One(c)) => Ids::Three(a, b, c),
(Ids::Two(a, b), Ids::Two(c, d)) => Ids::Any(vec![a, b, c, d]),
(Ids::Two(a, b), Ids::Three(c, d, e)) => Ids::Any(vec![a, b, c, d, e]),
(Ids::Two(a, b), Ids::Any(mut c)) => {
let () = c.extend_from_slice(&[a, b]);
Ids::Any(c)
},
(Ids::Three(a, b, c), Ids::One(d)) => Ids::Any(vec![a, b, c, d]),
(Ids::Three(a, b, c), Ids::Two(d, e)) => Ids::Any(vec![a, b, c, d, e]),
(Ids::Three(a, b, c), Ids::Three(d, e, f)) => Ids::Any(vec![a, b, c, d, e, f]),
(Ids::Three(a, b, c), Ids::Any(mut d)) => {
let () = d.extend_from_slice(&[a, b, c]);
Ids::Any(d)
},
(Ids::Any(mut a), Ids::One(b)) => {
let () = a.extend_from_slice(&[b]);
Ids::Any(a)
},
(Ids::Any(mut a), Ids::Two(b, c)) => {
let () = a.extend_from_slice(&[b, c]);
Ids::Any(a)
},
(Ids::Any(mut a), Ids::Three(b, c, d)) => {
let () = a.extend_from_slice(&[b, c, d]);
Ids::Any(a)
},
(Ids::Any(mut a), Ids::Any(mut b)) => {
let () = a.append(&mut b);
Ids::Any(a)
},
}
}
}
impl From<Ids> for HashSet<Id> {
fn from(other: Ids) -> Self {
match other {
Ids::One(a) => HashSet::from([a]),
Ids::Two(a, b) => HashSet::from([a, b]),
Ids::Three(a, b, c) => HashSet::from([a, b, c]),
Ids::Any(ids) => HashSet::from_iter(ids),
}
}
}
#[derive(Clone, Debug)]
pub enum Event {
Updated(Ids),
Quit,
#[cfg(not(feature = "readline"))]
Key(Key, ()),
#[cfg(feature = "readline")]
Key(Key, Vec<u8>),
}
impl Event {
#[inline]
pub fn updated(id: Id) -> Self {
Self::Updated(Ids::One(id))
}
#[cfg(all(test, not(feature = "readline")))]
pub fn is_updated(&self) -> bool {
matches!(self, Self::Updated(..))
}
}
impl From<u8> for Event {
fn from(b: u8) -> Self {
#[cfg(not(feature = "readline"))]
{
Event::Key(Key::Char(char::from(b)), ())
}
#[cfg(feature = "readline")]
{
Event::Key(Key::Char(char::from(b)), vec![b])
}
}
}
impl Mergeable for Event {
fn merge_with(self, other: Self) -> Self {
match (self, other) {
(event @ Self::Key(..), _) | (_, event @ Self::Key(..)) => {
panic!("Attempting to merge incompatible event: {event:?}")
},
(Self::Updated(ids1), Self::Updated(ids2)) => Self::Updated(ids1.merge_with(ids2)),
(Self::Quit, _) | (_, Self::Quit) => Self::Quit,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ids_merging() {
let one1 = Ids::One(1);
let one2 = Ids::One(2);
let two = one1.merge_with(one2);
assert_eq!(two, Ids::Two(1, 2));
let three = two.merge_with(Ids::One(3));
assert_eq!(three, Ids::Three(1, 2, 3));
let any = three.merge_with(Ids::One(4));
assert_eq!(any, Ids::Any(vec![1, 2, 3, 4]));
}
}