facet_json/
deserialize.rs

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