1use leptos::logging::log;
2use std::collections::HashMap;
3use std::collections::HashSet;
4use std::hash::Hash;
5
6pub mod file_handler;
7pub mod serve;
8
9pub use dust_macro::{DustState, dust_define_callback, dust_lib, dust_main};
10
11pub use console_error_panic_hook;
13pub use leptos;
14pub use leptos_meta;
15pub use leptos_router;
16pub use once_cell;
17pub use serde;
18
19#[cfg(feature = "ssr")]
20pub use tokio;
21
22#[cfg(feature = "hydrate")]
23pub use wasm_bindgen;
24
25pub use web_sys;
26
27pub struct Input<T> {
28 pub value: T,
29}
30
31#[derive(Clone, Copy)]
32pub enum OutputState {
33 NoChange,
34 Updated,
35}
36
37pub struct Output<T> {
38 pub value: T,
39 pub state: OutputState,
40}
41
42impl<T: Clone> Output<T> {
43 pub fn new(value: T) -> Output<T> {
44 Output {
45 value: value,
46 state: OutputState::NoChange,
47 }
48 }
49
50 pub fn set(&mut self, value: T) {
51 self.value = value;
52 self.state = OutputState::Updated;
53 }
54}
55
56#[derive(Clone)]
57pub struct StateCallback<I, V, S> {
58 pub name: &'static str,
59 pub cb: fn(&mut S) -> Vec<V>,
60 pub inputs: Vec<I>,
61 pub outputs: Vec<I>,
62}
63
64impl<I, S, V> StateCallback<I, V, S> {
65 pub fn new(name: &'static str, cb: fn(&mut S) -> Vec<V>, inputs: Vec<I>, outputs: Vec<I>) -> Self {
66 Self {
67 name,
68 cb,
69 inputs,
70 outputs,
71 }
72 }
73}
74
75impl<I, S, V> std::hash::Hash for StateCallback<I, V, S> {
76 fn hash<H>(&self, state: &mut H)
77 where
78 H: std::hash::Hasher,
79 {
80 let pointer = self.cb as *const ();
81 pointer.hash(state);
82 state.finish();
83 }
84}
85
86impl<I, V, S> PartialEq for StateCallback<I, V, S> {
87 fn eq(&self, other: &StateCallback<I, V, S>) -> bool {
88 let self_pointer = self.cb as *const ();
89 let other_pointer = other.cb as *const ();
90 return self_pointer == other_pointer;
91 }
92}
93
94#[derive(Clone)]
95pub struct StateCallbackWithId<I, V, S> {
96 pub id: usize,
97 pub callback: StateCallback<I, V, S>,
98}
99
100pub trait StateTypes {
101 type Identifier;
102 type Value;
103 type CallbackInfo;
104 type Context;
105}
106
107impl<I, V, S> Eq for StateCallback<I, V, S> {}
108
109pub trait ValueToIdentifier<I> {
110 fn to_identifier(&self) -> I;
111}
112
113pub trait ApplyUpdates<V> {
114 fn apply_updates(&mut self, updates: &Vec<V>);
115}
116
117pub struct Executor<I, V, S> {
118 callbacks: Vec<StateCallbackWithId<I, V, S>>,
119 input_to_callbacks: HashMap<I, Vec<usize>>,
120 callback_to_dependants: HashMap<usize, Vec<usize>>,
122 callback_to_topological_rank: HashMap<usize, usize>,
124}
125
126impl<I, V, S> Executor<I, V, S>
127where
128 I: Hash + PartialEq + Eq + Clone + Copy,
129 V: Clone + std::fmt::Debug + ValueToIdentifier<I>,
130 S: Clone + Default + ApplyUpdates<V>,
131{
132 pub fn new() -> Executor<I, V, S> {
133 let app = Executor {
134 callbacks: Vec::new(),
135 input_to_callbacks: HashMap::new(),
136 callback_to_dependants: HashMap::new(),
137 callback_to_topological_rank: HashMap::new(),
138 };
139 return app;
140 }
141
142 pub fn register_callback(&mut self, callback: StateCallback<I, V, S>) {
143 let id = self.callbacks.len();
144
145 self.callbacks.push(StateCallbackWithId {
146 id: id,
147 callback: callback,
148 });
149 }
150
151 pub fn init_callbacks(&mut self) {
152 for cb in self.callbacks.iter() {
153 for input in cb.callback.inputs.iter() {
154 if !self.input_to_callbacks.contains_key(input) {
155 self.input_to_callbacks.insert(input.clone(), Vec::new());
156 }
157
158 let v = self.input_to_callbacks.get_mut(input).unwrap();
159 v.push(cb.id);
160 }
161 }
162
163 let mut callback_names: HashMap<usize, &'static str> = HashMap::new();
164 for cb in self.callbacks.iter() {
165 callback_names.insert(cb.id, cb.callback.name);
166 self.callback_to_dependants.insert(cb.id, Vec::new());
167 let edges = self.callback_to_dependants.get_mut(&cb.id).unwrap();
168
169 for output in cb.callback.outputs.iter() {
170 if let Some(deps) = self.input_to_callbacks.get(output) {
171 for dep in deps.iter() {
172 edges.push(*dep);
173 }
174 }
175 }
176 }
177
178 let mut temp_marks: HashSet<usize> = HashSet::new();
179 let mut perm_marks: HashSet<usize> = HashSet::new();
180 let mut cycle: Vec<usize> = Vec::new();
181 let mut topological_order: Vec<usize> = Vec::new();
182
183 fn visit(
184 id: usize,
185 callback_names: &HashMap<usize, &'static str>,
186 callback_to_dependants: &HashMap<usize, Vec<usize>>,
187 temp_marks: &mut HashSet<usize>,
188 perm_marks: &mut HashSet<usize>,
189 cycle: &mut Vec<usize>,
190 topological_order: &mut Vec<usize>,
191 ) -> bool {
192 if perm_marks.contains(&id) {
193 return false;
194 }
195 if temp_marks.contains(&id) {
196 cycle.push(id);
197 return true;
198 }
199
200 temp_marks.insert(id);
201 for dep in callback_to_dependants.get(&id).unwrap().iter() {
202 if visit(
203 *dep,
204 callback_names,
205 callback_to_dependants,
206 temp_marks,
207 perm_marks,
208 cycle,
209 topological_order,
210 ) {
211 if cycle.len() == 1 || cycle.first().unwrap() != cycle.last().unwrap() {
212 cycle.push(id);
214 }
215 return true;
216 }
217 }
218 temp_marks.remove(&id);
219 perm_marks.insert(id);
220 topological_order.push(id);
221 return false;
222 }
223
224 for cb in self.callbacks.iter() {
225 if !perm_marks.contains(&cb.id) {
226 if visit(
227 cb.id,
228 &callback_names,
229 &self.callback_to_dependants,
230 &mut temp_marks,
231 &mut perm_marks,
232 &mut cycle,
233 &mut topological_order,
234 ) {
235 let cycle_description = cycle
236 .iter()
237 .rev()
238 .map(|id| self.callbacks[*id].callback.name)
239 .collect::<Vec<&str>>()
240 .join(" -> ");
241 panic!("Found callback cycle: {}", cycle_description);
242 }
243 }
244 }
245
246 topological_order.reverse();
247 let topological_order_description = topological_order
248 .iter()
249 .map(|id| self.callbacks[*id].callback.name)
250 .collect::<Vec<&str>>()
251 .join(" -> ");
252 log!(
253 "Computed callback tological order {}",
254 topological_order_description
255 );
256
257 for (rank, id) in topological_order.iter().enumerate() {
258 self.callback_to_topological_rank.insert(*id, rank);
259 }
260 }
261
262 pub fn get_execution_plan(&self, updated_inputs: &Vec<I>) -> Vec<usize> {
263 let mut execution_plan: Vec<usize> = Vec::new();
264 let mut visited_cb_ids: HashSet<usize> = HashSet::new();
265
266 fn visit(
267 id: usize,
268 callback_to_dependants: &HashMap<usize, Vec<usize>>,
269 execution_plan: &mut Vec<usize>,
270 visited_cb_ids: &mut HashSet<usize>,
271 ) {
272 if visited_cb_ids.contains(&id) {
273 return;
274 }
275
276 execution_plan.push(id);
277 visited_cb_ids.insert(id);
278 for dep in callback_to_dependants.get(&id).unwrap().iter() {
279 visit(*dep, callback_to_dependants, execution_plan, visited_cb_ids);
280 }
281 }
282
283 for input in updated_inputs.iter() {
284 for id in self.input_to_callbacks.get(input).unwrap().iter() {
285 visit(
286 *id,
287 &self.callback_to_dependants,
288 &mut execution_plan,
289 &mut visited_cb_ids,
290 );
291 }
292 }
293
294 execution_plan.sort_by_key(|id| self.callback_to_topological_rank.get(id).unwrap());
295 return execution_plan;
296 }
297
298 pub fn get_required_state(
299 &self,
300 updated_inputs: &Vec<I>,
301 execution_plan: &Vec<usize>,
302 ) -> HashSet<I> {
303 let mut available_inputs: HashSet<I> = HashSet::from_iter(updated_inputs.iter().cloned());
304 let mut required_state: HashSet<I> = HashSet::new();
305
306 for id in execution_plan.iter() {
307 let callback = &self.callbacks[*id].callback;
308 for input in callback.inputs.iter() {
309 if !available_inputs.contains(input) {
310 required_state.insert(*input);
311 }
312 }
313 for output in callback.outputs.iter() {
314 available_inputs.insert(*output);
315 }
316 }
317
318 return required_state;
319 }
320
321 pub fn get_required_initialization_inputs(&self) -> HashSet<I> {
322 let mut required_inputs: HashSet<I> = HashSet::new();
323 for cb in self.callbacks.iter() {
324 for input in cb.callback.inputs.iter() {
325 required_inputs.insert(input.clone());
326 }
327 }
328
329 for cb in self.callbacks.iter() {
330 for output in cb.callback.outputs.iter() {
331 if required_inputs.contains(output) {
334 required_inputs.remove(output);
335 }
336 }
337 }
338 return required_inputs;
339 }
340
341 pub fn process_updates(&self, input_updates: Vec<V>, required_state: Vec<V>) -> Vec<V> {
342 let mut state = S::default();
343 state.apply_updates(&required_state);
344 state.apply_updates(&input_updates);
345
346 let updated_inputs = input_updates.iter().map(|v| v.to_identifier()).collect();
347 let execution_plan = self.get_execution_plan(&updated_inputs);
348
349 let mut output_updates: Vec<V> = Vec::new();
350 for id in execution_plan.iter() {
351 let callback = &self.callbacks[*id].callback;
352
353 let mut new_updates = (callback.cb)(&mut state);
354 state.apply_updates(&new_updates);
355 output_updates.append(&mut new_updates);
356 }
357
358 println!("output_updates: {:?}", output_updates);
359 return output_updates;
360 }
361}