1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
use core::any::{Any, TypeId}; use core::mem::replace; use alloc::vec::Vec; pub trait Context { fn get_raw(&self, type_: TypeId) -> Option<&dyn Any>; fn get_mut_raw(&mut self, type_: TypeId) -> Option<&mut dyn Any>; } pub trait ContextExt: Context { fn get<T: 'static>(&self) -> Option<&T> { self.get_raw(TypeId::of::<T>()).map(|x| x.downcast_ref::<T>().expect("invalid cast")) } fn get_mut<T: 'static>(&mut self) -> Option<&mut T> { self.get_mut_raw(TypeId::of::<T>()).map(|x| x.downcast_mut::<T>().expect("invalid cast")) } } impl<T: Context + ?Sized> ContextExt for T { } #[derive(Derivative)] #[derivative(Debug)] pub struct Reactive<Owner: Copy, Type> { value: Type, #[derivative(Debug="ignore")] on_changed: Option<Vec<fn(owner: Owner, context: &mut dyn Context, old: &Type)>>, } pub struct OnChanged<Owner: Copy, Type>( Option<Vec<fn(owner: Owner, context: &mut dyn Context, old: &Type)>> ); impl<Owner: Copy, Type> OnChanged<Owner, Type> { pub fn raise(self, owner: Owner, context: &mut dyn Context, old: &Type) { if let Some(on_changed) = self.0 { for on_changed in on_changed { on_changed(owner, context, old); } } } } impl<Owner: Copy, Type: Eq> Reactive<Owner, Type> { pub fn set_distinct(&mut self, value: Type) -> (Type, OnChanged<Owner, Type>) { let old = replace(&mut self.value, value); let on_changed = if old == self.value { None } else { self.on_changed.clone() }; (old, OnChanged(on_changed)) } } impl<Owner: Copy, Type> Reactive<Owner, Type> { pub fn new(value: Type) -> Self { Reactive { value, on_changed: None } } pub fn set_uncond(&mut self, value: Type) -> (Type, OnChanged<Owner, Type>) { let old = replace(&mut self.value, value); (old, OnChanged(self.on_changed.clone())) } pub fn get(&self) -> &Type { &self.value } pub fn on_changed( &mut self, callback: fn(owner: Owner, context: &mut dyn Context, old: &Type) ) { if let Some(on_changed) = self.on_changed.as_mut() { on_changed.push(callback); } else { self.on_changed = Some(vec![callback]); } } }