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),
        }
    }
}