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
95#[derive(Clone)]
97pub struct CommandLink<Msg: Send + 'static> {
98 scope: ScopeId,
99 tx: CommandTx,
100 cancellation_token: CancellationToken,
101 _marker: PhantomData<fn(Msg)>,
102}
103
104impl<Msg: Send + 'static> CommandLink<Msg> {
105 pub(crate) fn new(
106 scope: ScopeId,
107 tx: CommandTx,
108 cancellation_token: CancellationToken,
109 ) -> Self {
110 Self {
111 scope,
112 tx,
113 cancellation_token,
114 _marker: PhantomData,
115 }
116 }
117
118 pub fn cancellation_token(&self) -> CancellationToken {
120 self.cancellation_token.clone()
121 }
122
123 pub fn is_cancelled(&self) -> bool {
125 self.cancellation_token.is_cancelled()
126 }
127
128 pub fn send(&self, msg: Msg) {
130 let _ = self.tx.send((self.scope, Box::new(msg)));
131 }
132
133 pub fn send_if_not_cancelled(&self, msg: Msg) -> bool {
135 if self.is_cancelled() {
136 return false;
137 }
138 self.tx.send((self.scope, Box::new(msg))).is_ok()
139 }
140}
141
142pub struct Link<Msg: 'static> {
144 scope: ScopeId,
145 dispatcher: Dispatcher,
146 _marker: PhantomData<fn(Msg)>,
147}
148
149impl<Msg: 'static> Clone for Link<Msg> {
150 fn clone(&self) -> Self {
151 Self {
152 scope: self.scope,
153 dispatcher: self.dispatcher.clone(),
154 _marker: PhantomData,
155 }
156 }
157}
158
159impl<Msg: 'static> Link<Msg> {
160 pub(crate) fn new(scope: ScopeId, dispatcher: Dispatcher) -> Self {
161 Self {
162 scope,
163 dispatcher,
164 _marker: PhantomData,
165 }
166 }
167
168 pub fn send(&self, msg: Msg) {
170 self.dispatcher.dispatch(self.scope, Box::new(msg));
171 }
172
173 pub fn callback<E: 'static>(&self, f: impl Fn(E) -> Msg + 'static) -> Callback<E> {
175 let link = (*self).clone();
176 Callback::new(move |e| link.send(f(e)))
177 }
178
179 pub fn callback_opt<E: 'static>(&self, f: impl Fn(E) -> Option<Msg> + 'static) -> Callback<E> {
183 let link = (*self).clone();
184 Callback::new(move |e| {
185 if let Some(msg) = f(e) {
186 link.send(msg);
187 }
188 })
189 }
190
191 pub fn key_handler(&self, f: impl Fn(KeyEvent) -> Option<Msg> + 'static) -> KeyHandler {
195 let link = (*self).clone();
196 KeyHandler::new(move |e| {
197 if let Some(msg) = f(e) {
198 link.send(msg);
199 true
200 } else {
201 false
202 }
203 })
204 }
205}
206
207#[cfg(test)]
208mod tests {
209 use std::any::Any;
210 use std::cell::RefCell;
211 use std::rc::Rc;
212
213 use super::{Dispatcher, KeyHandler, Link, ScopeId};
214 use crate::core::event::{KeyCode, KeyEvent, KeyMods};
215
216 type TestQueue = Rc<RefCell<Vec<(ScopeId, Box<dyn Any>)>>>;
217
218 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
219 enum Msg {
220 Ping,
221 }
222
223 fn key(code: KeyCode) -> KeyEvent {
224 KeyEvent {
225 code,
226 mods: KeyMods::default(),
227 }
228 }
229
230 #[test]
231 fn key_handler_respects_explicit_handled_flag() {
232 let queue: TestQueue = Rc::new(RefCell::new(Vec::new()));
233 let dispatcher = {
234 let queue = queue.clone();
235 Dispatcher::new(move |scope, msg| queue.borrow_mut().push((scope, msg)))
236 };
237 let link: Link<Msg> = Link::new(ScopeId(1), dispatcher);
238 let handler = KeyHandler::new({
239 let link = link.clone();
240 move |_key| {
241 link.send(Msg::Ping);
242 false
243 }
244 });
245
246 let handled = handler.handle(key(KeyCode::Enter));
247
248 assert!(!handled);
249 assert_eq!(queue.borrow().len(), 1);
250 }
251
252 #[test]
253 fn key_handler_returns_true_when_message_emitted() {
254 let queue: TestQueue = Rc::new(RefCell::new(Vec::new()));
255 let dispatcher = {
256 let queue = queue.clone();
257 Dispatcher::new(move |scope, msg| queue.borrow_mut().push((scope, msg)))
258 };
259 let link: Link<Msg> = Link::new(ScopeId(1), dispatcher);
260 let handler = link.key_handler(|key| match key.code {
261 KeyCode::Enter => Some(Msg::Ping),
262 _ => None,
263 });
264
265 assert!(handler.handle(key(KeyCode::Enter)));
266 assert_eq!(queue.borrow().len(), 1);
267 assert!(!handler.handle(key(KeyCode::Tab)));
268 assert_eq!(queue.borrow().len(), 1);
269 }
270}