1use axum::response::Response;
2use generational_box::{AnyStorage, Owner, SyncStorage};
3use std::{collections::HashMap, future::Future, sync::Arc};
4use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender};
5
6use crate::{
7 closure::{Closure, ClosureTrait, ClosureWrapper, IntoClosure},
8 event_handlers::{EventHandler, EventHandlerWrapper},
9 html::Element,
10 state::{State, StateInner},
11 CoaxialResponse, Output,
12};
13
14pub struct Context<S = ()> {
15 uuid: u64,
16 index: u64,
17
18 state_owner: Owner<SyncStorage>,
19 pub(crate) closures: HashMap<String, Arc<dyn ClosureTrait<S>>>,
20 pub(crate) event_handlers: HashMap<String, Arc<dyn EventHandler>>,
21
22 pub(crate) changes_rx: UnboundedReceiver<(u64, String)>,
23 changes_tx: UnboundedSender<(u64, String)>,
24}
25
26impl<S> Context<S> {
27 pub fn use_closure<P, I>(&mut self, closure: I) -> Closure
28 where
29 I: IntoClosure<P, S> + Send + Sync + 'static,
30 P: Send + Sync + 'static,
31 ClosureWrapper<I, P>: ClosureTrait<S>,
32 {
33 self.index += 1;
34 let id = format!("{}-{}", self.uuid, self.index);
35 let closure: ClosureWrapper<I, P> = <I as IntoClosure<P, S>>::wrap(closure);
36 self.closures.insert(id.clone(), Arc::new(closure));
37
38 Closure { id }
39 }
40
41 #[track_caller]
42 pub fn use_state<T: Send + Sync>(&mut self, value: T) -> State<T> {
43 self.index += 1;
44 State {
45 inner: self.state_owner.insert_with_caller(
46 StateInner {
47 value,
48 changes_tx: self.changes_tx.clone(),
49 },
50 #[cfg(any(debug_assertions, feature = "debug_ownership"))]
51 std::panic::Location::caller(),
52 ),
53 id: self.index + self.uuid,
54 }
55 }
56
57 pub fn on<F, Fut, P>(&mut self, name: impl ToString, closure: F)
60 where
61 F: Fn(P) -> Fut + Send + Sync + 'static,
62 Fut: Future<Output = ()> + Send + Sync + 'static,
63 P: serde::de::DeserializeOwned + Send + Sync + 'static,
64 {
65 self.event_handlers.insert(
66 name.to_string(),
67 Arc::new(EventHandlerWrapper::new(closure)),
68 );
69 }
70
71 pub fn with(self, element: Element) -> CoaxialResponse<S> {
72 Response::new(Output {
73 element,
74 context: self,
75 })
76 }
77}
78
79impl<S> Default for Context<S> {
80 fn default() -> Self {
81 let (changes_tx, changes_rx) = unbounded_channel();
82
83 Self {
84 uuid: 100000,
86 index: 0,
87 state_owner: <SyncStorage as AnyStorage>::owner(),
88 closures: Default::default(),
89 event_handlers: Default::default(),
90
91 changes_rx,
92 changes_tx,
93 }
94 }
95}