1use std::{cell::RefCell, pin::Pin, rc::Rc, task::Poll};
2
3use hooks::{dyn_hook, HookPollNextUpdate};
4use yew::{Component, Html, Properties};
5
6pub type DynHookComponent<Props> = dyn_hook![ for<'a> (&'a Props) -> Html ];
7
8pub struct PinBoxDynHookComponent<Props> {
9 hook: RefCell<Pin<Box<DynHookComponent<Props>>>>,
10 abort_control: Option<Rc<()>>,
11}
12
13impl<Props> PinBoxDynHookComponent<Props> {
14 #[inline]
15 pub fn new(hook: Pin<Box<DynHookComponent<Props>>>) -> Self {
16 Self {
17 hook: RefCell::new(hook),
18 abort_control: None,
19 }
20 }
21}
22
23impl<Props: 'static + Properties> PinBoxDynHookComponent<Props> {
24 pub fn view(&self, props: &Props) -> Html {
25 let mut hook = self.hook.borrow_mut();
26
27 let hook = hook.as_mut();
28
29 hook.erased_use_hook((props,))
30 }
31
32 pub fn rendered<COMP: Component<Message = bool>>(
33 &mut self,
34 ctx: &yew::Context<COMP>,
35 mut get_hook: impl FnMut(&COMP) -> &Self + 'static,
36 ) {
37 let weak = if let Some(ac) = &self.abort_control {
38 if Rc::weak_count(ac) == 0 && Rc::strong_count(ac) == 1 {
39 Some(Rc::downgrade(ac))
40 } else {
41 None
42 }
43 } else {
44 let abort_control = Rc::new(());
45 let weak = Rc::downgrade(&abort_control);
46 self.abort_control = Some(abort_control);
47 Some(weak)
48 };
49
50 if let Some(mut weak) = weak {
51 let scope = ctx.link();
52 let s = scope.clone();
53
54 scope.send_future(std::future::poll_fn(move |cx| {
55 if weak.strong_count() == 0 {
56 return Poll::Ready(false);
57 }
58
59 let comp = s.get_component().unwrap();
60 let mut hook = get_hook(&comp).hook.borrow_mut();
61 let hook = hook.as_mut();
62 let res =
63 <DynHookComponent<Props> as HookPollNextUpdate>::poll_next_update(hook, cx);
64
65 if res.is_ready() {
66 std::mem::take(&mut weak);
67 }
68
69 res
70 }));
71 }
72 }
73
74 #[inline]
75 pub fn changed(&mut self) -> bool {
76 self.abort_control.take();
77 true
78 }
79}