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 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
use std::fmt::Debug; use std::sync::Arc; use arc_swap::ArcSwapOption; use crossbeam_channel as ch; use crate::{ component::{Component, RenderContext, RenderQueue}, model::Update, }; pub struct Dispatcher<M> where M: Update, { model: M, } impl<M> Dispatcher<M> where M: Update + Default, { pub fn new() -> Self { let model = M::default(); Dispatcher { model } } } impl<M> Dispatcher<M> where M: Update, M::Action: Debug, { pub fn main<C>(mut self, mut ui: <C as Component>::Renderer) where C: Component<Model = M>, { let (h, rx) = Handle::new(ui.queue()); let mut toplevel = <C as Component>::view(&ui, h.clone(), &self.model); log::info!("Toplevel component is ready"); let root = toplevel.root(); ui.show(root); ui.main_loop(|ui| match rx.try_recv() { Ok(act) => { log::info!("Action received: {:?}", act); self.model.update(&act); toplevel.update(&ui, &self.model); } Err(ch::TryRecvError::Empty) => {} Err(ch::TryRecvError::Disconnected) => { log::error!("Critical error: dispatcher loop has broken."); ui.quit(); } }); } } pub struct Handle<A> { inner: ArcSwapOption<HandleInner<A>>, queue: Arc<dyn RenderQueue>, } struct HandleInner<A> { tx: ch::Sender<A>, } impl<A> Handle<A> { fn new(queue: impl RenderQueue) -> (Handle<A>, ch::Receiver<A>) { let (tx, rx) = ch::unbounded(); let inner = HandleInner { tx }; ( Handle { inner: ArcSwapOption::from_pointee(inner), queue: Arc::new(queue), }, rx, ) } } impl<A> Handle<A> where A: Debug + Send + 'static, { pub fn dispatch(&self, action: A) { let lease = match self.inner.lease().into_option() { Some(v) => v, None => return, }; log::info!("Dispatching: {:#?}", action); let inner: &HandleInner<A> = &*lease; let tx = inner.tx.clone(); self.queue.execute(Box::new(move || { let _ = tx.try_send(action); })); } } impl<A> Clone for Handle<A> { fn clone(&self) -> Self { Handle { inner: self.inner.clone(), queue: Arc::clone(&self.queue), } } }