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