facet_json_read/
deserialize.rs

1use std::num::NonZero;
2
3use crate::parser::{JsonParseErrorKind, JsonParseErrorWithContext, JsonParser};
4
5use facet_core::{Facet, Opaque, OpaqueUninit};
6use facet_poke::{Poke, PokeValue};
7use log::trace;
8
9/// Deserializes a JSON string into a value of type `T` that implements `Facet`.
10///
11/// This function takes a JSON string representation and converts it into a Rust
12/// value of the specified type `T`. The type must implement the `Facet` trait
13/// to provide the necessary type information for deserialization.
14///
15/// # Parameters
16/// * `json` - A string slice containing the JSON to deserialize
17///
18/// # Returns
19/// * `Ok(T)` - The successfully deserialized value
20/// * `Err(JsonParseErrorWithContext)` - An error with context if deserialization fails
21///
22/// # Example
23/// ```
24/// # use facet_core::Facet;
25/// # use facet_derive::Facet;
26/// # use facet_core as facet;
27/// # #[derive(Facet)]
28/// # struct Person { name: String, age: u64 }
29/// let json = r#"{"name":"Alice","age":30}"#;
30/// let person: Person = facet_json_read::from_str(json).unwrap();
31/// ```
32pub fn from_str<T: Facet>(json: &str) -> Result<T, JsonParseErrorWithContext<'_>> {
33    let (poke, _guard) = Poke::alloc::<T>();
34    let opaque = from_str_opaque(poke, json)?;
35    Ok(unsafe { opaque.read::<T>() })
36}
37
38/// Deserialize a `Poke` object from a JSON string.
39pub fn from_str_opaque<'input, 'mem>(
40    poke: Poke<'mem>,
41    json: &'input str,
42) -> Result<Opaque<'mem>, JsonParseErrorWithContext<'input>> {
43    trace!("Starting JSON deserialization");
44    let mut parser = JsonParser::new(json);
45    deserialize_value(&mut parser, poke)
46}
47
48macro_rules! int {
49    ($parser:expr, $parsed:expr, $pv:expr, $type:ty) => {
50        if $pv.shape().is_type::<$type>() {
51            let n = <$type>::try_from($parsed?).map_err(|e| {
52                $parser.make_error(JsonParseErrorKind::Custom(format!(
53                    "Invalid value for {}: {e}",
54                    stringify!($type)
55                )))
56            })?;
57            return Ok($pv.put(n));
58        }
59
60        if $pv.shape().is_type::<NonZero<$type>>() {
61            let n = <$type>::try_from($parsed?).map_err(|e| {
62                $parser.make_error(JsonParseErrorKind::Custom(format!(
63                    "Invalid value for core::num::NonZero<{}>: {e}",
64                    stringify!($type)
65                )))
66            })?;
67            let n = NonZero::new(n).ok_or_else(|| {
68                $parser.make_error(JsonParseErrorKind::Custom(format!(
69                    "Can't deserialize zero to core::num::NonZero<{}>",
70                    stringify!($type)
71                )))
72            })?;
73
74            return Ok($pv.put(n));
75        }
76    };
77}
78
79macro_rules! unsigneds {
80    ($parser:expr, $pv:expr, $type:ty, $($types:ty),*) => {
81        int!($parser, $parser.parse_u64(), $pv, $type);
82        unsigneds!($parser, $pv, $($types),*);
83    };
84    ($parser:expr, $pv:expr, $type:ty) => {
85        int!($parser, $parser.parse_u64(), $pv, $type);
86    };
87}
88
89macro_rules! signeds {
90    ($parser:expr, $pv:expr, $type:ty, $($types:ty),*) => {
91        int!($parser, $parser.parse_i64(), $pv, $type);
92        signeds!($parser, $pv, $($types),*);
93    };
94    ($parser:expr, $pv:expr, $type:ty) => {
95        int!($parser, $parser.parse_i64(), $pv, $type);
96    };
97}
98
99/// Deserializes a value from JSON using an iterative approach.
100///
101/// This function takes a JSON parser and a Poke object and deserializes the JSON
102/// into the Poke object. It uses an iterative approach with a stack to avoid
103/// recursion.
104fn deserialize_value<'input, 'mem>(
105    parser: &mut JsonParser<'input>,
106    root_poke: Poke<'mem>,
107) -> Result<Opaque<'mem>, JsonParseErrorWithContext<'input>> {
108    use std::collections::VecDeque;
109
110    enum StackItem<'mem> {
111        Value {
112            poke: Poke<'mem>,
113        },
114        FinishStruct {
115            ps: facet_poke::PokeStruct<'mem>,
116        },
117        StructField {
118            key: String,
119        },
120        AfterStructField {
121            index: usize,
122        },
123        FinishList {
124            pl: facet_poke::PokeList<'mem>,
125        },
126        AfterListItem {
127            item: OpaqueUninit<'mem>,
128        },
129        FinishMap {
130            pm: facet_poke::PokeMap<'mem>,
131        },
132        AfterMapValue {
133            key: String,
134            value: OpaqueUninit<'mem>,
135        },
136    }
137
138    let mut result = None;
139    let mut stack = VecDeque::new();
140    stack.push_back(StackItem::Value { poke: root_poke });
141
142    while let Some(item) = stack.pop_front() {
143        match item {
144            StackItem::Value { poke } => {
145                let shape = poke.shape();
146                trace!("Deserializing {shape}");
147
148                match poke {
149                    Poke::Scalar(pv) => {
150                        trace!("Deserializing \x1b[1;36mscalar\x1b[0m");
151                        fn aux<'input, 'mem>(
152                            parser: &mut JsonParser<'input>,
153                            pv: PokeValue<'mem>,
154                        ) -> Result<Opaque<'mem>, JsonParseErrorWithContext<'input>>
155                        {
156                            if pv.shape().is_type::<String>() {
157                                let s = parser.parse_string()?;
158                                let data = pv.put(s);
159                                return Ok(data);
160                            }
161                            if pv.shape().is_type::<bool>() {
162                                let b = parser.parse_bool()?;
163                                return Ok(pv.put(b));
164                            }
165                            if pv.shape().is_type::<f32>() {
166                                let n = parser.parse_f64()? as f32;
167                                return Ok(pv.put(n));
168                            }
169                            if pv.shape().is_type::<f64>() {
170                                let n = parser.parse_f64()?;
171                                return Ok(pv.put(n));
172                            }
173
174                            unsigneds!(parser, pv, u8, u16, u32, u64, u128, usize);
175                            signeds!(parser, pv, i8, i16, i32, i64, i128, isize);
176
177                            panic!("Unknown scalar shape: {}", pv.shape());
178                        }
179
180                        result = Some(aux(parser, pv)?);
181                    }
182                    Poke::Struct(ps) => {
183                        trace!("Deserializing \x1b[1;36mstruct\x1b[0m");
184                        stack.push_front(StackItem::FinishStruct { ps });
185
186                        let first_key = parser.expect_object_start()?;
187                        if let Some(key) = first_key {
188                            stack.push_front(StackItem::StructField { key });
189                        }
190                    }
191                    Poke::List(list_uninit) => {
192                        trace!("Deserializing \x1b[1;36marray\x1b[0m");
193                        parser.expect_array_start()?;
194
195                        let pl = list_uninit.init(None).unwrap_or_else(|_| {
196                            panic!("Failed to initialize list");
197                        });
198
199                        let has_element = parser.parse_array_element()?;
200
201                        if let Some(true) = has_element {
202                            let item_shape = pl.def().t;
203                            let item_data =
204                                OpaqueUninit::new(unsafe { std::alloc::alloc(item_shape.layout) });
205                            let item_poke = unsafe { Poke::unchecked_new(item_data, item_shape) };
206
207                            stack.push_front(StackItem::FinishList { pl });
208                            stack.push_front(StackItem::AfterListItem { item: item_data });
209                            stack.push_front(StackItem::Value { poke: item_poke });
210                        } else {
211                            stack.push_front(StackItem::FinishList { pl });
212                        }
213                    }
214                    Poke::Map(map_uninit) => {
215                        trace!("Deserializing \x1b[1;36mhashmap\x1b[0m");
216                        let first_key = parser.expect_object_start()?;
217
218                        let pm = map_uninit.init(None).unwrap_or_else(|_| {
219                            panic!("Failed to initialize map"); // TODO: map errors
220                        });
221
222                        if let Some(key) = first_key {
223                            let value_shape = pm.def().v;
224                            let value_data =
225                                OpaqueUninit::new(unsafe { std::alloc::alloc(value_shape.layout) });
226                            let value_poke =
227                                unsafe { Poke::unchecked_new(value_data, value_shape) };
228
229                            stack.push_front(StackItem::FinishMap { pm });
230                            stack.push_front(StackItem::AfterMapValue {
231                                key,
232                                value: value_data,
233                            });
234                            stack.push_front(StackItem::Value { poke: value_poke });
235                        } else {
236                            stack.push_front(StackItem::FinishMap { pm });
237                        }
238                    }
239                    Poke::Enum(pe) => {
240                        trace!("Deserializing \x1b[1;36menum\x1b[0m");
241                        let variant_str = parser.parse_string()?;
242
243                        let pe = pe.set_variant_by_name(&variant_str).map_err(|_| {
244                            parser.make_error(JsonParseErrorKind::Custom(format!(
245                                "Invalid enum variant: {}",
246                                variant_str
247                            )))
248                        })?;
249
250                        trace!("Finished deserializing \x1b[1;36menum\x1b[0m");
251                        let opaque = pe.build_in_place();
252                        result = Some(opaque);
253                    }
254                    _ => todo!("unsupported poke type"),
255                }
256            }
257            StackItem::StructField { key } => {
258                trace!("Processing struct key: \x1b[1;33m{}\x1b[0m", key);
259
260                let ps = match stack.front_mut().unwrap() {
261                    StackItem::FinishStruct { ps } => ps,
262                    _ => unreachable!(),
263                };
264
265                match ps.field_by_name(&key) {
266                    Ok((index, field_poke)) => {
267                        trace!("Found field, it's at index: \x1b[1;33m{index}\x1b[0m");
268
269                        stack.push_front(StackItem::AfterStructField { index });
270
271                        stack.push_front(StackItem::Value { poke: field_poke });
272                    }
273                    Err(_) => {
274                        trace!("No field named \x1b[1;36m{}\x1b[0m", key);
275                        return Err(parser.make_error(JsonParseErrorKind::UnknownField(key)));
276                    }
277                }
278            }
279            StackItem::AfterStructField { index } => {
280                trace!("After processing struct field at index: \x1b[1;33m{index}\x1b[0m");
281
282                let ps = match stack.front_mut().unwrap() {
283                    StackItem::FinishStruct { ps } => ps,
284                    _ => unreachable!(),
285                };
286
287                unsafe {
288                    ps.mark_initialized(index);
289                }
290
291                let next_key = parser.parse_object_key()?;
292                if let Some(next_key) = next_key {
293                    stack.push_front(StackItem::StructField { key: next_key });
294                }
295            }
296            StackItem::FinishStruct { ps } => {
297                trace!("Finished deserializing \x1b[1;36mstruct\x1b[0m");
298
299                let opaque = ps.build_in_place();
300                result = Some(opaque);
301            }
302            StackItem::AfterListItem { item } => {
303                trace!("Processing array item at index");
304
305                let pl = match stack.front_mut().unwrap() {
306                    StackItem::FinishList { pl } => pl,
307                    _ => unreachable!(),
308                };
309                let item = unsafe { item.assume_init() };
310                unsafe {
311                    pl.push(item);
312                }
313                unsafe { std::alloc::dealloc(item.as_mut_byte_ptr(), pl.def().t.layout) };
314
315                let has_next = parser.parse_array_element()?;
316                if let Some(true) = has_next {
317                    let item_shape = pl.def().t;
318                    let item_data =
319                        OpaqueUninit::new(unsafe { std::alloc::alloc(item_shape.layout) });
320                    let item_poke = unsafe { Poke::unchecked_new(item_data, item_shape) };
321
322                    stack.push_front(StackItem::AfterListItem { item: item_data });
323                    stack.push_front(StackItem::Value { poke: item_poke });
324                }
325            }
326            StackItem::FinishList { pl } => {
327                trace!("Finished deserializing \x1b[1;36marray\x1b[0m");
328                let opaque = pl.build_in_place();
329                result = Some(opaque);
330            }
331            StackItem::AfterMapValue { mut key, value } => {
332                trace!("Processing hashmap key: \x1b[1;33m{}\x1b[0m", key);
333
334                let pm = match stack.front_mut().unwrap() {
335                    StackItem::FinishMap { pm } => pm,
336                    _ => unreachable!(),
337                };
338                let key_data = Opaque::new(&mut key);
339                let value = unsafe { value.assume_init() };
340                unsafe {
341                    pm.insert(key_data, value);
342                }
343                core::mem::forget(key); // key has been moved out of
344                unsafe { std::alloc::dealloc(value.as_mut_byte_ptr(), pm.def().v.layout) };
345
346                let next_key = parser.parse_object_key()?;
347                if let Some(next_key) = next_key {
348                    let value_shape = pm.def().v;
349                    let value_data =
350                        OpaqueUninit::new(unsafe { std::alloc::alloc(value_shape.layout) });
351                    let value_poke = unsafe { Poke::unchecked_new(value_data, value_shape) };
352
353                    stack.push_front(StackItem::AfterMapValue {
354                        key: next_key,
355                        value: value_data,
356                    });
357                    stack.push_front(StackItem::Value { poke: value_poke });
358                }
359            }
360            StackItem::FinishMap { pm } => {
361                trace!("Finished deserializing \x1b[1;36mhashmap\x1b[0m");
362                let opaque = pm.build_in_place();
363                result = Some(opaque);
364            }
365        }
366    }
367
368    result.ok_or_else(|| {
369        parser.make_error(JsonParseErrorKind::Custom(
370            "Unexpected end of input".to_string(),
371        ))
372    })
373}