use core::fmt::{Debug, Display}; use std::{collections::{LinkedList, VecDeque}, sync::{Arc, Mutex}}; use rgb::Rgb; #[derive(Debug, Clone, PartialEq, Eq)] pub enum Variant { SignedByte(i8), Byte(u8), UInt(u32), Int(i32), BigUInt(u64), BigInt(i64), Boolean(bool), String(String), RGB(Rgb), Vec(Vec) } macro_rules! impl_variant_type { ($type:ty, $var_type:tt) => { impl From<$type> for Variant { fn from(value: $type) -> Self { Variant::$var_type(value) } } impl Into<$type> for Variant { fn into(self) -> $type { match self { Variant::$var_type(value) => value, _ => panic!(concat!("Expected Variant::", stringify!($var_type), "but got {:?}"), self) } } } }; } impl_variant_type!(u8, Byte); impl_variant_type!(i8, SignedByte); impl_variant_type!(u32, UInt); impl_variant_type!(i32, Int); impl_variant_type!(i64, BigInt); impl_variant_type!(u64, BigUInt); impl_variant_type!(bool, Boolean); impl_variant_type!(String, String); impl_variant_type!(Rgb, RGB); impl_variant_type!(Vec, Vec); impl<'a> From<&'a str> for Variant { fn from(value: &'a str) -> Self { Variant::String(value.to_owned()) } } #[derive(Debug, Clone, PartialEq, Eq)] pub enum Event { ReadyToRock, Tick, StartThing(&'static str), StopThing(&'static str), PropertyChange(&'static str, Variant) } impl Event { pub const fn new_tick() -> Self { Event::Tick } pub fn new_property_change(key: &'static str, data: T) -> Self where Variant: From { Event::PropertyChange(key, Variant::from(data)) } pub const fn new_ready_to_rock() -> Self { Event::ReadyToRock } pub const fn new_start_thing(name: &'static str) -> Self { Event::StartThing(name) } pub const fn new_stop_thing(name: &'static str) -> Self { Event::StopThing(name) } } #[derive(Debug, Clone, PartialEq, Eq)] pub struct Property { key: &'static str, value: Variant } impl Property { pub const fn new(key: &'static str, value: Variant) -> Self { Property { key, value: value } } } #[derive(Debug, Clone)] pub struct Properties { contents: LinkedList } impl Properties { fn new() -> Self { Properties { contents: LinkedList::new() } } fn get_key(&self, key: &'static str) -> Option<&Property> { for next in self.contents.iter() { if next.key == key { return Some(next); } } return None; } fn get_key_mut(&mut self, key: &'static str) -> Option<&mut Property> { for next in self.contents.iter_mut() { if next.key == key { return Some(next); } } return None; } pub fn get(&self, key: &'static str) -> Option { match self.get_key(key) { None => None, Some(v) => Some(v.value.clone()) } } pub fn set(&mut self, key: &'static str, value: V) -> bool where Variant: From { let as_variant: Variant = value.into(); match self.get_key_mut(key) { None => { self.contents.push_front(Property::new(key, as_variant)); return true }, Some(found_key) => { if found_key.value != as_variant { found_key.value = as_variant; return true } } } return false } } #[derive(Clone)] pub struct EventBus { pending: Arc>>, props: Arc> } impl EventBus { pub fn new() -> Self { EventBus { pending: Arc::new(Mutex::new(VecDeque::with_capacity(32))), props: Arc::new(Mutex::new(Properties::new())) } } pub fn next(&mut self) -> Event { let next = self.pending.lock().unwrap().pop_front().unwrap_or(Event::new_tick()); match next { Event::PropertyChange(key, value) => { if self.props.lock().unwrap().set(key, value.clone()) { log::trace!("prop-update key={} value={:?}", key, value); Event::PropertyChange(key, value) } else { Event::new_tick() } }, _ => next } } pub fn push(&mut self, event: Event) { self.pending.lock().unwrap().push_back(event); } pub fn property(&self, key: &'static str) -> Option { self.props.lock().unwrap().get(key) } }