facet_json/
deserialize.rs

1use alloc::{borrow::Cow, format};
2
3use facet_core::Facet;
4use facet_deserialize::{
5    DeserError, DeserErrorKind, Expectation, Format, NextData, NextResult, Outcome, Scalar, Span,
6    Spannable, Spanned,
7};
8use log::trace;
9
10mod tokenizer;
11use tokenizer::{Token, TokenError, TokenErrorKind, Tokenizer};
12
13/// Deserialize JSON from a given byte slice
14pub fn from_slice<'input: 'facet, 'facet, T: Facet<'facet>>(
15    input: &'input [u8],
16) -> Result<T, DeserError<'input>> {
17    facet_deserialize::deserialize::<T, Json>(input)
18}
19
20/// Deserialize JSON from a given string
21pub fn from_str<'input: 'facet, 'facet, T: Facet<'facet>>(
22    input: &'input str,
23) -> Result<T, DeserError<'input>> {
24    let input = input.as_bytes();
25    facet_deserialize::deserialize::<T, Json>(input)
26}
27
28/// Deserialize JSON from a given string, converting any dynamic error into a static one.
29///
30/// This function attempts to deserialize a type `T` implementing `Facet` from the input string slice.
31/// If deserialization fails, the error is converted into an owned, static error type to avoid lifetime issues.
32pub fn from_str_static_error<'input: 'facet, 'facet, T: Facet<'facet>>(
33    input: &'input str,
34) -> Result<T, DeserError<'input>> {
35    let input = input.as_bytes();
36    facet_deserialize::deserialize::<T, Json>(input).map_err(|e| e.into_owned())
37}
38
39/// The JSON format
40pub struct Json;
41
42impl Format for Json {
43    fn next<'input, 'facet>(
44        nd: NextData<'input, 'facet>,
45        mut expectation: Expectation,
46    ) -> NextResult<'input, 'facet, Spanned<Outcome<'input>>, Spanned<DeserErrorKind>> {
47        trace!("Starting next at offset {}", nd.start());
48        let input = &nd.input()[nd.start()..];
49        let mut tokenizer = Tokenizer::new(input);
50
51        loop {
52            let token = match tokenizer.next_token() {
53                Ok(token) => {
54                    trace!("Token for next: {:?}", token.node);
55                    token
56                }
57                Err(err) => {
58                    trace!("Tokenizer error in next: {:?}", err.kind);
59                    return (nd, Err(convert_token_error(err)));
60                }
61            };
62
63            // Adjust token span to be relative to the beginning of the overall input
64            let token_offset = nd.start();
65            let span = Span::new(token.span.start() + token_offset, token.span.len());
66
67            let res = match token.node {
68                Token::String(s) => Ok(Spanned {
69                    node: Outcome::Scalar(Scalar::String(Cow::Owned(s))),
70                    span,
71                }),
72                Token::F64(n) => Ok(Spanned {
73                    node: Outcome::Scalar(Scalar::F64(n)),
74                    span,
75                }),
76                Token::I64(n) => Ok(Spanned {
77                    node: Outcome::Scalar(Scalar::I64(n)),
78                    span,
79                }),
80                Token::U64(n) => Ok(Spanned {
81                    node: Outcome::Scalar(Scalar::U64(n)),
82                    span,
83                }),
84                Token::True => Ok(Spanned {
85                    node: Outcome::Scalar(Scalar::Bool(true)),
86                    span,
87                }),
88                Token::False => Ok(Spanned {
89                    node: Outcome::Scalar(Scalar::Bool(false)),
90                    span,
91                }),
92                Token::Null => Ok(Spanned {
93                    node: Outcome::Scalar(Scalar::Null),
94                    span,
95                }),
96                Token::LBrace => Ok(Spanned {
97                    node: Outcome::ObjectStarted,
98                    span,
99                }),
100                Token::RBrace => {
101                    if expectation == Expectation::ObjectKeyOrObjectClose {
102                        Ok(Spanned {
103                            node: Outcome::ObjectEnded,
104                            span,
105                        })
106                    } else {
107                        trace!("Did not expect closing brace, expected {:?}", expectation);
108                        Err(DeserErrorKind::UnexpectedChar {
109                            got: '}',
110                            wanted: "a value",
111                        }
112                        .with_span(span))
113                    }
114                }
115                Token::LBracket => Ok(Spanned {
116                    node: Outcome::ListStarted,
117                    span,
118                }),
119                Token::RBracket => {
120                    if expectation == Expectation::ListItemOrListClose {
121                        Ok(Spanned {
122                            node: Outcome::ListEnded,
123                            span,
124                        })
125                    } else {
126                        Err(DeserErrorKind::UnexpectedChar {
127                            got: ']',
128                            wanted: "a value",
129                        }
130                        .with_span(span))
131                    }
132                }
133                Token::Colon => {
134                    if expectation == Expectation::ObjectVal {
135                        expectation = Expectation::Value;
136                        continue;
137                    } else {
138                        trace!("Did not expect ObjectValue, expected {:?}", expectation);
139                        Err(DeserErrorKind::UnexpectedChar {
140                            got: ':',
141                            wanted: "a value, not a colon",
142                        }
143                        .with_span(span))
144                    }
145                }
146                Token::Comma => match expectation {
147                    Expectation::ListItemOrListClose | Expectation::ObjectKeyOrObjectClose => {
148                        expectation = Expectation::Value;
149                        continue;
150                    }
151                    other => {
152                        trace!("Did not expect comma, expected {:?}", other);
153                        Err(DeserErrorKind::UnexpectedChar {
154                            got: ',',
155                            wanted: "<value or key>",
156                        }
157                        .with_span(span))
158                    }
159                },
160                Token::Eof => {
161                    return (
162                        nd,
163                        Err(DeserErrorKind::UnexpectedEof {
164                            wanted: "any value (got EOF)",
165                        }
166                        .with_span(span)),
167                    );
168                }
169            };
170
171            return (nd, res);
172        }
173    }
174
175    fn skip<'input, 'facet>(
176        nd: NextData<'input, 'facet>,
177    ) -> NextResult<'input, 'facet, Span, Spanned<DeserErrorKind>> {
178        trace!("Starting skip at offset {}", nd.start());
179        let input = &nd.input()[nd.start()..];
180        let mut tokenizer = Tokenizer::new(input);
181
182        loop {
183            let token = match tokenizer.next_token() {
184                Ok(token) => {
185                    trace!("Initial token for skip: {:?}", token.node);
186                    token
187                }
188                Err(err) => {
189                    trace!("Tokenizer error on initial token: {:?}", err.kind);
190                    return (nd, Err(convert_token_error(err)));
191                }
192            };
193
194            let res = match token.node {
195                Token::LBrace | Token::LBracket => {
196                    trace!(
197                        "Skip: found container start ({:?}), entering depth parse",
198                        token.node
199                    );
200                    let mut depth = 1;
201                    let mut last_span = token.span;
202                    while depth > 0 {
203                        let token = match tokenizer.next_token() {
204                            Ok(token) => {
205                                trace!(
206                                    "Skip: depth {}, next token in container: {:?}",
207                                    depth, token.node
208                                );
209                                token
210                            }
211                            Err(err) => {
212                                trace!("Tokenizer error while skipping container: {:?}", err.kind);
213                                return (nd, Err(convert_token_error(err)));
214                            }
215                        };
216
217                        match token.node {
218                            Token::LBrace | Token::LBracket => {
219                                depth += 1;
220                                last_span = token.span;
221                                trace!("Container nested incremented, depth now {}", depth);
222                            }
223                            Token::RBrace | Token::RBracket => {
224                                depth -= 1;
225                                last_span = token.span;
226                                trace!("Container closed, depth now {}", depth);
227                            }
228                            _ => {
229                                last_span = token.span;
230                                trace!("Skipping non-container token: {:?}", token.node);
231                            }
232                        }
233                    }
234                    trace!("Skip complete, span {:?}", last_span);
235                    (nd, Ok(last_span))
236                }
237                Token::String(_)
238                | Token::F64(_)
239                | Token::I64(_)
240                | Token::U64(_)
241                | Token::True
242                | Token::False
243                | Token::Null => {
244                    trace!("Skip found primitive: {:?}", token.node);
245                    (nd, Ok(token.span))
246                }
247                Token::Colon => {
248                    // Skip colon token
249                    continue;
250                }
251                other => {
252                    trace!(
253                        "Skip encountered unexpected token kind: {:?} at span {:?}",
254                        other, token.span
255                    );
256                    (
257                        nd,
258                        Err(DeserErrorKind::UnexpectedChar {
259                            got: format!("{:?}", other).chars().next().unwrap_or('?'),
260                            wanted: "value",
261                        }
262                        .with_span(Span::new(token.span.start(), token.span.len()))),
263                    )
264                }
265            };
266            let (nd, mut span) = res;
267            if let Ok(valid_span) = &mut span {
268                let offset = nd.start();
269                valid_span.start += offset;
270            }
271            let res = (nd, span);
272            trace!("Returning {:?}", res.1);
273            return res;
274        }
275    }
276}
277
278fn convert_token_error(err: TokenError) -> Spanned<DeserErrorKind> {
279    match err.kind {
280        TokenErrorKind::UnexpectedCharacter(c) => DeserErrorKind::UnexpectedChar {
281            got: c,
282            wanted: "valid JSON character",
283        }
284        .with_span(err.span),
285        TokenErrorKind::UnexpectedEof(why) => {
286            DeserErrorKind::UnexpectedEof { wanted: why }.with_span(err.span)
287        }
288        TokenErrorKind::InvalidUtf8(s) => DeserErrorKind::InvalidUtf8(s).with_span(err.span),
289        TokenErrorKind::NumberOutOfRange(number) => {
290            DeserErrorKind::NumberOutOfRange(number).with_span(err.span)
291        }
292    }
293}