1use std::any::Any;
2use std::marker::PhantomData;
3use std::rc::Rc;
4use std::sync::atomic::{AtomicBool, Ordering};
5use std::sync::{Arc, mpsc};
6
7use crate::core::event::KeyEvent;
8
9#[derive(Clone)]
11pub struct Callback<E>(Rc<dyn Fn(E)>);
12
13impl<E> Callback<E> {
14 pub fn new(f: impl Fn(E) + 'static) -> Self {
16 Self(Rc::new(f))
17 }
18
19 pub fn emit(&self, event: E) {
21 (self.0)(event)
22 }
23}
24
25impl<E> PartialEq for Callback<E> {
26 fn eq(&self, other: &Self) -> bool {
27 Rc::ptr_eq(&self.0, &other.0)
28 }
29}
30
31impl<E> Eq for Callback<E> {}
32
33#[derive(Clone)]
35pub struct KeyHandler(Rc<dyn Fn(KeyEvent) -> bool>);
36
37impl KeyHandler {
38 pub fn new(f: impl Fn(KeyEvent) -> bool + 'static) -> Self {
40 Self(Rc::new(f))
41 }
42
43 pub fn handle(&self, event: KeyEvent) -> bool {
45 (self.0)(event)
46 }
47}
48
49impl PartialEq for KeyHandler {
50 fn eq(&self, other: &Self) -> bool {
51 Rc::ptr_eq(&self.0, &other.0)
52 }
53}
54
55#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
57pub struct ScopeId(pub u32);
58
59#[derive(Clone)]
61pub struct Dispatcher(Rc<dyn Fn(ScopeId, Box<dyn Any>)>);
62
63impl Dispatcher {
64 pub fn new(f: impl Fn(ScopeId, Box<dyn Any>) + 'static) -> Self {
66 Self(Rc::new(f))
67 }
68
69 pub fn dispatch(&self, scope: ScopeId, msg: Box<dyn Any>) {
71 (self.0)(scope, msg)
72 }
73}
74
75pub(crate) type CommandTx = mpsc::Sender<(ScopeId, Box<dyn Any + Send>)>;
76pub(crate) type CommandRx = mpsc::Receiver<(ScopeId, Box<dyn Any + Send>)>;
77
78#[derive(Clone, Debug, Default)]
80pub struct CancellationToken {
81 cancelled: Arc<AtomicBool>,
82}
83
84impl CancellationToken {
85 pub fn is_cancelled(&self) -> bool {
87 self.cancelled.load(Ordering::Acquire)
88 }
89
90 pub(crate) fn cancel(&self) {
91 self.cancelled.store(true, Ordering::Release);
92 }
93}
94
95pub struct CommandLink<Msg: Send + 'static> {
97 scope: ScopeId,
98 tx: CommandTx,
99 cancellation_token: CancellationToken,
100 _marker: PhantomData<fn(Msg)>,
101}
102
103impl<Msg: Send + 'static> Clone for CommandLink<Msg> {
107 fn clone(&self) -> Self {
108 Self {
109 scope: self.scope,
110 tx: self.tx.clone(),
111 cancellation_token: self.cancellation_token.clone(),
112 _marker: PhantomData,
113 }
114 }
115}
116
117impl<Msg: Send + 'static> CommandLink<Msg> {
118 pub(crate) fn new(
119 scope: ScopeId,
120 tx: CommandTx,
121 cancellation_token: CancellationToken,
122 ) -> Self {
123 Self {
124 scope,
125 tx,
126 cancellation_token,
127 _marker: PhantomData,
128 }
129 }
130
131 pub fn cancellation_token(&self) -> CancellationToken {
133 self.cancellation_token.clone()
134 }
135
136 pub fn is_cancelled(&self) -> bool {
138 self.cancellation_token.is_cancelled()
139 }
140
141 pub fn send(&self, msg: Msg) {
143 let _ = self.tx.send((self.scope, Box::new(msg)));
144 }
145
146 pub fn send_if_not_cancelled(&self, msg: Msg) -> bool {
148 if self.is_cancelled() {
149 return false;
150 }
151 self.tx.send((self.scope, Box::new(msg))).is_ok()
152 }
153
154 pub fn send_after(&self, delay: std::time::Duration, msg: Msg) {
162 let link = self.clone();
163 crate::core::component::schedule_after(delay, move || {
164 link.send_if_not_cancelled(msg);
165 });
166 }
167}
168
169pub struct Link<Msg: 'static> {
171 scope: ScopeId,
172 dispatcher: Dispatcher,
173 _marker: PhantomData<fn(Msg)>,
174}
175
176impl<Msg: 'static> Clone for Link<Msg> {
177 fn clone(&self) -> Self {
178 Self {
179 scope: self.scope,
180 dispatcher: self.dispatcher.clone(),
181 _marker: PhantomData,
182 }
183 }
184}
185
186impl<Msg: 'static> Link<Msg> {
187 pub(crate) fn new(scope: ScopeId, dispatcher: Dispatcher) -> Self {
188 Self {
189 scope,
190 dispatcher,
191 _marker: PhantomData,
192 }
193 }
194
195 pub fn send(&self, msg: Msg) {
197 self.dispatcher.dispatch(self.scope, Box::new(msg));
198 }
199
200 pub fn callback<E: 'static>(&self, f: impl Fn(E) -> Msg + 'static) -> Callback<E> {
202 let link = (*self).clone();
203 Callback::new(move |e| link.send(f(e)))
204 }
205
206 pub fn callback_opt<E: 'static>(&self, f: impl Fn(E) -> Option<Msg> + 'static) -> Callback<E> {
210 let link = (*self).clone();
211 Callback::new(move |e| {
212 if let Some(msg) = f(e) {
213 link.send(msg);
214 }
215 })
216 }
217
218 pub fn key_handler(&self, f: impl Fn(KeyEvent) -> Option<Msg> + 'static) -> KeyHandler {
222 let link = (*self).clone();
223 KeyHandler::new(move |e| {
224 if let Some(msg) = f(e) {
225 link.send(msg);
226 true
227 } else {
228 false
229 }
230 })
231 }
232}
233
234#[cfg(test)]
235mod tests {
236 use std::any::Any;
237 use std::cell::RefCell;
238 use std::rc::Rc;
239
240 use super::{Dispatcher, KeyHandler, Link, ScopeId};
241 use crate::core::event::{KeyCode, KeyEvent, KeyMods};
242
243 type TestQueue = Rc<RefCell<Vec<(ScopeId, Box<dyn Any>)>>>;
244
245 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
246 enum Msg {
247 Ping,
248 }
249
250 fn key(code: KeyCode) -> KeyEvent {
251 KeyEvent {
252 code,
253 mods: KeyMods::default(),
254 }
255 }
256
257 #[test]
258 fn key_handler_respects_explicit_handled_flag() {
259 let queue: TestQueue = Rc::new(RefCell::new(Vec::new()));
260 let dispatcher = {
261 let queue = queue.clone();
262 Dispatcher::new(move |scope, msg| queue.borrow_mut().push((scope, msg)))
263 };
264 let link: Link<Msg> = Link::new(ScopeId(1), dispatcher);
265 let handler = KeyHandler::new({
266 let link = link.clone();
267 move |_key| {
268 link.send(Msg::Ping);
269 false
270 }
271 });
272
273 let handled = handler.handle(key(KeyCode::Enter));
274
275 assert!(!handled);
276 assert_eq!(queue.borrow().len(), 1);
277 }
278
279 #[test]
280 fn key_handler_returns_true_when_message_emitted() {
281 let queue: TestQueue = Rc::new(RefCell::new(Vec::new()));
282 let dispatcher = {
283 let queue = queue.clone();
284 Dispatcher::new(move |scope, msg| queue.borrow_mut().push((scope, msg)))
285 };
286 let link: Link<Msg> = Link::new(ScopeId(1), dispatcher);
287 let handler = link.key_handler(|key| match key.code {
288 KeyCode::Enter => Some(Msg::Ping),
289 _ => None,
290 });
291
292 assert!(handler.handle(key(KeyCode::Enter)));
293 assert_eq!(queue.borrow().len(), 1);
294 assert!(!handler.handle(key(KeyCode::Tab)));
295 assert_eq!(queue.borrow().len(), 1);
296 }
297}