wsdom_core/interaction/
callback.rs1use std::{fmt::Write, marker::PhantomData, pin::Pin, task::Poll};
26
27use crate::{
28 js::value::JsValue,
29 js_cast::JsCast,
30 link::{Browser, RetrievalState},
31 protocol::{DEL, GET, REP, SET},
32};
33
34pub struct Callback<E> {
41 arr_id: u64,
42 ret_id: u64,
43 browser: Browser,
44 consumed: usize,
45 _phantom: PhantomData<Pin<Box<E>>>,
46}
47
48impl<E: JsCast> futures_core::Stream for Callback<E> {
49 type Item = E;
50
51 fn poll_next(
52 self: Pin<&mut Self>,
53 cx: &mut std::task::Context<'_>,
54 ) -> Poll<Option<Self::Item>> {
55 let this = self.get_mut();
56 let mut link = this.browser.0.lock().unwrap();
57 let ret_id = this.ret_id;
58 match link.retrievals.entry(ret_id) {
59 std::collections::hash_map::Entry::Occupied(mut occ) => {
60 let state = occ.get_mut();
61
62 let new_waker = cx.waker();
63 if !state.waker.will_wake(new_waker) {
64 state.waker = new_waker.to_owned();
65 }
66
67 if state.times > this.consumed {
68 this.consumed += 1;
69 let val_id = link.get_new_id();
70 let arr_id = this.arr_id;
71 writeln!(
72 link.raw_commands_buf(),
73 "{SET}({val_id}, {GET}({arr_id}).shift());"
74 )
75 .unwrap();
76 link.wake_outgoing_lazy();
77 Poll::Ready(Some(JsCast::unchecked_from_js(JsValue {
78 id: val_id,
79 browser: this.browser.to_owned(),
80 })))
81 } else {
82 Poll::Pending
83 }
84 }
85 std::collections::hash_map::Entry::Vacant(vac) => {
86 vac.insert(RetrievalState {
87 waker: cx.waker().to_owned(),
88 last_value: String::new(),
89 times: 0,
90 });
91 Poll::Pending
92 }
93 }
94 }
95}
96impl<E> Drop for Callback<E> {
97 fn drop(&mut self) {
98 let mut link = self.browser.0.lock().unwrap();
99 let ret_id = self.ret_id;
100 link.retrievals.remove(&ret_id);
101 let arr_id = self.arr_id;
102 writeln!(link.raw_commands_buf(), "{DEL}({arr_id});").unwrap();
103 }
104}
105
106pub fn new_callback<E>(browser: &Browser) -> (Callback<E>, JsValue) {
111 let mut link = browser.0.lock().unwrap();
112 let arr_id = link.get_new_id();
113 let ret_id = link.get_new_id();
114 let func_id = link.get_new_id();
115 let func = JsValue {
116 browser: browser.to_owned(),
117 id: func_id,
118 };
119 writeln!(link.raw_commands_buf(),
120"{SET}({arr_id}, []); {SET}({func_id}, function(e) {{ {GET}({arr_id}).push(e); {REP}({ret_id}, 0) }});").unwrap();
121 link.wake_outgoing_lazy();
122 let callback = Callback {
123 browser: browser.to_owned(),
124 ret_id,
125 arr_id,
126 consumed: 0,
127 _phantom: PhantomData,
128 };
129 (callback, func)
130}