workflow_wasm/extensions/
object.rs

1//!
2//! Js [`Object`] property access utilities
3//!
4
5use crate::convert::*;
6use crate::error::Error;
7use crate::extensions::jsvalue::JsValueExtension;
8use crate::utils::*;
9use js_sys::{Object, Reflect};
10use wasm_bindgen::prelude::*;
11
12/// Custom trait implementing simplified property accessor functions for [`Object`].
13pub trait ObjectExtension {
14    /// Get a type that implements [`TryFrom<JsValue>`] from a property of the [`Object`].
15    fn get<T>(&self, prop: &str) -> Result<T, Error>
16    where
17        T: TryFrom<JsValue>,
18        <T as TryFrom<wasm_bindgen::JsValue>>::Error: std::fmt::Display;
19
20    /// Try to get a type that implements [`TryFrom<JsValue>`] from a property of the [`Object`].
21    /// Returns `Ok(None)` if the property does not exist.
22    fn try_get<T>(&self, prop: &str) -> Result<Option<T>, Error>
23    where
24        T: TryFrom<JsValue>,
25        <T as TryFrom<wasm_bindgen::JsValue>>::Error: std::fmt::Display;
26
27    /// Obtain a [`Cast`] from a property of the [`Object`].
28    fn cast_into<T>(&self, prop: &str) -> Result<T, Error>
29    where
30        T: TryCastFromJs,
31        <T as TryCastFromJs>::Error: std::fmt::Display;
32
33    fn cast_from<T>(&self, prop: &str) -> Result<Cast<'static, T>, Error>
34    where
35        T: TryCastFromJs,
36        <T as TryCastFromJs>::Error: std::fmt::Display;
37
38    /// Try to obtain a [`Cast`] from a property of the [`Object`].
39    /// Returns `Ok(None)` if the property does not exist (`null` or `undefined`).
40    fn try_cast_into<T>(&self, prop: &str) -> Result<Option<T>, Error>
41    where
42        T: TryCastFromJs,
43        <T as TryCastFromJs>::Error: std::fmt::Display;
44
45    fn try_cast_from<T>(&self, prop: &str) -> Result<Option<Cast<'static, T>>, Error>
46    where
47        T: TryCastFromJs,
48        <T as TryCastFromJs>::Error: std::fmt::Display;
49
50    /// Get `JsValue` property
51    fn get_value(&self, prop: &str) -> Result<JsValue, Error>;
52    /// Get `Object` property
53    fn get_object(&self, prop: &str) -> Result<Object, Error>;
54    /// Get `Object` property
55    fn try_get_object(&self, prop: &str) -> Result<Option<Object>, Error>;
56    /// Try Get `JsValue` property
57    fn try_get_value(&self, prop: &str) -> Result<Option<JsValue>, Error>;
58    /// get `String` property
59    fn get_string(&self, prop: &str) -> Result<String, Error>;
60    /// get `String` property
61    fn try_get_string(&self, prop: &str) -> Result<Option<String>, Error>;
62    /// get `Number` property as `u8`
63    fn get_u8(&self, prop: &str) -> Result<u8, Error>;
64    /// get `Number` property as `u16`
65    fn get_u16(&self, prop: &str) -> Result<u16, Error>;
66    /// get `Number` property as `u32`
67    fn get_u32(&self, prop: &str) -> Result<u32, Error>;
68    /// get `Number` property as `u64`
69    fn get_u64(&self, prop: &str) -> Result<u64, Error>;
70    /// get `Number` property as `f64`
71    fn get_f64(&self, prop: &str) -> Result<f64, Error>;
72    /// get `Boolean` property as `bool`
73    fn get_bool(&self, prop: &str) -> Result<bool, Error>;
74    fn try_get_bool(&self, prop: &str) -> Result<Option<bool>, Error>;
75    /// get property as `Vec<JsValue>`
76    fn get_vec(&self, prop: &str) -> Result<Vec<JsValue>, Error>;
77    /// get `Vec<u8>` property from a hex string or an `Array`
78    fn get_vec_u8(&self, prop: &str) -> Result<Vec<u8>, Error>;
79    /// get `Uint8Array` property as `Vec<u8>`
80    fn get_vec_u8_from_number_array(&self, prop: &str) -> Result<Vec<u8>, Error>;
81    /// get `Uint8Array` property as `Vec<u8>`
82    fn get_vec_u8_from_uint8_array(&self, prop: &str) -> Result<Vec<u8>, Error>;
83    /// set `JsValue` property
84    fn set(&self, prop: &str, value: &JsValue) -> Result<bool, Error>;
85    /// set `Array` property from `&[JsValue]`
86    fn set_vec(&self, prop: &str, values: &[JsValue]) -> Result<bool, Error>;
87    /// set multiple `JsValue` properties
88    fn set_properties(&self, props: &[(&str, &JsValue)]) -> Result<(), Error>;
89    /// delete property
90    fn delete(&self, prop: &str) -> Result<bool, Error>;
91}
92
93impl ObjectExtension for Object {
94    fn get<T>(&self, prop: &str) -> Result<T, Error>
95    where
96        T: TryFrom<JsValue>,
97        <T as TryFrom<wasm_bindgen::JsValue>>::Error: std::fmt::Display,
98    {
99        let js_value = Reflect::get(self, &JsValue::from(prop))?;
100        T::try_from(js_value).map_err(Error::custom)
101    }
102
103    fn try_get<T>(&self, prop: &str) -> Result<Option<T>, Error>
104    where
105        T: TryFrom<JsValue>,
106        <T as TryFrom<wasm_bindgen::JsValue>>::Error: std::fmt::Display,
107    {
108        let js_value = Reflect::get(self, &JsValue::from(prop))?;
109        if js_value.is_undefined() {
110            Ok(None)
111        } else {
112            Ok(Some(T::try_from(js_value).map_err(Error::custom)?))
113        }
114    }
115
116    fn cast_into<T>(&self, prop: &str) -> Result<T, Error>
117    where
118        T: TryCastFromJs,
119        <T as TryCastFromJs>::Error: std::fmt::Display,
120    {
121        let js_value = Reflect::get(self, &JsValue::from(prop))?;
122        T::try_owned_from(&js_value).map_err(Error::custom)
123    }
124
125    fn cast_from<T>(&self, prop: &str) -> Result<Cast<'static, T>, Error>
126    where
127        T: TryCastFromJs,
128        <T as TryCastFromJs>::Error: std::fmt::Display,
129    {
130        let js_value = Reflect::get(self, &JsValue::from(prop))?;
131        T::try_captured_cast_from(&js_value).map_err(Error::custom)
132    }
133
134    fn try_cast_into<T>(&self, prop: &str) -> Result<Option<T>, Error>
135    where
136        T: TryCastFromJs,
137        <T as TryCastFromJs>::Error: std::fmt::Display,
138    {
139        let js_value = Reflect::get(self, &JsValue::from(prop))?;
140        if js_value.is_undefined() {
141            Ok(None)
142        } else {
143            Ok(Some(T::try_owned_from(js_value).map_err(Error::custom)?))
144        }
145    }
146
147    fn try_cast_from<T>(&self, prop: &str) -> Result<Option<Cast<'static, T>>, Error>
148    where
149        T: TryCastFromJs,
150        <T as TryCastFromJs>::Error: std::fmt::Display,
151    {
152        let js_value = Reflect::get(self, &JsValue::from(prop))?;
153        if js_value.is_undefined() {
154            Ok(None)
155        } else {
156            Ok(Some(
157                T::try_captured_cast_from(js_value).map_err(Error::custom)?,
158            ))
159        }
160    }
161
162    fn get_value(&self, prop: &str) -> Result<JsValue, Error> {
163        Ok(Reflect::get(self, &JsValue::from(prop))?)
164    }
165
166    fn get_object(&self, prop: &str) -> Result<Object, Error> {
167        let value = Reflect::get(self, &JsValue::from(prop))?;
168        let object = Object::try_from(&value).ok_or(Error::MissingProperty(prop.to_string()))?;
169        Ok(object.clone())
170    }
171
172    fn try_get_object(&self, prop: &str) -> Result<Option<Object>, Error> {
173        let value = Reflect::get(self, &JsValue::from(prop))?;
174        Ok(Object::try_from(&value).cloned())
175    }
176
177    fn try_get_value(&self, prop: &str) -> Result<Option<JsValue>, Error> {
178        let js_value = Reflect::get(self, &JsValue::from(prop))?;
179        if js_value == JsValue::UNDEFINED {
180            Ok(None)
181        } else {
182            Ok(Some(js_value))
183        }
184    }
185
186    fn get_string(&self, prop: &str) -> Result<String, Error> {
187        try_get_string_from_prop(self, prop)
188    }
189
190    fn try_get_string(&self, prop: &str) -> Result<Option<String>, Error> {
191        Ok(self.get_value(prop)?.as_string())
192    }
193
194    fn get_bool(&self, prop: &str) -> Result<bool, Error> {
195        try_get_bool_from_prop(self, prop)
196    }
197
198    fn try_get_bool(&self, prop: &str) -> Result<Option<bool>, Error> {
199        Ok(self.get_value(prop)?.as_bool())
200    }
201
202    fn get_u8(&self, prop: &str) -> Result<u8, Error> {
203        try_get_u8_from_prop(self, prop)
204    }
205
206    fn get_u16(&self, prop: &str) -> Result<u16, Error> {
207        try_get_u16_from_prop(self, prop)
208    }
209
210    fn get_u32(&self, prop: &str) -> Result<u32, Error> {
211        try_get_u32_from_prop(self, prop)
212    }
213
214    fn get_u64(&self, prop: &str) -> Result<u64, Error> {
215        try_get_u64_from_prop(self, prop)
216    }
217
218    fn get_vec(&self, prop: &str) -> Result<Vec<JsValue>, Error> {
219        try_get_vec_from_prop(self, prop)
220    }
221
222    fn get_vec_u8(&self, prop: &str) -> Result<Vec<u8>, Error> {
223        let v = Reflect::get(self, &JsValue::from(prop))?;
224        v.try_as_vec_u8()
225    }
226
227    fn get_vec_u8_from_number_array(&self, prop: &str) -> Result<Vec<u8>, Error> {
228        try_get_vec_u8_from_number_array_prop(self, prop)
229    }
230
231    fn get_vec_u8_from_uint8_array(&self, prop: &str) -> Result<Vec<u8>, Error> {
232        try_get_vec_u8_from_uint8_array_prop(self, prop)
233    }
234
235    fn get_f64(&self, prop: &str) -> Result<f64, Error> {
236        try_get_f64_from_prop(self, prop)
237    }
238
239    fn set(&self, prop: &str, value: &JsValue) -> Result<bool, Error> {
240        Ok(Reflect::set(self, &JsValue::from(prop), value)?)
241    }
242
243    fn set_vec(&self, prop: &str, values: &[JsValue]) -> Result<bool, Error> {
244        let array = js_sys::Array::new();
245        for v in values {
246            array.push(v);
247        }
248        Ok(Reflect::set(self, &JsValue::from(prop), &array)?)
249    }
250
251    fn set_properties(&self, props: &[(&str, &JsValue)]) -> Result<(), Error> {
252        for (k, v) in props.iter() {
253            Reflect::set(self, &JsValue::from(*k), v)?;
254        }
255        Ok(())
256    }
257
258    fn delete(&self, prop: &str) -> Result<bool, Error> {
259        Ok(Reflect::delete_property(self, &JsValue::from(prop))?)
260    }
261}