sauron_core/dom/
dispatch.rs1use crate::dom::Program;
5use crate::dom::{Application, Cmd, Effects};
6use wasm_bindgen_futures::spawn_local;
7
8pub struct Dispatch<APP>
15where
16 APP: Application,
17{
18 #[allow(clippy::type_complexity)]
20 pub(crate) commands: Vec<Box<dyn FnOnce(Program<APP>)>>,
21}
22
23impl<APP> Dispatch<APP>
24where
25 APP: Application,
26{
27 pub fn new<F>(f: F) -> Self
29 where
30 F: FnOnce(Program<APP>) + 'static,
31 {
32 Self {
33 commands: vec![Box::new(f)],
34 }
35 }
36
37 pub fn batch(cmds: impl IntoIterator<Item = Self>) -> Self {
40 let mut commands = vec![];
41 for cmd in cmds {
42 commands.extend(cmd.commands);
43 }
44 Self { commands }
45 }
46
47 pub fn push(&mut self, cmd: Self) {
49 self.append([cmd])
50 }
51
52 pub fn append(&mut self, cmds: impl IntoIterator<Item = Self>) {
54 for cmd in cmds {
55 self.commands.extend(cmd.commands);
56 }
57 }
58
59 pub fn none() -> Self {
61 Dispatch { commands: vec![] }
62 }
63
64 pub fn is_empty(&self) -> bool {
66 self.commands.is_empty()
67 }
68
69 pub(crate) fn emit(self, program: Program<APP>) {
71 for cb in self.commands {
72 let program_clone = program.clone();
73 cb(program_clone);
74 }
75 }
76
77 pub fn batch_msg(msg_list: impl IntoIterator<Item = APP::MSG>) -> Self {
81 let msg_list: Vec<APP::MSG> = msg_list.into_iter().collect();
82 Dispatch::new(move |mut program| {
83 program.dispatch_multiple(msg_list);
84 })
85 }
86}
87
88impl<APP> From<Effects<APP::MSG, ()>> for Dispatch<APP>
89where
90 APP: Application,
91{
92 fn from(effects: Effects<APP::MSG, ()>) -> Self {
94 let Effects { local, external: _ } = effects;
97
98 Dispatch::batch(local.into_iter().map(Dispatch::from))
99 }
100}
101
102impl<APP, IN> From<IN> for Dispatch<APP>
103where
104 APP: Application,
105 IN: IntoIterator<Item = Effects<APP::MSG, ()>>,
106{
107 fn from(effects: IN) -> Self {
108 Dispatch::batch(effects.into_iter().map(Dispatch::from))
109 }
110}
111
112impl<APP> From<Cmd<APP::MSG>> for Dispatch<APP>
113where
114 APP: Application,
115{
116 fn from(task: Cmd<APP::MSG>) -> Self {
117 Dispatch::new(move |program| {
118 for mut command in task.commands.into_iter() {
119 let program = program.downgrade();
120 spawn_local(async move {
121 let mut program = program.upgrade().expect("upgrade");
122 while let Some(msg) = command.next().await {
123 program.dispatch(msg)
124 }
125 });
126 }
127 })
128 }
129}