1use std::{
2 cell::{Ref, RefCell},
3 fmt::Debug,
4 rc::Rc,
5};
6use wasm_bindgen::{
7 convert::{FromWasmAbi, IntoWasmAbi},
8 describe::WasmDescribe,
9 prelude::Closure,
10 JsValue, UnwrapThrowExt,
11};
12
13#[derive(Debug, Default, PartialEq, Eq, Hash, Clone, Copy)]
23pub struct Void;
24
25impl WasmDescribe for Void {
26 fn describe() {
27 JsValue::describe()
28 }
29}
30
31impl IntoWasmAbi for Void {
32 type Abi = <JsValue as IntoWasmAbi>::Abi;
33
34 fn into_abi(self) -> Self::Abi {
35 JsValue::undefined().into_abi()
36 }
37}
38
39impl FromWasmAbi for Void {
40 type Abi = <JsValue as FromWasmAbi>::Abi;
41
42 unsafe fn from_abi(js: Self::Abi) -> Self {
43 JsValue::from_abi(js);
44 Void
45 }
46}
47
48impl From<Void> for JsValue {
49 fn from(_: Void) -> Self {
50 JsValue::undefined()
51 }
52}
53
54pub struct Callback<T, U = ()> {
67 closure: Rc<RefCell<dyn FnMut(T) -> U>>,
68 js: Rc<RefCell<Option<Closure<dyn FnMut(T) -> U>>>>,
69}
70
71impl<T, U> Callback<T, U>
72where
73 T: 'static,
74 U: 'static,
75{
76 pub fn new(f: impl FnMut(T) -> U + 'static) -> Self {
78 Self {
79 closure: Rc::new(RefCell::new(f)),
80 js: Default::default(),
81 }
82 }
83
84 pub fn to_closure(&self) -> impl FnMut(T) -> U + 'static {
86 let callback = self.clone();
87 move |arg| callback.call(arg)
88 }
89
90 pub fn call(&self, arg: T) -> U {
92 let mut f = self.closure.borrow_mut();
93 f(arg)
94 }
95
96 pub fn premap<V>(&self, mut f: impl FnMut(V) -> T + 'static) -> Callback<V, U>
98 where
99 V: 'static,
100 {
101 let cb = self.clone();
102
103 Callback::new(move |v| {
104 let t = f(v);
105 cb.call(t)
106 })
107 }
108
109 pub fn postmap<V>(
111 &self,
112 mut f: impl FnMut(U) -> V + 'static,
113 ) -> Callback<T, V>
114 where
115 V: 'static,
116 {
117 let cb = self.clone();
118
119 Callback::new(move |t| {
120 let u = cb.call(t);
121 f(u)
122 })
123 }
124
125 pub fn as_js(&self) -> Ref<'_, JsValue>
127 where
128 T: FromWasmAbi,
129 U: IntoWasmAbi,
130 {
131 {
132 self.js.borrow_mut().get_or_insert_with(|| {
133 Closure::new({
134 let closure = self.closure.clone();
135
136 move |arg| {
137 let mut f = closure.borrow_mut();
138 f(arg)
139 }
140 })
141 });
142 }
143
144 Ref::map(self.js.borrow(), |x| {
145 x.as_ref().expect_throw("no closure available").as_ref()
146 })
147 }
148}
149
150impl<T: 'static> Callback<T> {
151 pub fn noop() -> Self {
153 Callback::new(|_| ())
154 }
155}
156
157impl<T, U> Default for Callback<T, U>
158where
159 T: 'static,
160 U: Default + 'static,
161{
162 fn default() -> Self {
163 Self::new(|_| U::default())
164 }
165}
166
167impl<F, T, U> From<F> for Callback<T, U>
168where
169 F: FnMut(T) -> U + 'static,
170 T: 'static,
171 U: 'static,
172{
173 fn from(value: F) -> Self {
174 Self::new(value)
175 }
176}
177
178impl<T, U> Debug for Callback<T, U> {
179 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
180 f.write_str("Callback(|_| { … })")
181 }
182}
183
184impl<T, U> PartialEq for Callback<T, U> {
185 fn eq(&self, other: &Self) -> bool {
186 Rc::ptr_eq(&self.closure, &other.closure) && Rc::ptr_eq(&self.js, &other.js)
187 }
188}
189
190impl<T, U> Eq for Callback<T, U> {}
191
192impl<T, U> Clone for Callback<T, U> {
193 fn clone(&self) -> Self {
194 Self {
195 closure: self.closure.clone(),
196 js: self.js.clone(),
197 }
198 }
199}