1use std::{
2 any::TypeId,
3 cell::{Cell, RefCell},
4 collections::VecDeque,
5 fmt,
6 future::Future,
7 hash::{Hash, Hasher},
8 pin::Pin,
9 rc::Rc,
10 sync::Arc,
11 task::{Context, Poll, Waker},
12};
13
14use cranpose_core::{collections::map::HashMap, hash::default};
15use cranpose_foundation::{
16 DelegatableNode, ModifierNode, ModifierNodeContext, ModifierNodeElement, NodeCapabilities,
17 NodeState, PointerInputNode, impl_pointer_input_node,
18};
19use cranpose_ui_graphics::Size;
20use futures_task::{ArcWake, waker};
21
22use super::{Modifier, PointerEvent, inspector_metadata};
23
24impl Modifier {
25 #[track_caller]
36 pub fn pointer_input<K, F, Fut>(self, key: K, handler: F) -> Self
37 where
38 K: Hash + 'static,
39 F: Fn(PointerInputScope) -> Fut + 'static,
40 Fut: Future<Output = ()> + 'static,
41 {
42 let element = PointerInputElement::new(
43 KeyToken::declaration_site(std::panic::Location::caller()),
44 vec![KeyToken::new(&key)],
45 pointer_input_handler(handler),
46 );
47 let key_count = element.key_count();
48 let handler_id = element.handler_id();
49 self.then(
50 Self::with_element(element).with_inspector_metadata(inspector_metadata(
51 "pointerInput",
52 move |info| {
53 info.add_property("keyCount", key_count.to_string());
54 info.add_property("handlerId", handler_id.to_string());
55 },
56 )),
57 )
58 }
59}
60
61fn pointer_input_handler<F, Fut>(handler: F) -> PointerInputHandler
62where
63 F: Fn(PointerInputScope) -> Fut + 'static,
64 Fut: Future<Output = ()> + 'static,
65{
66 Rc::new(move |scope| Box::pin(handler(scope)))
67}
68
69type PointerInputFuture = Pin<Box<dyn Future<Output = ()>>>;
70type PointerInputHandler = Rc<dyn Fn(PointerInputScope) -> PointerInputFuture>;
71
72#[derive(Clone, Copy, Debug, PartialEq, Eq)]
73pub(crate) enum PointerInputTaskOwner {
74 App(crate::render_state::AppContextId),
75}
76
77pub(crate) struct PointerInputTaskRegistry {
78 tasks: RefCell<HashMap<u64, Rc<PointerInputTaskInner>>>,
79}
80
81impl PointerInputTaskRegistry {
82 pub(crate) fn new() -> Self {
83 Self {
84 tasks: RefCell::new(HashMap::default()),
85 }
86 }
87
88 pub(crate) fn insert(&self, task_id: u64, task: Rc<PointerInputTaskInner>) {
89 self.tasks.borrow_mut().insert(task_id, task);
90 }
91
92 pub(crate) fn remove(&self, task_id: u64) {
93 self.tasks.borrow_mut().remove(&task_id);
94 }
95
96 pub(crate) fn request_poll(&self, task_id: u64, owner: PointerInputTaskOwner) {
97 if let Some(task) = self.tasks.borrow().get(&task_id).cloned() {
98 task.request_poll(owner, task_id);
99 }
100 }
101}
102
103#[derive(Clone)]
104struct PointerInputElement {
105 site: KeyToken,
106 keys: Vec<KeyToken>,
107 handler: PointerInputHandler,
108 handler_id: u64,
109}
110
111impl PointerInputElement {
112 fn new(site: KeyToken, keys: Vec<KeyToken>, handler: PointerInputHandler) -> Self {
113 let handler_id = pointer_handler_identity(&handler);
114 Self {
115 site,
116 keys,
117 handler,
118 handler_id,
119 }
120 }
121
122 fn key_count(&self) -> usize {
123 self.keys.len()
124 }
125
126 fn handler_id(&self) -> u64 {
127 self.handler_id
128 }
129}
130
131fn pointer_handler_identity(handler: &PointerInputHandler) -> u64 {
132 Rc::as_ptr(handler) as *const () as usize as u64
133}
134
135impl fmt::Debug for PointerInputElement {
136 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
137 f.debug_struct("PointerInputElement")
138 .field("site", &self.site)
139 .field("keys", &self.keys)
140 .field("handler", &Rc::as_ptr(&self.handler))
141 .field("handler_id", &self.handler_id)
142 .finish()
143 }
144}
145
146impl PartialEq for PointerInputElement {
147 fn eq(&self, other: &Self) -> bool {
148 self.site == other.site && self.keys == other.keys
149 }
150}
151
152impl Eq for PointerInputElement {}
153
154impl Hash for PointerInputElement {
155 fn hash<H: Hasher>(&self, state: &mut H) {
156 self.site.hash(state);
157 self.keys.hash(state);
158 }
159}
160
161impl ModifierNodeElement for PointerInputElement {
162 type Node = SuspendingPointerInputNode;
163
164 fn create(&self) -> Self::Node {
165 SuspendingPointerInputNode::new(self.site, self.keys.clone(), self.handler.clone())
166 }
167
168 fn update(&self, node: &mut Self::Node) {
169 node.update(self.site, self.keys.clone(), self.handler.clone());
170 }
171
172 fn capabilities(&self) -> NodeCapabilities {
173 NodeCapabilities::POINTER_INPUT
174 }
175}
176
177#[derive(Clone)]
180pub struct PointerInputScope {
181 state: Rc<PointerInputScopeState>,
182}
183
184impl PointerInputScope {
185 fn new(state: Rc<PointerInputScopeState>) -> Self {
186 Self { state }
187 }
188
189 pub fn size(&self) -> Size {
198 self.state.size.get()
199 }
200
201 pub async fn await_pointer_event_scope<R, F, Fut>(&self, block: F) -> R
204 where
205 F: FnOnce(AwaitPointerEventScope) -> Fut,
206 Fut: Future<Output = R>,
207 {
208 let scope = AwaitPointerEventScope {
209 state: self.state.clone(),
210 };
211 block(scope).await
212 }
213}
214
215#[derive(Clone)]
216pub struct AwaitPointerEventScope {
217 state: Rc<PointerInputScopeState>,
218}
219
220impl AwaitPointerEventScope {
221 pub fn size(&self) -> Size {
224 self.state.size.get()
225 }
226
227 pub async fn await_pointer_event(&self) -> PointerEvent {
228 NextPointerEvent {
229 state: self.state.clone(),
230 }
231 .await
232 }
233}
234
235struct NextPointerEvent {
236 state: Rc<PointerInputScopeState>,
237}
238
239impl Future for NextPointerEvent {
240 type Output = PointerEvent;
241
242 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
243 self.state.poll_event(cx)
244 }
245}
246
247struct PointerInputScopeState {
248 events: RefCell<VecDeque<PointerEvent>>,
249 waiting: RefCell<Option<Waker>>,
250 size: Rc<Cell<Size>>,
251}
252
253impl PointerInputScopeState {
254 fn new(size: Rc<Cell<Size>>) -> Self {
255 Self {
256 events: RefCell::new(VecDeque::new()),
257 waiting: RefCell::new(None),
258 size,
259 }
260 }
261
262 fn push_event(&self, event: PointerEvent) {
263 self.events.borrow_mut().push_back(event);
264 let waker = {
265 let mut waiting = self.waiting.borrow_mut();
266 waiting.take()
267 };
268 if let Some(waker) = waker {
269 waker.wake();
270 }
271 }
272
273 fn poll_event(&self, cx: &mut Context<'_>) -> Poll<PointerEvent> {
274 if let Some(event) = self.events.borrow_mut().pop_front() {
275 Poll::Ready(event)
276 } else {
277 self.waiting.replace(Some(cx.waker().clone()));
278 Poll::Pending
279 }
280 }
281}
282
283struct PointerEventDispatcher {
284 state: Rc<RefCell<Option<Rc<PointerInputScopeState>>>>,
285 handler: Rc<dyn Fn(PointerEvent)>,
286}
287
288impl PointerEventDispatcher {
289 fn new() -> Self {
290 let state = Rc::new(RefCell::new(None::<Rc<PointerInputScopeState>>));
291 let state_for_handler = state.clone();
292 let handler = Rc::new(move |event: PointerEvent| {
293 if let Some(inner) = state_for_handler.borrow().as_ref() {
294 inner.push_event(event);
295 }
296 });
297 Self { state, handler }
298 }
299
300 fn handler(&self) -> Rc<dyn Fn(PointerEvent)> {
301 self.handler.clone()
302 }
303
304 fn set_state(&self, state: Option<Rc<PointerInputScopeState>>) {
305 *self.state.borrow_mut() = state;
306 }
307}
308
309struct PointerInputTask {
310 id: u64,
311 owner: PointerInputTaskOwner,
312 inner: Rc<PointerInputTaskInner>,
313}
314
315impl PointerInputTask {
316 fn new(future: PointerInputFuture) -> Self {
317 let inner = Rc::new(PointerInputTaskInner::new(future));
318 let id = Rc::as_ptr(&inner) as usize as u64;
319 let owner = crate::render_state::register_pointer_input_task(id, inner.clone());
320 Self { id, owner, inner }
321 }
322
323 fn poll(&self) {
324 self.inner.poll(self.owner, self.id);
325 }
326
327 fn cancel(self) {
328 self.inner.cancel();
329 crate::render_state::remove_pointer_input_task(self.owner, self.id);
330 }
331}
332
333impl Drop for PointerInputTask {
334 fn drop(&mut self) {
335 self.inner.cancel();
336 crate::render_state::remove_pointer_input_task(self.owner, self.id);
337 }
338}
339
340pub(crate) struct PointerInputTaskInner {
341 future: RefCell<Option<PointerInputFuture>>,
342 is_polling: Cell<bool>,
343 needs_poll: Cell<bool>,
344}
345
346impl PointerInputTaskInner {
347 fn new(future: PointerInputFuture) -> Self {
348 Self {
349 future: RefCell::new(Some(future)),
350 is_polling: Cell::new(false),
351 needs_poll: Cell::new(false),
352 }
353 }
354
355 fn cancel(&self) {
356 self.future.borrow_mut().take();
357 }
358
359 fn request_poll(&self, owner: PointerInputTaskOwner, task_id: u64) {
360 if self.is_polling.get() {
361 self.needs_poll.set(true);
362 } else {
363 self.poll(owner, task_id);
364 }
365 }
366
367 fn poll(&self, owner: PointerInputTaskOwner, task_id: u64) {
368 if self.is_polling.replace(true) {
369 self.needs_poll.set(true);
370 return;
371 }
372 loop {
373 self.needs_poll.set(false);
374 let waker = waker(Arc::new(PointerInputTaskWaker { task_id, owner }));
375 let mut cx = Context::from_waker(&waker);
376 let mut future_slot = self.future.borrow_mut();
377 if let Some(future) = future_slot.as_mut() {
378 let poll_result = future.as_mut().poll(&mut cx);
379 if poll_result.is_ready() {
380 future_slot.take();
381 }
382 }
383 if !self.needs_poll.get() {
384 break;
385 }
386 }
387 self.is_polling.set(false);
388 }
389}
390
391struct PointerInputTaskWaker {
392 task_id: u64,
393 owner: PointerInputTaskOwner,
394}
395
396impl ArcWake for PointerInputTaskWaker {
397 fn wake_by_ref(arc_self: &Arc<Self>) {
398 crate::render_state::request_pointer_input_task_poll(arc_self.owner, arc_self.task_id);
399 }
400}
401
402pub struct SuspendingPointerInputNode {
403 site: KeyToken,
404 keys: Vec<KeyToken>,
405 handler: PointerInputHandler,
406 dispatcher: PointerEventDispatcher,
407 task: Option<PointerInputTask>,
408 layout_size: Rc<Cell<Size>>,
409 state: NodeState,
410}
411
412impl SuspendingPointerInputNode {
413 fn new(site: KeyToken, keys: Vec<KeyToken>, handler: PointerInputHandler) -> Self {
414 Self {
415 site,
416 keys,
417 handler,
418 dispatcher: PointerEventDispatcher::new(),
419 task: None,
420 layout_size: Rc::new(Cell::new(Size {
421 width: 0.0,
422 height: 0.0,
423 })),
424 state: NodeState::new(),
425 }
426 }
427
428 fn update(&mut self, site: KeyToken, keys: Vec<KeyToken>, handler: PointerInputHandler) {
429 let should_restart = self.site != site || self.keys != keys;
430 self.site = site;
431 self.keys = keys;
432 self.handler = handler;
433 if should_restart {
434 self.restart();
435 }
436 }
437
438 fn restart(&mut self) {
439 self.cancel();
440 self.start();
441 }
442
443 fn start(&mut self) {
444 let state = Rc::new(PointerInputScopeState::new(self.layout_size.clone()));
445 self.dispatcher.set_state(Some(state.clone()));
446 let scope = PointerInputScope::new(state);
447 let future = (self.handler)(scope);
448 let task = PointerInputTask::new(future);
449 task.poll();
450 self.task = Some(task);
451 }
452
453 fn cancel(&mut self) {
454 if let Some(task) = self.task.take() {
455 task.cancel();
456 }
457 self.dispatcher.set_state(None);
458 }
459}
460
461impl Drop for SuspendingPointerInputNode {
462 fn drop(&mut self) {
463 self.cancel();
464 }
465}
466
467impl ModifierNode for SuspendingPointerInputNode {
468 fn on_attach(&mut self, _context: &mut dyn ModifierNodeContext) {
469 self.start();
470 }
471
472 fn on_detach(&mut self) {
473 self.cancel();
474 }
475
476 fn on_reset(&mut self) {}
477
478 impl_pointer_input_node!();
479}
480
481impl DelegatableNode for SuspendingPointerInputNode {
482 fn node_state(&self) -> &NodeState {
483 &self.state
484 }
485}
486
487impl PointerInputNode for SuspendingPointerInputNode {
488 fn pointer_input_handler(&self) -> Option<Rc<dyn Fn(PointerEvent)>> {
489 Some(self.dispatcher.handler())
490 }
491
492 fn layout_size_sink(&self) -> Option<Rc<Cell<Size>>> {
493 Some(self.layout_size.clone())
494 }
495}
496
497#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
498struct KeyToken {
499 type_id: TypeId,
500 hash: u64,
501}
502
503impl KeyToken {
504 fn declaration_site(site: &'static std::panic::Location<'static>) -> Self {
505 Self::new(&(site.file(), site.line(), site.column()))
506 }
507
508 fn new<T: Hash + 'static>(value: &T) -> Self {
509 let mut hasher = default::new();
510 value.hash(&mut hasher);
511 Self {
512 type_id: TypeId::of::<T>(),
513 hash: hasher.finish(),
514 }
515 }
516}