shapely_json/
from_json.rs

1use crate::parser::{JsonParseErrorKind, JsonParseErrorWithContext, JsonParser};
2use shapely::{Partial, Shapely as _, error, trace, warn};
3
4/// Deserialize a `Partial` object from a JSON string.
5pub fn from_json<'input>(
6    partial: &mut Partial,
7    json: &'input str,
8) -> Result<(), JsonParseErrorWithContext<'input>> {
9    use shapely::{Innards, Scalar};
10
11    trace!("Starting JSON deserialization");
12    let mut parser = JsonParser::new(json);
13
14    fn deserialize_value<'input>(
15        parser: &mut JsonParser<'input>,
16        partial: &mut Partial,
17    ) -> Result<(), JsonParseErrorWithContext<'input>> {
18        let shape_desc = partial.shape();
19        let shape = shape_desc.get();
20        trace!("Deserializing value with shape:\n{:?}", shape);
21
22        match &shape.innards {
23            Innards::Scalar(scalar) => {
24                let slot = partial.scalar_slot().expect("Scalar slot");
25                trace!("Deserializing \x1b[1;36mscalar\x1b[0m, \x1b[1;35m{scalar:?}\x1b[0m");
26
27                match scalar {
28                    Scalar::String => slot.fill(parser.parse_string()?),
29                    Scalar::U8 => slot.fill(parser.parse_u8()?),
30                    Scalar::U16 => slot.fill(parser.parse_u16()?),
31                    Scalar::U32 => slot.fill(parser.parse_u32()?),
32                    Scalar::U64 => slot.fill(parser.parse_u64()?),
33                    Scalar::I8 => slot.fill(parser.parse_i8()?),
34                    Scalar::I16 => slot.fill(parser.parse_i16()?),
35                    Scalar::I32 => slot.fill(parser.parse_i32()?),
36                    Scalar::I64 => slot.fill(parser.parse_i64()?),
37                    Scalar::F32 => slot.fill(parser.parse_f32()?),
38                    Scalar::F64 => slot.fill(parser.parse_f64()?),
39                    Scalar::Boolean => slot.fill(parser.parse_bool()?),
40                    _ => {
41                        warn!("Unsupported scalar type: {:?}", scalar);
42                        return Err(parser.make_error(JsonParseErrorKind::Custom(format!(
43                            "Unsupported scalar type: {:?}",
44                            scalar
45                        ))));
46                    }
47                }
48            }
49            Innards::Struct { .. } => {
50                trace!("Deserializing \x1b[1;36mstruct\x1b[0m");
51
52                let mut first = true;
53                while let Some(key) = if first {
54                    first = false;
55                    parser.expect_object_start()?
56                } else {
57                    parser.parse_object_key()?
58                } {
59                    trace!("Processing struct key: \x1b[1;33m{}\x1b[0m", key);
60                    let slot = partial
61                        .slot_by_name(&key)
62                        .map_err(|_| parser.make_error(JsonParseErrorKind::UnknownField(key)))?;
63                    let mut partial_field = Partial::alloc(slot.shape());
64                    deserialize_value(parser, &mut partial_field)?;
65                    slot.fill_from_partial(partial_field);
66                }
67                trace!("Finished deserializing \x1b[1;36mstruct\x1b[0m");
68
69                // TODO: this would be a good place to decide what to do about unset fields? Is this
70                // where we finally get to use `set_default`?
71            }
72            Innards::Tuple { .. } => {
73                trace!("Deserializing \x1b[1;36mtuple\x1b[0m");
74
75                // Parse array start
76                parser.expect_array_start()?;
77
78                let mut index = 0;
79                while let Some(has_element) = parser.parse_array_element()? {
80                    if !has_element {
81                        break;
82                    }
83
84                    let field_name = index.to_string();
85                    trace!("Processing tuple index: \x1b[1;33m{}\x1b[0m", field_name);
86
87                    let slot = partial.slot_by_name(&field_name).map_err(|_| {
88                        parser.make_error(JsonParseErrorKind::Custom(format!(
89                            "Tuple index out of bounds: {}",
90                            index
91                        )))
92                    })?;
93
94                    let mut partial_field = Partial::alloc(slot.shape());
95                    deserialize_value(parser, &mut partial_field)?;
96                    slot.fill_from_partial(partial_field);
97
98                    index += 1;
99                }
100
101                trace!("Finished deserializing \x1b[1;36mtuple\x1b[0m");
102            }
103            Innards::TupleStruct { .. } => {
104                trace!("Deserializing \x1b[1;36mtuple struct\x1b[0m");
105
106                // Parse array start
107                parser.expect_array_start()?;
108
109                let mut index = 0;
110                while let Some(has_element) = parser.parse_array_element()? {
111                    if !has_element {
112                        break;
113                    }
114
115                    let field_name = index.to_string();
116                    trace!(
117                        "Processing tuple struct index: \x1b[1;33m{}\x1b[0m",
118                        field_name
119                    );
120
121                    let slot = partial.slot_by_name(&field_name).map_err(|_| {
122                        parser.make_error(JsonParseErrorKind::Custom(format!(
123                            "Tuple struct index out of bounds: {}",
124                            index
125                        )))
126                    })?;
127
128                    let mut partial_field = Partial::alloc(slot.shape());
129                    deserialize_value(parser, &mut partial_field)?;
130                    slot.fill_from_partial(partial_field);
131
132                    index += 1;
133                }
134
135                trace!("Finished deserializing \x1b[1;36mtuple struct\x1b[0m");
136            }
137            Innards::List { item_shape, .. } => {
138                trace!("Deserializing \x1b[1;36marray\x1b[0m");
139
140                // Parse array start
141                parser.expect_array_start()?;
142
143                // Get the array slot to push items into (no size hint in JSON unfortunately)
144                let mut array_slot = partial.array_slot(None).expect("Array slot");
145
146                let mut index = 0;
147                while let Some(has_element) = parser.parse_array_element()? {
148                    if !has_element {
149                        break;
150                    }
151
152                    trace!("Processing array item at index: \x1b[1;33m{}\x1b[0m", index);
153
154                    // Create a partial for the item
155                    let mut item_partial = Partial::alloc(*item_shape);
156
157                    // Deserialize the item
158                    deserialize_value(parser, &mut item_partial)?;
159
160                    // Add the item to the array
161                    array_slot.push(item_partial);
162
163                    index += 1;
164                }
165
166                trace!(
167                    "Finished deserializing \x1b[1;36marray\x1b[0m with {} items",
168                    index
169                );
170            }
171            Innards::Map { value_shape, .. } => {
172                trace!("Deserializing \x1b[1;36mhashmap\x1b[0m");
173
174                // Parse object start and get first key if it exists
175                let first_key = parser.expect_object_start()?;
176
177                // Get the hashmap slot to insert key-value pairs into
178                let mut hashmap_slot = partial.hashmap_slot(None).expect("HashMap slot");
179
180                // Process each key-value pair in the JSON object
181                let mut current_key = first_key;
182                while let Some(key) = current_key {
183                    trace!("Processing hashmap key: \x1b[1;33m{}\x1b[0m", key);
184
185                    // Create a partial for the key (string type)
186                    let mut key_partial = Partial::alloc(String::shape_desc());
187                    key_partial.scalar_slot().expect("String slot").fill(key);
188
189                    // Create a partial for the value
190                    let mut value_partial = Partial::alloc(*value_shape);
191
192                    // Deserialize the value
193                    deserialize_value(parser, &mut value_partial)?;
194
195                    // Insert the key-value pair into the hashmap
196                    hashmap_slot.insert(key_partial, value_partial);
197
198                    // Get the next key
199                    current_key = parser.parse_object_key()?;
200                }
201
202                trace!("Finished deserializing \x1b[1;36mhashmap\x1b[0m");
203            }
204            // Add support for other shapes (Array, Transparent) as needed
205            _ => {
206                error!(
207                    "Don't know how to parse this shape as JSON: {:?}",
208                    shape.innards
209                );
210                return Err(parser.make_error(JsonParseErrorKind::Custom(format!(
211                    "Don't know how to parse this shape as JSON: {:?}",
212                    shape.innards
213                ))));
214            }
215        }
216        Ok(())
217    }
218
219    deserialize_value(&mut parser, partial)
220}