convert_js/
to_js.rs

1use wasm_bindgen::JsValue;
2
3pub trait ToJs {
4    fn to_js(&self) -> JsValue;
5
6    /// return `None` to leave property unset
7    ///
8    /// return `Some(value)` to set property
9    fn to_js_property_value(&self) -> Option<JsValue> {
10        Some(self.to_js())
11    }
12}
13
14/// # Convert as js
15///
16/// `Some(value)` => `value`
17///
18/// `None`        => `undefined`
19///
20/// # Convert as js property value
21///
22/// `Some(value)` => property set to `value`
23///
24/// `None`        => property unset
25impl<T> ToJs for Option<T>
26where
27    T: ToJs,
28{
29    fn to_js(&self) -> JsValue {
30        if let Some(v) = self {
31            v.to_js()
32        } else {
33            JsValue::UNDEFINED
34        }
35    }
36
37    fn to_js_property_value(&self) -> Option<JsValue> {
38        self.as_ref().map(|v| v.to_js())
39    }
40}
41
42impl<'a, B: 'a + ?Sized + ToJs + ToOwned> ToJs for std::borrow::Cow<'a, B> {
43    fn to_js(&self) -> JsValue {
44        self.as_ref().to_js()
45    }
46}
47
48macro_rules! impl_to_js {
49    (deref_copy: $($n:ty)*) => ($(
50        impl ToJs for $n {
51            #[inline]
52            fn to_js(&self) -> JsValue {
53                JsValue::from(*self)
54            }
55        }
56    )*);
57    (into: $($n:ty)*) => ($(
58        impl ToJs for $n {
59            #[inline]
60            fn to_js(&self) -> JsValue {
61                JsValue::from(self)
62            }
63        }
64    )*);
65}
66
67impl_to_js! {
68    into:
69    str
70    String
71    js_sys::Intl::Collator
72    js_sys::Intl::DateTimeFormat
73    js_sys::Intl::NumberFormat
74    js_sys::Intl::PluralRules
75    js_sys::WebAssembly::CompileError
76    js_sys::WebAssembly::Global
77    js_sys::WebAssembly::Instance
78    js_sys::WebAssembly::LinkError
79    js_sys::WebAssembly::Memory
80    js_sys::WebAssembly::Module
81    js_sys::WebAssembly::RuntimeError
82    js_sys::WebAssembly::Table
83    js_sys::Array
84    js_sys::ArrayBuffer
85    // js_sys::ArrayIter
86    js_sys::AsyncIterator
87    js_sys::BigInt
88    js_sys::BigInt64Array
89    js_sys::BigUint64Array
90    js_sys::Boolean
91    js_sys::DataView
92    js_sys::Date
93    js_sys::Error
94    js_sys::EvalError
95    js_sys::Float32Array
96    js_sys::Float64Array
97    js_sys::Function
98    js_sys::Generator
99    js_sys::Int8Array
100    js_sys::Int16Array
101    js_sys::Int32Array
102    // js_sys::IntoIter
103    // js_sys::Iter
104    js_sys::Iterator
105    js_sys::IteratorNext
106    js_sys::JsString
107    js_sys::Map
108    js_sys::Number
109    js_sys::Object
110    js_sys::Promise
111    js_sys::Proxy
112    js_sys::RangeError
113    js_sys::ReferenceError
114    js_sys::RegExp
115    js_sys::Set
116    js_sys::SharedArrayBuffer
117    js_sys::Symbol
118    js_sys::SyntaxError
119    js_sys::TypeError
120    js_sys::Uint8Array
121    js_sys::Uint8ClampedArray
122    js_sys::Uint16Array
123    js_sys::Uint32Array
124    js_sys::UriError
125    js_sys::WeakMap
126    js_sys::WeakSet
127}
128
129impl_to_js! {
130    deref_copy:
131    &str
132    // numbers https://docs.rs/wasm-bindgen/0.2.78/src/wasm_bindgen/lib.rs.html#849
133    i8 u8 i16 u16 i32 u32 f32 f64
134    // big_numbers https://docs.rs/wasm-bindgen/0.2.78/src/wasm_bindgen/lib.rs.html#869
135    i64 u64 i128 u128 isize usize
136    bool
137}
138
139impl<T: ToJs> ToJs for &T {
140    fn to_js(&self) -> JsValue {
141        (*self).to_js()
142    }
143}
144
145macro_rules! impl_js_for_iter {
146    ($($t:tt)+) => {
147        $($t)+ {
148            #[inline]
149            fn to_js(&self) -> JsValue {
150                js_sys::Array::from_iter(self.iter().map(|v| v.to_js())).into()
151            }
152        }
153    };
154}
155
156impl_js_for_iter! { impl<T: ToJs> ToJs for Vec<T> }
157impl_js_for_iter! { impl<T: ToJs> ToJs for &[T] }
158impl_js_for_iter! { impl<N: ToJs, const S: usize> ToJs for [N; S] }
159
160macro_rules! impl_js_for_tuple {
161    (@impl $arr_method:ident ( $($t:ident),+ $(,)? )) => {
162        impl<$($t: ToJs),+> ToJs for ($($t),+ ,) {
163            #[inline]
164            fn to_js(&self) -> JsValue {
165                #![allow(non_snake_case)]
166                let ($($t),+ ,) = self;
167                js_sys::Array::$arr_method(
168                    $(&$t.to_js()),+
169                ).into()
170            }
171        }
172    };
173    (@impl ( $($t:ident),+ $(,)? )) => {
174        impl<$($t: ToJs),+> ToJs for ($($t),+ ,) {
175            #[inline]
176            fn to_js(&self) -> JsValue {
177                #![allow(non_snake_case)]
178                let ($($t),+ ,) = self;
179                js_sys::Array::from_iter([
180                    $($t.to_js()),+
181                ]).into()
182            }
183        }
184    };
185    ( $( $($arr_method:ident)? ( $($t:ident),+ $(,)? ) )* ) => {
186        $(
187            impl_js_for_tuple! { @impl $($arr_method)? ($($t),+ ,) }
188        )*
189    };
190}
191
192impl_js_for_tuple! {
193    of1(T0,)
194    of2(T0,T1)
195    of3(T0,T1,T2)
196    of4(T0,T1,T2,T3)
197    of5(T0,T1,T2,T3,T4)
198    (T0,T1,T2,T3,T4,T5)
199    (T0,T1,T2,T3,T4,T5,T6)
200    (T0,T1,T2,T3,T4,T5,T6,T7)
201    (T0,T1,T2,T3,T4,T5,T6,T7,T8)
202    (T0,T1,T2,T3,T4,T5,T6,T7,T8,T9)
203}
204
205impl<T: ToJs> ToJs for Box<T> {
206    #[inline]
207    fn to_js(&self) -> JsValue {
208        self.as_ref().to_js()
209    }
210}
211
212impl ToJs for () {
213    fn to_js(&self) -> JsValue {
214        JsValue::UNDEFINED
215    }
216}
217
218impl ToJs for JsValue {
219    fn to_js(&self) -> JsValue {
220        self.clone()
221    }
222}
223
224impl<T: ?Sized> ToJs for wasm_bindgen::prelude::Closure<T> {
225    /// Note: unlike [`Closure::into_js_value`]
226    /// after calling `closure.to_js`,
227    /// the closure is not forgotten by rust memory.
228    /// You should make sure it lives long enough to be called in js.
229    ///
230    /// [`Closure::into_js_value`]: https://docs.rs/wasm-bindgen/0.2.78/wasm_bindgen/closure/struct.Closure.html#method.into_js_value
231    fn to_js(&self) -> JsValue {
232        AsRef::<JsValue>::as_ref(&self).clone()
233    }
234}