1use std::fmt::{self, Debug};
2use std::convert::From;
3use std::hash::{Hash, Hasher};
4use std::iter::FromIterator;
5use std::collections::*;
6use std::cell::{self, Cell, RefCell};
7use std::rc::Rc;
8use std::any::Any;
9use serde::{self, Serialize, Deserialize, de::DeserializeOwned};
10use either::Either;
11use wasm_bindgen::JsValue;
12use wasm_bindgen::closure;
13use wasm_bindgen::closure::Closure;
14
15
16pub mod console {
20 use super::*;
21
22 pub fn log(value: impl Loggable) {
23 match value.to_js_value() {
24 Either::Left(x) => {
25 web_sys::console::log_1(&x);
26 }
27 Either::Right(x) => {
28 web_sys::console::log_1(x);
29 }
30 }
31 }
32 pub fn warn(value: impl Loggable) {
33 match value.to_js_value() {
34 Either::Left(x) => {
35 web_sys::console::warn_1(&x);
36 }
37 Either::Right(x) => {
38 web_sys::console::warn_1(x);
39 }
40 }
41 }
42
43 pub trait Loggable {
44 fn to_js_value(&self) -> Either<JsValue, &JsValue>;
45 }
46 impl Loggable for &str {
47 fn to_js_value(&self) -> Either<JsValue, &JsValue> {
48 Either::Left(JsValue::from_str(self))
49 }
50 }
51 impl Loggable for String {
52 fn to_js_value(&self) -> Either<JsValue, &JsValue> {
53 Either::Left(JsValue::from_str(self.as_str()))
54 }
55 }
56 impl Loggable for JsValue {
57 fn to_js_value(&self) -> Either<JsValue, &JsValue> {
58 Either::Right(&self)
59 }
60 }
61 impl Loggable for &JsValue {
62 fn to_js_value(&self) -> Either<JsValue, &JsValue> {
63 Either::Right(self)
64 }
65 }
66}
67
68
69#[derive(Clone)]
75pub struct VoidCallback {
76 pub i_bindgen_closure: Rc<Closure<dyn Fn(JsValue)>>,
77 pub i_js_function: Rc<js_sys::Function>,
78}
79
80impl VoidCallback {
81 pub fn new(cb: Box<Fn(JsValue)>) -> Self {
82 use wasm_bindgen::JsCast;
83 let function_wrapper: Closure<dyn Fn(JsValue)> = Closure::wrap(Box::new({
84 move |value: JsValue| {
85 cb(value)
86 }
87 }));
88 let js_function: &js_sys::Function = function_wrapper.as_ref().unchecked_ref();
89 let js_function: js_sys::Function = js_function.clone();
90 let void_callback = VoidCallback {
91 i_bindgen_closure: Rc::new(function_wrapper),
92 i_js_function: Rc::new(js_function),
93 };
94 void_callback
95 }
96}
97
98impl Debug for VoidCallback {
99 fn fmt(&self, f: &mut std::fmt::Formatter) -> fmt::Result {
100 write!(f, "VoidCallback")
101 }
102}
103impl PartialEq for VoidCallback {
104 fn eq(&self, other: &VoidCallback) -> bool {true}
105}
106impl crate::dom::Callback for VoidCallback {
107 fn as_js_function(&self) -> &js_sys::Function {
108 self.i_js_function.as_ref()
109 }
110}
111
112#[derive(Clone)]
117pub struct QueueCallback {
118 pub i_bindgen_closure: Rc<Closure<dyn Fn(JsValue)>>,
119 pub i_js_function: Rc<js_sys::Function>,
120 pub i_events: Rc<RefCell<VecDeque<JsValue>>>,
121}
122
123impl QueueCallback {
124 pub fn new() -> Self {
125 use wasm_bindgen::JsCast;
126 let events_queue = Rc::new(RefCell::new(VecDeque::new()));
127 let function_wrapper: Closure<dyn Fn(JsValue)> = Closure::wrap(Box::new({
128 let events_queue = events_queue.clone();
129 move |value: JsValue| {
130 events_queue.borrow_mut().push_back(value);
131 }
132 }));
133 let js_function: &js_sys::Function = function_wrapper.as_ref().unchecked_ref();
134 let js_function: js_sys::Function = js_function.clone();
135 let queue_callback = QueueCallback {
136 i_bindgen_closure: Rc::new(function_wrapper),
137 i_js_function: Rc::new(js_function),
138 i_events: events_queue,
139 };
140 queue_callback
141 }
142 pub fn drain(&self) -> Vec<JsValue> {
143 let xs: Vec<JsValue> = self.i_events.borrow_mut().drain(..).collect();
144 xs
145 }
146}
147
148impl Debug for QueueCallback {
149 fn fmt(&self, f: &mut std::fmt::Formatter) -> fmt::Result {
150 write!(f, "QueueCallback")
151 }
152}
153impl PartialEq for QueueCallback {
154 fn eq(&self, other: &QueueCallback) -> bool {true}
155}
156
157impl crate::dom::Callback for QueueCallback {
158 fn as_js_function(&self) -> &js_sys::Function {
159 self.i_js_function.as_ref()
160 }
161}
162
163pub trait Handler<Msg> {
168 fn handler(&self, event: JsValue) -> Msg;
169}
170
171#[derive(Clone)]
172pub struct EventCallback<Msg> {
173 pub i_handler: Rc<Handler<Msg>>,
174 pub i_bindgen_closure: Rc<Closure<dyn Fn(JsValue)>>,
175 pub i_js_function: Rc<js_sys::Function>,
176 pub i_events: Rc<RefCell<VecDeque<JsValue>>>,
177}
178
179impl<Msg> EventCallback<Msg> {
180 pub fn new(handler: Rc<Handler<Msg>>) -> Self {
181 use wasm_bindgen::JsCast;
182 let events_queue = Rc::new(RefCell::new(VecDeque::new()));
183 let function_wrapper: Closure<dyn Fn(JsValue)> = Closure::wrap(Box::new({
184 let events_queue = events_queue.clone();
185 move |value: JsValue| {
186 events_queue.borrow_mut().push_back(value);
187 }
188 }));
189 let js_function: &js_sys::Function = function_wrapper.as_ref().unchecked_ref();
190 let js_function: js_sys::Function = js_function.clone();
191 let queue_callback = EventCallback {
192 i_handler: handler,
193 i_bindgen_closure: Rc::new(function_wrapper),
194 i_js_function: Rc::new(js_function),
195 i_events: events_queue,
196 };
197 queue_callback
198 }
199 }
209
210impl<Msg> Debug for EventCallback<Msg> {
211 fn fmt(&self, f: &mut std::fmt::Formatter) -> fmt::Result {
212 write!(f, "EventCallback")
213 }
214}
215impl<Msg> PartialEq for EventCallback<Msg> {
216 fn eq(&self, other: &EventCallback<Msg>) -> bool {true}
217}
218
219impl<Msg> crate::dom::Callback for EventCallback<Msg> {
220 fn as_js_function(&self) -> &js_sys::Function {
221 self.i_js_function.as_ref()
222 }
223}
224
225