shopify_function_wasm_api/
read.rs

1//! The read API for the Shopify Function Wasm API.
2//!
3//! This consists primarily of the `Deserialize` trait for converting [`Value`] into other types.
4
5use crate::Value;
6use std::collections::{BTreeMap, HashMap};
7
8/// An error that can occur when deserializing a value.
9#[derive(Debug, thiserror::Error)]
10#[non_exhaustive]
11pub enum Error {
12    /// The value is not of the expected type.
13    #[error("Invalid type")]
14    InvalidType,
15}
16
17/// A trait for types that can be deserialized from a [`Value`].
18///
19/// # Example
20/// ```rust
21/// use shopify_function_wasm_api::{Context, Deserialize, Value, read::Error};
22///
23/// #[derive(Debug, PartialEq)]
24/// struct MyStruct {
25///     value: i32,
26/// }
27///
28/// impl Deserialize for MyStruct {
29///     fn deserialize(value: &Value) -> Result<Self, Error> {
30///         if !value.is_obj() {
31///             return Err(Error::InvalidType);
32///         }
33///         let value = i32::deserialize(&value.get_obj_prop("value"))?;
34///         Ok(MyStruct { value })
35///     }
36/// }
37///
38/// let context = Context::new_with_input(serde_json::json!({ "value": 1 }));
39/// let value = context.input_get().unwrap();
40/// let my_struct = MyStruct::deserialize(&value).unwrap();
41/// assert_eq!(my_struct, MyStruct { value: 1 });
42/// ```
43pub trait Deserialize: Sized {
44    /// Deserialize a value from a [`Value`].
45    fn deserialize(value: &Value) -> Result<Self, Error>;
46}
47
48impl Deserialize for Value {
49    fn deserialize(value: &Value) -> Result<Self, Error> {
50        Ok(*value)
51    }
52}
53
54impl Deserialize for () {
55    fn deserialize(value: &Value) -> Result<Self, Error> {
56        if value.is_null() {
57            Ok(())
58        } else {
59            Err(Error::InvalidType)
60        }
61    }
62}
63
64impl Deserialize for bool {
65    fn deserialize(value: &Value) -> Result<Self, Error> {
66        value.as_bool().ok_or(Error::InvalidType)
67    }
68}
69
70macro_rules! impl_deserialize_for_int {
71    ($ty:ty) => {
72        impl Deserialize for $ty {
73            fn deserialize(value: &Value) -> Result<Self, Error> {
74                value
75                    .as_number()
76                    .and_then(|n| {
77                        if n.trunc() == n && n >= <$ty>::MIN as f64 && n <= <$ty>::MAX as f64 {
78                            Some(n as $ty)
79                        } else {
80                            None
81                        }
82                    })
83                    .ok_or(Error::InvalidType)
84            }
85        }
86    };
87}
88
89impl_deserialize_for_int!(i8);
90impl_deserialize_for_int!(i16);
91impl_deserialize_for_int!(i32);
92impl_deserialize_for_int!(i64);
93impl_deserialize_for_int!(u8);
94impl_deserialize_for_int!(u16);
95impl_deserialize_for_int!(u32);
96impl_deserialize_for_int!(u64);
97impl_deserialize_for_int!(usize);
98impl_deserialize_for_int!(isize);
99
100impl Deserialize for f64 {
101    fn deserialize(value: &Value) -> Result<Self, Error> {
102        value.as_number().ok_or(Error::InvalidType)
103    }
104}
105
106impl Deserialize for String {
107    fn deserialize(value: &Value) -> Result<Self, Error> {
108        value.as_string().ok_or(Error::InvalidType)
109    }
110}
111
112impl Deserialize for char {
113    fn deserialize(value: &Value) -> Result<Self, Error> {
114        let s = value.as_string().ok_or(Error::InvalidType)?;
115        let mut chars = s.chars();
116        match (chars.next(), chars.next()) {
117            (Some(c), None) => Ok(c),
118            _ => Err(Error::InvalidType),
119        }
120    }
121}
122
123impl<T: Deserialize> Deserialize for Option<T> {
124    fn deserialize(value: &Value) -> Result<Self, Error> {
125        if value.is_null() {
126            Ok(None)
127        } else {
128            Ok(Some(T::deserialize(value)?))
129        }
130    }
131}
132
133impl<T: Deserialize> Deserialize for Vec<T> {
134    fn deserialize(value: &Value) -> Result<Self, Error> {
135        if let Some(len) = value.array_len() {
136            let mut vec = Vec::with_capacity(len);
137            for i in 0..len {
138                vec.push(T::deserialize(&value.get_at_index(i))?);
139            }
140            Ok(vec)
141        } else {
142            Err(Error::InvalidType)
143        }
144    }
145}
146
147impl<T: Deserialize> Deserialize for HashMap<String, T> {
148    fn deserialize(value: &Value) -> Result<Self, Error> {
149        let Some(obj_len) = value.obj_len() else {
150            return Err(Error::InvalidType);
151        };
152
153        let mut map = HashMap::new();
154
155        for i in 0..obj_len {
156            let key = value.get_obj_key_at_index(i).ok_or(Error::InvalidType)?;
157            let value = value.get_at_index(i);
158            map.insert(key, T::deserialize(&value)?);
159        }
160
161        Ok(map)
162    }
163}
164
165impl<T: Deserialize> Deserialize for BTreeMap<String, T> {
166    fn deserialize(value: &Value) -> Result<Self, Error> {
167        let Some(obj_len) = value.obj_len() else {
168            return Err(Error::InvalidType);
169        };
170
171        let mut map = BTreeMap::new();
172
173        for i in 0..obj_len {
174            let key = value.get_obj_key_at_index(i).ok_or(Error::InvalidType)?;
175            let value = value.get_at_index(i);
176            map.insert(key, T::deserialize(&value)?);
177        }
178
179        Ok(map)
180    }
181}
182
183macro_rules! impl_deserialize_tuple {
184    ($n:literal) => {
185        seq_macro::seq!(N in 0..$n {
186            impl<#(T~N: Deserialize,)*> Deserialize for (#(T~N,)*) {
187                fn deserialize(value: &Value) -> Result<Self, Error> {
188                    let Some(len) = value.array_len() else {
189                        return Err(Error::InvalidType);
190                    };
191
192                    if len != $n {
193                        return Err(Error::InvalidType);
194                    }
195
196                    Ok((#(T~N::deserialize(&value.get_at_index(N))?,)*))
197                }
198            }
199        });
200    }
201}
202
203seq_macro::seq!(N in 2..=10 {
204    impl_deserialize_tuple!(N);
205});
206
207macro_rules! impl_deserialize_array {
208    ($n:literal) => {
209        impl<T: Deserialize> Deserialize for [T; $n] {
210            fn deserialize(value: &Value) -> Result<Self, Error> {
211                let Some(len) = value.array_len() else {
212                    return Err(Error::InvalidType);
213                };
214
215                if len != $n {
216                    return Err(Error::InvalidType);
217                }
218
219                seq_macro::seq!(N in 0..$n {
220                    Ok([#(T::deserialize(&value.get_at_index(N))?,)*])
221                })
222            }
223        }
224    };
225}
226
227seq_macro::seq!(N in 0..=32 {
228    impl_deserialize_array!(N);
229});
230
231#[cfg(test)]
232mod tests {
233    use super::*;
234    use crate::Context;
235
236    fn deserialize_json_value<T: Deserialize>(value: serde_json::Value) -> Result<T, Error> {
237        let context = Context::new_with_input(value);
238        let value = context.input_get().unwrap();
239        T::deserialize(&value)
240    }
241
242    #[test]
243    fn test_deserialize_bool() {
244        [true, false].iter().for_each(|&b| {
245            let value = serde_json::json!(b);
246            let result: bool = deserialize_json_value(value).unwrap();
247            assert_eq!(result, b);
248        });
249    }
250
251    macro_rules! test_deserialize_int {
252        ($ty:ty) => {
253            paste::paste! {
254                #[test]
255                fn [<test_deserialize_ $ty>]() {
256                    [$ty::MIN, 0 as $ty, $ty::MAX].iter().for_each(|&n| {
257                        let value = serde_json::json!(n);
258                        let result: $ty = deserialize_json_value(value).unwrap();
259                        assert_eq!(result, n);
260                    });
261                }
262            }
263        };
264    }
265
266    test_deserialize_int!(i8);
267    test_deserialize_int!(i16);
268    test_deserialize_int!(i32);
269    test_deserialize_int!(i64);
270    test_deserialize_int!(u8);
271    test_deserialize_int!(u16);
272    test_deserialize_int!(u32);
273    test_deserialize_int!(u64);
274    test_deserialize_int!(usize);
275    test_deserialize_int!(isize);
276
277    #[test]
278    fn test_deserialize_f64() {
279        let value = serde_json::json!(1.0);
280        let result: f64 = deserialize_json_value(value).unwrap();
281        assert_eq!(result, 1.0);
282    }
283
284    #[test]
285    fn test_deserialize_string() {
286        let value = serde_json::json!("test");
287        let result: String = deserialize_json_value(value).unwrap();
288        assert_eq!(result, "test");
289    }
290
291    #[test]
292    fn test_deserialize_char() {
293        let value = serde_json::json!("a");
294        let result: char = deserialize_json_value(value).unwrap();
295        assert_eq!(result, 'a');
296
297        // Test invalid cases
298        let value = serde_json::json!("ab");
299        assert!(deserialize_json_value::<char>(value).is_err());
300
301        let value = serde_json::json!("");
302        assert!(deserialize_json_value::<char>(value).is_err());
303    }
304
305    #[test]
306    fn test_deserialize_option() {
307        [None, Some(1), Some(2)].iter().for_each(|&opt| {
308            let value = serde_json::json!(opt);
309            let result: Option<i32> = deserialize_json_value(value).unwrap();
310            assert_eq!(result, opt);
311        });
312    }
313
314    #[test]
315    fn test_deserialize_vec() {
316        let value = serde_json::json!([1, 2, 3]);
317        let result: Vec<i32> = deserialize_json_value(value).unwrap();
318        assert_eq!(result, vec![1, 2, 3]);
319    }
320
321    #[test]
322    fn test_deserialize_hash_map() {
323        let value = serde_json::json!({
324            "key1": "value1",
325            "key2": "value2",
326        });
327        let result: HashMap<String, String> = deserialize_json_value(value).unwrap();
328        let expected = HashMap::from([
329            ("key1".to_string(), "value1".to_string()),
330            ("key2".to_string(), "value2".to_string()),
331        ]);
332        assert_eq!(result, expected);
333    }
334
335    #[test]
336    fn test_deserialize_btree_map() {
337        let value = serde_json::json!({
338            "key1": "value1",
339            "key2": "value2",
340        });
341        let result: BTreeMap<String, String> = deserialize_json_value(value).unwrap();
342        let expected = BTreeMap::from([
343            ("key1".to_string(), "value1".to_string()),
344            ("key2".to_string(), "value2".to_string()),
345        ]);
346        assert_eq!(result, expected);
347    }
348
349    #[test]
350    fn test_deserialize_unit() {
351        let value = serde_json::json!(null);
352        deserialize_json_value::<()>(value).unwrap();
353    }
354
355    #[test]
356    fn test_deserialize_tuple() {
357        let value = serde_json::json!([1, 2, 3]);
358        let result: (i32, i32, i32) = deserialize_json_value(value).unwrap();
359        assert_eq!(result, (1, 2, 3));
360    }
361
362    #[test]
363    fn test_deserialize_fixed_array() {
364        let value = serde_json::json!([1, 2, 3]);
365        let result: [i32; 3] = deserialize_json_value(value).unwrap();
366        assert_eq!(result, [1, 2, 3]);
367
368        // Test wrong size
369        let value = serde_json::json!([1, 2]);
370        assert!(deserialize_json_value::<[i32; 3]>(value).is_err());
371
372        let value = serde_json::json!([1, 2, 3, 4]);
373        assert!(deserialize_json_value::<[i32; 3]>(value).is_err());
374
375        // Test edge cases
376        let value = serde_json::json!([]);
377        let result: [i32; 0] = deserialize_json_value(value).unwrap();
378        assert_eq!(result, [] as [i32; 0]);
379
380        let value = serde_json::json!([42]);
381        let result: [i32; 1] = deserialize_json_value(value).unwrap();
382        assert_eq!(result, [42]);
383
384        // Test larger array
385        let value = serde_json::json!([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
386        let result: [i32; 10] = deserialize_json_value(value).unwrap();
387        assert_eq!(result, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
388    }
389}