Skip to main content

wasm_bindgen_derive/
helpers.rs

1use alloc::format;
2use alloc::string::String;
3use alloc::vec::Vec;
4
5use wasm_bindgen::{JsCast, JsValue};
6
7/// Converts the given optional typed value into a JS value with the custom type `T`.
8///
9/// The type `T` would be defined in an `extern "C"` block, e.g.
10/// ```
11/// use wasm_bindgen::prelude::wasm_bindgen;
12/// #[wasm_bindgen]
13/// extern "C" {
14/// #[wasm_bindgen(typescript_type = "MyType | undefined")]
15///     pub type OptionMyType; // <-- this would be `T`
16/// }
17/// ```
18///
19/// If the typed value is `None`, the result is JS `underfined`.
20pub fn into_js_option<T, U>(val: Option<U>) -> T
21where
22    JsValue: From<U>,
23    T: JsCast,
24{
25    let js_val = match val {
26        None => JsValue::UNDEFINED,
27        Some(val) => val.into(),
28    };
29    js_val.unchecked_into::<T>()
30}
31
32/// Attempts to unpack a JS value into a typed value,
33/// returning `None` if the JS value is `undefined`.
34pub fn try_from_js_option<T>(val: impl Into<JsValue>) -> Result<Option<T>, String>
35where
36    for<'a> T: TryFrom<&'a JsValue>,
37    for<'a> <T as TryFrom<&'a JsValue>>::Error: core::fmt::Display,
38{
39    let js_val = val.into();
40    if js_val.is_undefined() {
41        return Ok(None);
42    }
43    T::try_from(&js_val)
44        .map(Some)
45        .map_err(|err| format!("{}", err))
46}
47
48/// Converts the given iterator into a JS array of the custom type `T`.
49///
50/// The type `T` would be defined in an `extern "C"` block, e.g.
51/// ```
52/// use wasm_bindgen::prelude::wasm_bindgen;
53/// #[wasm_bindgen]
54/// extern "C" {
55///     #[wasm_bindgen(typescript_type = "MyType[]")]
56///     pub type MyTypeArray; // <-- this would be `T`
57/// }
58/// ```
59pub fn into_js_array<T, U>(value: impl IntoIterator<Item = U>) -> T
60where
61    JsValue: From<U>,
62    T: JsCast,
63{
64    value
65        .into_iter()
66        .map(JsValue::from)
67        .collect::<js_sys::Array>()
68        .unchecked_into::<T>()
69}
70
71/// Attempts to unpack a JS array into a vector of typed values.
72pub fn try_from_js_array<T>(val: impl Into<JsValue>) -> Result<Vec<T>, String>
73where
74    for<'a> T: TryFrom<&'a JsValue>,
75    for<'a> <T as TryFrom<&'a JsValue>>::Error: core::fmt::Display,
76{
77    let js_val = val.into();
78    let array: &js_sys::Array = js_val.dyn_ref().ok_or("The argument must be an array")?;
79    let length: usize = array
80        .length()
81        .try_into()
82        .map_err(|err| format!("{}", err))?;
83    let mut typed_array = Vec::<T>::with_capacity(length);
84    for (idx, js) in array.iter().enumerate() {
85        let typed_elem =
86            T::try_from(&js).map_err(|err| format!("Failed to cast item {}: {}", idx, err))?;
87        typed_array.push(typed_elem);
88    }
89    Ok(typed_array)
90}