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) } impl From for Variant { fn from(value: u8) -> Self { Variant::Byte(value) } } impl Into for Variant { fn into(self) -> u8 { match self { Variant::Byte(b) => b, _ => 0 } } } impl From for Variant { fn from(value: u64) -> Self { Variant::BigUInt(value) } } impl Into for Variant { fn into(self) -> u64 { match self { Variant::BigUInt(b) => b, _ => 0 } } } impl From for Variant { fn from(value: bool) -> Self { Variant::Boolean(value) } } impl From for Variant { fn from(value: i64) -> Self { Variant::BigInt(value) } } impl From for Variant { fn from(value: u32) -> Self { Variant::UInt(value) } } impl From for Variant { fn from(value: i32) -> Self { Variant::Int(value) } } impl From for Variant { fn from(value: String) -> Self { Variant::String(value) } } impl<'a> From<&'a str> for Variant { fn from(value: &'a str) -> Self { Variant::String(value.to_owned()) } } impl From> for Variant { fn from(value: Rgb) -> Self { Variant::RGB(value) } } impl From for Variant { fn from(value: i8) -> Self { Variant::SignedByte(value) } } impl Display for Variant { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Variant::BigInt(i) => (i as &dyn Display).fmt(f), Variant::BigUInt(i) => (i as &dyn Display).fmt(f), Variant::Boolean(i) => (i as &dyn Display).fmt(f), Variant::Byte(i) => (i as &dyn Display).fmt(f), Variant::Int(i) => (i as &dyn Display).fmt(f), Variant::String(i) => (i as &dyn Display).fmt(f), Variant::UInt(i) => (i as &dyn Display).fmt(f), Variant::SignedByte(b) => (b as &dyn Display).fmt(f), Variant::RGB(rgb) => f.write_fmt(format_args!("[{}, {}, {}]", rgb.r, rgb.g, rgb.b)), } } } #[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) } }