serser/json/
from.rs

1use std::fmt;
2
3use base64::prelude::*;
4
5use crate::token::*;
6use crate::Error;
7use crate::IntoTokens;
8use crate::TokenError;
9use crate::TokenSink;
10
11/// The error returned from [json_from_tokens].
12#[derive(Debug, Eq, PartialEq)]
13pub enum WriteError {
14    /// The string formatter (or I/O) failed.
15    Fmt(fmt::Error),
16
17    /// The token stream was invalid.
18    Token(TokenError),
19}
20
21impl fmt::Display for WriteError {
22    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
23        match self {
24            Self::Fmt(err) => err.fmt(f),
25            Self::Token(err) => err.fmt(f),
26        }
27    }
28}
29
30impl std::error::Error for WriteError {}
31impl Error for WriteError {
32    fn invalid_token(token: Token<'_>, expected: Option<TokenTypes>) -> Self {
33        WriteError::Token(TokenError::invalid_token(token, expected))
34    }
35
36    fn invalid_field(field: &str) -> Self {
37        WriteError::Token(TokenError::invalid_field(field))
38    }
39
40    fn missing_fields(fields: &[&str]) -> Self {
41        WriteError::Token(TokenError::missing_fields(fields))
42    }
43
44    fn invalid_variant(variant: EnumVariant<'_>) -> Self {
45        WriteError::Token(TokenError::invalid_variant(variant))
46    }
47
48    fn unexpected_end(expected: Option<TokenTypes>) -> Self {
49        WriteError::Token(TokenError::unexpected_end(expected))
50    }
51}
52
53/// Writes JSON to `writer` from data in an [IntoTokens].
54///
55/// The output JSON contains no whitespace.
56pub fn json_from_tokens<I: IntoTokens, W: fmt::Write>(
57    writer: W,
58    into: I,
59) -> Result<(), WriteError> {
60    let mut sink = JsonTokenSink {
61        writer,
62        state: JsonState::Plain,
63        states: Vec::new(),
64    };
65    into.into_tokens(&mut sink)?;
66
67    match sink.state {
68        JsonState::Done => Ok(()),
69        _ => Err(WriteError::unexpected_end(sink.expect_tokens())),
70    }
71}
72
73struct JsonTokenSink<W: fmt::Write> {
74    writer: W,
75    state: JsonState,
76    states: Vec<JsonState>,
77}
78
79impl<W: fmt::Write> JsonTokenSink<W> {
80    /// Writes the comma or colon as appropriate before a
81    /// token. Updates the state.
82    fn write_sep(&mut self, token: &Token<'_>) -> Result<(), WriteError> {
83        match self.state {
84            JsonState::Plain => self.state = JsonState::Done,
85            JsonState::FirstArrayElement => self.state = JsonState::ArrayElement,
86            JsonState::ArrayElement => self
87                .writer
88                .write_str(",")
89                .map_err(|err| WriteError::Fmt(err))?,
90            JsonState::FirstObjectKey => {
91                match token {
92                    Token::Field(_) => {}
93                    _ => {
94                        return Err(WriteError::invalid_token(
95                            token.clone(),
96                            Some(TokenTypes::new(TokenType::Field)),
97                        ))
98                    }
99                }
100
101                self.state = JsonState::ObjectValue;
102            }
103            JsonState::ObjectKey => {
104                match token {
105                    Token::Field(_) => {}
106                    _ => {
107                        return Err(WriteError::invalid_token(
108                            token.clone(),
109                            Some(TokenTypes::new(TokenType::Field)),
110                        ))
111                    }
112                }
113
114                self.writer
115                    .write_str(",")
116                    .map_err(|err| WriteError::Fmt(err))?;
117                self.state = JsonState::ObjectValue;
118            }
119            JsonState::ObjectValue => {
120                self.writer
121                    .write_str(":")
122                    .map_err(|err| WriteError::Fmt(err))?;
123                self.state = JsonState::ObjectKey;
124            }
125            JsonState::EnumVariant(kind) => self.state = JsonState::EnumStart(kind),
126            JsonState::EnumStart(_) => {
127                self.writer
128                    .write_str(":")
129                    .map_err(|err| WriteError::Fmt(err))?;
130                self.state = JsonState::EnumEnd;
131            }
132            JsonState::EnumEnd => {}
133            JsonState::Done => unreachable!(),
134        }
135
136        Ok(())
137    }
138
139    fn write_bytes(&mut self, v: &[u8]) -> Result<(), fmt::Error> {
140        let w = &mut self.writer;
141
142        w.write_char('"')?;
143        w.write_str(BASE64_STANDARD.encode(v).as_str())?;
144        w.write_char('"')?;
145
146        Ok(())
147    }
148
149    fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
150        let mut start = 0;
151        let mut end = 0;
152        let w = &mut self.writer;
153
154        w.write_char('"')?;
155
156        for c in s.chars() {
157            if c == '\\' || c == '"' || c < ' ' {
158                w.write_str(&s[start..end])?;
159
160                w.write_char('\\')?;
161
162                match c {
163                    '\x07' => w.write_char('b')?,
164                    '\x0C' => w.write_char('f')?,
165                    '\n' => w.write_char('n')?,
166                    '\r' => w.write_char('r')?,
167                    '\t' => w.write_char('t')?,
168                    c if c < ' ' => write!(w, "u{:04X}", c as u32)?,
169                    c => w.write_char(c)?,
170                }
171
172                end += c.len_utf8();
173                start = end;
174            } else {
175                end += c.len_utf8();
176            }
177        }
178
179        if start < end {
180            w.write_str(&s[start..end])?;
181        }
182
183        w.write_char('"')?;
184
185        Ok(())
186    }
187}
188
189impl<W: fmt::Write> TokenSink for JsonTokenSink<W> {
190    type Error = WriteError;
191
192    fn yield_token(&mut self, token: Token<'_>) -> Result<bool, Self::Error> {
193        if token.is_end() {
194            match self.state {
195                JsonState::FirstArrayElement | JsonState::ArrayElement => match token {
196                    Token::EndSeq | Token::EndTuple => {}
197                    _ => {
198                        return Err(WriteError::invalid_token(
199                            token.into(),
200                            Some(TokenTypes::new(TokenType::EndTuple).with(TokenType::EndSeq)),
201                        ))
202                    }
203                },
204                JsonState::FirstObjectKey | JsonState::ObjectKey => match token {
205                    Token::EndStruct => {}
206                    _ => {
207                        return Err(WriteError::invalid_token(
208                            token.into(),
209                            Some(TokenTypes::new(TokenType::EndStruct)),
210                        ))
211                    }
212                },
213                JsonState::EnumEnd => match token {
214                    Token::EndEnum => {}
215                    _ => {
216                        return Err(WriteError::invalid_token(
217                            token.into(),
218                            Some(TokenTypes::new(TokenType::EndEnum)),
219                        ))
220                    }
221                },
222
223                JsonState::ObjectValue => {
224                    return Err(WriteError::Token(TokenError::InvalidToken(
225                        token.into(),
226                        None,
227                    )))
228                }
229                JsonState::EnumVariant(_) => {
230                    return Err(WriteError::Token(TokenError::InvalidToken(
231                        token.into(),
232                        Some(TokenTypes::new(TokenType::Variant)),
233                    )))
234                }
235                // Backfill empty enums.
236                JsonState::EnumStart(EnumKind::Tuple) => self
237                    .writer
238                    .write_str(":[]")
239                    .map_err(|err| WriteError::Fmt(err))?,
240                JsonState::EnumStart(EnumKind::Struct) => self
241                    .writer
242                    .write_str(":{}")
243                    .map_err(|err| WriteError::Fmt(err))?,
244                _ => {}
245            }
246
247            self.state = JsonState::Done;
248        } else {
249            self.write_sep(&token)?;
250        }
251
252        let w = &mut self.writer;
253
254        match token {
255            Token::Unit => w.write_str("null"),
256            Token::Bool(v) => write!(w, "{}", v),
257            Token::U8(v) => write!(w, "{}", v),
258            Token::U16(v) => write!(w, "{}", v),
259            Token::U32(v) => write!(w, "{}", v),
260            Token::U64(v) => write!(w, "{}", v),
261            Token::U128(v) => write!(w, "{}", v),
262            Token::Usize(v) => write!(w, "{}", v),
263            Token::I8(v) => write!(w, "{}", v),
264            Token::I16(v) => write!(w, "{}", v),
265            Token::I32(v) => write!(w, "{}", v),
266            Token::I64(v) => write!(w, "{}", v),
267            Token::I128(v) => write!(w, "{}", v),
268            Token::Isize(v) => write!(w, "{}", v),
269            Token::F32(v) => write!(w, "{}", v),
270            Token::F64(v) => write!(w, "{}", v),
271            Token::Char(v) => self.write_str(v.to_string().as_str()),
272            Token::Bytes(v) => self.write_bytes(v),
273            Token::Str(s) => self.write_str(s),
274            Token::Field(s) => self.write_str(s),
275            Token::Variant(EnumVariant::Str(s)) => self.write_str(s),
276            Token::Variant(EnumVariant::Usize(i)) => write!(w, "\"{}\"", i),
277
278            Token::Seq(_) => {
279                self.states.push(std::mem::replace(
280                    &mut self.state,
281                    JsonState::FirstArrayElement,
282                ));
283                w.write_str("[")
284            }
285            Token::Tuple(_) => {
286                self.states.push(std::mem::replace(
287                    &mut self.state,
288                    JsonState::FirstArrayElement,
289                ));
290                w.write_str("[")
291            }
292            Token::Struct(_) => {
293                self.states.push(std::mem::replace(
294                    &mut self.state,
295                    JsonState::FirstObjectKey,
296                ));
297                w.write_str("{")
298            }
299            Token::Enum(meta) => {
300                self.states.push(std::mem::replace(
301                    &mut self.state,
302                    JsonState::EnumVariant(meta.kind.unwrap_or(EnumKind::Tuple)),
303                ));
304                w.write_str("{")
305            }
306
307            Token::EndSeq => {
308                self.state = self
309                    .states
310                    .pop()
311                    .ok_or(WriteError::invalid_token(token, Some(TokenTypes::EMPTY)))?;
312                w.write_str("]")
313            }
314            Token::EndTuple => {
315                self.state = self
316                    .states
317                    .pop()
318                    .ok_or(WriteError::invalid_token(token, Some(TokenTypes::EMPTY)))?;
319                w.write_str("]")
320            }
321            Token::EndStruct => {
322                self.state = self
323                    .states
324                    .pop()
325                    .ok_or(WriteError::invalid_token(token, Some(TokenTypes::EMPTY)))?;
326                w.write_str("}")
327            }
328            Token::EndEnum => {
329                self.state = self
330                    .states
331                    .pop()
332                    .ok_or(WriteError::invalid_token(token, Some(TokenTypes::EMPTY)))?;
333                w.write_str("}")
334            }
335        }
336        .map_err(|err| WriteError::Fmt(err))?;
337
338        Ok(true)
339    }
340
341    fn expect_tokens(&mut self) -> Option<TokenTypes> {
342        match self.state {
343            JsonState::Plain => None,
344            JsonState::FirstArrayElement => None,
345            JsonState::ArrayElement => None,
346            JsonState::FirstObjectKey => Some(TokenTypes::new(TokenType::Field)),
347            JsonState::ObjectKey => Some(TokenTypes::new(TokenType::Field)),
348            JsonState::ObjectValue => None,
349            JsonState::EnumVariant(_) => Some(TokenTypes::new(TokenType::Variant)),
350            JsonState::EnumStart(EnumKind::Tuple) => Some(TokenTypes::new(TokenType::Tuple)),
351            JsonState::EnumStart(EnumKind::Struct) => Some(TokenTypes::new(TokenType::Struct)),
352            JsonState::EnumEnd => Some(TokenTypes::new(TokenType::EndEnum)),
353            JsonState::Done => Some(TokenTypes::EMPTY),
354        }
355    }
356}
357
358#[derive(Debug)]
359enum JsonState {
360    Plain,
361    FirstArrayElement,
362    ArrayElement,
363    FirstObjectKey,
364    ObjectKey,
365    ObjectValue,
366    EnumVariant(EnumKind),
367    EnumStart(EnumKind),
368    EnumEnd,
369    Done,
370}
371
372#[cfg(test)]
373mod tests {
374    use super::*;
375    use crate::TokenVec;
376
377    #[test]
378    fn test_from_tokens_plain() {
379        let cases = vec![
380            (Token::Unit, "null"),
381            (Token::Bool(true), "true"),
382            (Token::U8(42), "42"),
383            (Token::U16(42), "42"),
384            (Token::U32(42), "42"),
385            (Token::U64(42), "42"),
386            (Token::U128(42), "42"),
387            (Token::Usize(42), "42"),
388            (Token::I8(42), "42"),
389            (Token::I16(42), "42"),
390            (Token::I32(42), "42"),
391            (Token::I64(42), "42"),
392            (Token::I128(42), "42"),
393            (Token::Isize(42), "42"),
394            (Token::Char('a'), "\"a\""),
395            (Token::Bytes(b""), "\"\""),
396            (Token::Bytes(b"\x00"), "\"AA==\""),
397            (Token::Str("hello"), "\"hello\""),
398            (Token::Str("\n"), "\"\\n\""),
399            (Token::Str("❤️"), "\"❤️\""),
400            (Token::Str("\x1F"), "\"\\u001F\""),
401            (Token::Str("hello"), "\"hello\""),
402        ];
403
404        for (token, want) in cases {
405            let mut got = String::new();
406            json_from_tokens(&mut got, TokenVec::from_iter(vec![token].into_iter())).unwrap();
407            assert_eq!(got, want);
408        }
409    }
410
411    #[test]
412    fn test_from_tokens_seq() {
413        let cases = vec![
414            (
415                vec![Token::Seq(SeqMeta { size_hint: None }), Token::EndSeq],
416                "[]",
417            ),
418            (
419                vec![
420                    Token::Seq(SeqMeta { size_hint: None }),
421                    Token::Bool(true),
422                    Token::EndSeq,
423                ],
424                "[true]",
425            ),
426            (
427                vec![
428                    Token::Seq(SeqMeta { size_hint: None }),
429                    Token::Bool(true),
430                    Token::Bool(false),
431                    Token::EndSeq,
432                ],
433                "[true,false]",
434            ),
435            (
436                vec![
437                    Token::Seq(SeqMeta { size_hint: None }),
438                    Token::Seq(SeqMeta { size_hint: None }),
439                    Token::Bool(true),
440                    Token::EndSeq,
441                    Token::EndSeq,
442                ],
443                "[[true]]",
444            ),
445        ];
446
447        for (tokens, want) in cases {
448            let mut got = String::new();
449            json_from_tokens(&mut got, TokenVec::from_iter(tokens.into_iter())).unwrap();
450            assert_eq!(got, want);
451        }
452    }
453
454    #[test]
455    fn test_from_tokens_tuple() {
456        let cases = vec![
457            (
458                vec![Token::Tuple(TupleMeta { size_hint: None }), Token::EndTuple],
459                "[]",
460            ),
461            (
462                vec![
463                    Token::Tuple(TupleMeta { size_hint: None }),
464                    Token::Bool(true),
465                    Token::EndTuple,
466                ],
467                "[true]",
468            ),
469            (
470                vec![
471                    Token::Tuple(TupleMeta { size_hint: None }),
472                    Token::Bool(true),
473                    Token::Bool(false),
474                    Token::EndTuple,
475                ],
476                "[true,false]",
477            ),
478            (
479                vec![
480                    Token::Tuple(TupleMeta { size_hint: None }),
481                    Token::Tuple(TupleMeta { size_hint: None }),
482                    Token::Bool(true),
483                    Token::EndTuple,
484                    Token::EndTuple,
485                ],
486                "[[true]]",
487            ),
488        ];
489
490        for (tokens, want) in cases {
491            let mut got = String::new();
492            json_from_tokens(&mut got, TokenVec::from_iter(tokens.into_iter())).unwrap();
493            assert_eq!(got, want);
494        }
495    }
496
497    #[test]
498    fn test_from_tokens_struct() {
499        let cases = vec![
500            (
501                vec![Token::Struct(StructMeta { fields: None }), Token::EndStruct],
502                "{}",
503            ),
504            (
505                vec![
506                    Token::Struct(StructMeta { fields: None }),
507                    Token::Field("akey"),
508                    Token::Bool(true),
509                    Token::EndStruct,
510                ],
511                "{\"akey\":true}",
512            ),
513            (
514                vec![
515                    Token::Struct(StructMeta { fields: None }),
516                    Token::Field("akey"),
517                    Token::Bool(true),
518                    Token::Field("bkey"),
519                    Token::Bool(false),
520                    Token::EndStruct,
521                ],
522                "{\"akey\":true,\"bkey\":false}",
523            ),
524            (
525                vec![
526                    Token::Struct(StructMeta { fields: None }),
527                    Token::Field("akey"),
528                    Token::Struct(StructMeta { fields: None }),
529                    Token::Field("bkey"),
530                    Token::Bool(false),
531                    Token::EndStruct,
532                    Token::EndStruct,
533                ],
534                "{\"akey\":{\"bkey\":false}}",
535            ),
536        ];
537
538        for (tokens, want) in cases {
539            let mut got = String::new();
540            json_from_tokens(&mut got, TokenVec::from_iter(tokens.into_iter())).unwrap();
541            assert_eq!(got, want);
542        }
543    }
544
545    #[test]
546    fn test_from_tokens_enum_tuple() {
547        let cases = vec![
548            (
549                vec![
550                    Token::Enum(EnumMeta {
551                        variants: None,
552                        kind: None,
553                    }),
554                    Token::Variant(EnumVariant::Str("a")),
555                    Token::EndEnum,
556                ],
557                "{\"a\":[]}",
558            ),
559            (
560                vec![
561                    Token::Enum(EnumMeta {
562                        variants: None,
563                        kind: None,
564                    }),
565                    Token::Variant(EnumVariant::Usize(42)),
566                    Token::EndEnum,
567                ],
568                "{\"42\":[]}",
569            ),
570            (
571                vec![
572                    Token::Enum(EnumMeta {
573                        variants: None,
574                        kind: None,
575                    }),
576                    Token::Variant(EnumVariant::Str("a")),
577                    Token::Tuple(TupleMeta { size_hint: Some(1) }),
578                    Token::Bool(true),
579                    Token::EndTuple,
580                    Token::EndEnum,
581                ],
582                "{\"a\":[true]}",
583            ),
584            (
585                vec![
586                    Token::Enum(EnumMeta {
587                        variants: None,
588                        kind: None,
589                    }),
590                    Token::Variant(EnumVariant::Str("a")),
591                    Token::Tuple(TupleMeta { size_hint: Some(2) }),
592                    Token::Bool(true),
593                    Token::Bool(false),
594                    Token::EndTuple,
595                    Token::EndEnum,
596                ],
597                "{\"a\":[true,false]}",
598            ),
599            (
600                vec![
601                    Token::Enum(EnumMeta {
602                        variants: None,
603                        kind: None,
604                    }),
605                    Token::Variant(EnumVariant::Str("a")),
606                    Token::Tuple(TupleMeta { size_hint: Some(1) }),
607                    Token::Enum(EnumMeta {
608                        variants: None,
609                        kind: None,
610                    }),
611                    Token::Variant(EnumVariant::Str("b")),
612                    Token::Tuple(TupleMeta { size_hint: Some(1) }),
613                    Token::Bool(true),
614                    Token::EndTuple,
615                    Token::EndEnum,
616                    Token::EndTuple,
617                    Token::EndEnum,
618                ],
619                "{\"a\":[{\"b\":[true]}]}",
620            ),
621        ];
622
623        for (tokens, want) in cases {
624            let mut got = String::new();
625            json_from_tokens(&mut got, TokenVec::from_iter(tokens.into_iter())).unwrap();
626            assert_eq!(got, want);
627        }
628    }
629
630    #[test]
631    fn test_from_tokens_enum_struct() {
632        let cases = vec![
633            (
634                vec![
635                    Token::Enum(EnumMeta {
636                        variants: None,
637                        kind: None,
638                    }),
639                    Token::Variant(EnumVariant::Str("a")),
640                    Token::Struct(StructMeta {
641                        fields: Some(&["b"]),
642                    }),
643                    Token::Field("b"),
644                    Token::Bool(true),
645                    Token::EndStruct,
646                    Token::EndEnum,
647                ],
648                r#"{"a":{"b":true}}"#,
649            ),
650            (
651                vec![
652                    Token::Enum(EnumMeta {
653                        variants: None,
654                        kind: None,
655                    }),
656                    Token::Variant(EnumVariant::Str("a")),
657                    Token::Struct(StructMeta {
658                        fields: Some(&["b", "c"]),
659                    }),
660                    Token::Field("b"),
661                    Token::Bool(true),
662                    Token::Field("c"),
663                    Token::Bool(false),
664                    Token::EndStruct,
665                    Token::EndEnum,
666                ],
667                r#"{"a":{"b":true,"c":false}}"#,
668            ),
669            (
670                vec![
671                    Token::Enum(EnumMeta {
672                        variants: None,
673                        kind: None,
674                    }),
675                    Token::Variant(EnumVariant::Str("a")),
676                    Token::Struct(StructMeta {
677                        fields: Some(&["b"]),
678                    }),
679                    Token::Field("b"),
680                    Token::Enum(EnumMeta {
681                        variants: None,
682                        kind: None,
683                    }),
684                    Token::Variant(EnumVariant::Str("c")),
685                    Token::Struct(StructMeta {
686                        fields: Some(&["d"]),
687                    }),
688                    Token::Field("d"),
689                    Token::Bool(true),
690                    Token::EndStruct,
691                    Token::EndEnum,
692                    Token::EndStruct,
693                    Token::EndEnum,
694                ],
695                r#"{"a":{"b":{"c":{"d":true}}}}"#,
696            ),
697        ];
698
699        for (tokens, want) in cases {
700            let mut got = String::new();
701            json_from_tokens(&mut got, TokenVec::from_iter(tokens.into_iter())).unwrap();
702            assert_eq!(got, want);
703        }
704    }
705}