aws_smithy_json/deserialize/
token.rs

1/*
2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6use crate::deserialize::error::DeserializeError as Error;
7use crate::deserialize::must_not_be_finite;
8use crate::escape::unescape_string;
9pub use crate::escape::EscapeError;
10use aws_smithy_types::date_time::Format;
11use aws_smithy_types::primitive::Parse;
12use aws_smithy_types::{base64, Blob, DateTime, Document, Number};
13use std::borrow::Cow;
14use std::collections::HashMap;
15use std::iter::Peekable;
16
17/// New-type around `&str` that indicates the string is an escaped JSON string.
18/// Provides functions for retrieving the string in either form.
19#[derive(Debug, PartialEq, Eq, Copy, Clone)]
20pub struct EscapedStr<'a>(&'a str);
21
22impl<'a> EscapedStr<'a> {
23    pub fn new(value: &'a str) -> EscapedStr<'a> {
24        EscapedStr(value)
25    }
26
27    /// Returns the escaped string value
28    pub fn as_escaped_str(&self) -> &'a str {
29        self.0
30    }
31
32    /// Unescapes the string and returns it.
33    /// If the string doesn't need unescaping, it will be returned directly.
34    pub fn to_unescaped(self) -> Result<Cow<'a, str>, EscapeError> {
35        unescape_string(self.0)
36    }
37}
38
39/// Represents the location of a token
40#[derive(Debug, Eq, PartialEq, Copy, Clone)]
41pub struct Offset(pub usize);
42
43impl Offset {
44    /// Creates a custom error from the offset
45    pub fn error(&self, msg: Cow<'static, str>) -> Error {
46        Error::custom(msg).with_offset(self.0)
47    }
48}
49
50/// Enum representing the different JSON tokens that can be returned by
51/// [`crate::deserialize::json_token_iter`].
52#[derive(Debug, PartialEq)]
53pub enum Token<'a> {
54    StartArray {
55        offset: Offset,
56    },
57    EndArray {
58        offset: Offset,
59    },
60    ObjectKey {
61        offset: Offset,
62        key: EscapedStr<'a>,
63    },
64    StartObject {
65        offset: Offset,
66    },
67    EndObject {
68        offset: Offset,
69    },
70    ValueBool {
71        offset: Offset,
72        value: bool,
73    },
74    ValueNull {
75        offset: Offset,
76    },
77    ValueNumber {
78        offset: Offset,
79        value: Number,
80    },
81    ValueString {
82        offset: Offset,
83        value: EscapedStr<'a>,
84    },
85}
86
87impl<'a> Token<'a> {
88    pub fn offset(&self) -> Offset {
89        use Token::*;
90        *match self {
91            StartArray { offset } => offset,
92            EndArray { offset } => offset,
93            ObjectKey { offset, .. } => offset,
94            StartObject { offset } => offset,
95            EndObject { offset } => offset,
96            ValueBool { offset, .. } => offset,
97            ValueNull { offset } => offset,
98            ValueNumber { offset, .. } => offset,
99            ValueString { offset, .. } => offset,
100        }
101    }
102
103    /// Builds an error from the token's offset
104    pub fn error(&self, msg: Cow<'static, str>) -> Error {
105        self.offset().error(msg)
106    }
107}
108
109macro_rules! expect_fn {
110    ($name:ident, $token:ident, $doc:tt) => {
111        #[doc=$doc]
112        pub fn $name(token_result: Option<Result<Token<'_>, Error>>) -> Result<(), Error> {
113            match token_result.transpose()? {
114                Some(Token::$token { .. }) => Ok(()),
115                Some(token) => {
116                    Err(token.error(Cow::Borrowed(concat!("expected ", stringify!($token)))))
117                }
118                None => Err(Error::custom(concat!("expected ", stringify!($token)))),
119            }
120        }
121    };
122}
123
124expect_fn!(
125    expect_start_object,
126    StartObject,
127    "Expects a [Token::StartObject] token and returns an error if it's not present."
128);
129expect_fn!(
130    expect_start_array,
131    StartArray,
132    "Expects a [Token::StartArray] token and returns an error if it's not present."
133);
134
135macro_rules! expect_value_or_null_fn {
136    ($name:ident, $token:ident, $typ:ident, $doc:tt) => {
137        #[doc=$doc]
138        pub fn $name(token: Option<Result<Token<'_>, Error>>) -> Result<Option<$typ>, Error> {
139            match token.transpose()? {
140                Some(Token::ValueNull { .. }) => Ok(None),
141                Some(Token::$token { value, .. }) => Ok(Some(value)),
142                _ => Err(Error::custom(concat!(
143                    "expected ",
144                    stringify!($token),
145                    " or ValueNull"
146                ))),
147            }
148        }
149    };
150}
151
152expect_value_or_null_fn!(expect_bool_or_null, ValueBool, bool, "Expects a [Token::ValueBool] or [Token::ValueNull], and returns the bool value if it's not null.");
153expect_value_or_null_fn!(expect_string_or_null, ValueString, EscapedStr, "Expects a [Token::ValueString] or [Token::ValueNull], and returns the [EscapedStr] value if it's not null.");
154
155/// Expects a [Token::ValueString], [Token::ValueNumber] or [Token::ValueNull].
156///
157/// If the value is a string, it MUST be `Infinity`, `-Infinity` or `Nan`.
158/// If the value is a number, it is returned directly
159pub fn expect_number_or_null(
160    token: Option<Result<Token<'_>, Error>>,
161) -> Result<Option<Number>, Error> {
162    match token.transpose()? {
163        Some(Token::ValueNull { .. }) => Ok(None),
164        Some(Token::ValueNumber { value, .. }) => Ok(Some(value)),
165        Some(Token::ValueString { value, offset }) => match value.to_unescaped() {
166            Err(err) => Err(Error::custom_source( "expected a valid string, escape was invalid", err).with_offset(offset.0)),
167            Ok(v) => f64::parse_smithy_primitive(v.as_ref())
168                // disregard the exact error
169                .map_err(|_|())
170                // only infinite / NaN can be used as strings
171                .and_then(must_not_be_finite)
172                .map(|float| Some(aws_smithy_types::Number::Float(float)))
173                // convert to a helpful error
174                .map_err(|_| {
175                    Error::custom(
176                        format!(
177                        "only `Infinity`, `-Infinity`, `NaN` can represent a float as a string but found `{}`",
178                        v
179                    )).with_offset(offset.0)
180                }),
181        },
182        _ => Err(Error::custom(
183            "expected ValueString, ValueNumber, or ValueNull",
184        )),
185    }
186}
187
188/// Expects a [Token::ValueString] or [Token::ValueNull]. If the value is a string, it interprets it as a base64 encoded [Blob] value.
189pub fn expect_blob_or_null(token: Option<Result<Token<'_>, Error>>) -> Result<Option<Blob>, Error> {
190    Ok(match expect_string_or_null(token)? {
191        Some(value) => Some(Blob::new(
192            base64::decode(value.as_escaped_str())
193                .map_err(|err| Error::custom_source("failed to decode base64", err))?,
194        )),
195        None => None,
196    })
197}
198
199/// Expects a [Token::ValueNull], [Token::ValueString], or [Token::ValueNumber] depending
200/// on the passed in `timestamp_format`. If there is a non-null value, it interprets it as an
201/// [`DateTime` ] in the requested format.
202pub fn expect_timestamp_or_null(
203    token: Option<Result<Token<'_>, Error>>,
204    timestamp_format: Format,
205) -> Result<Option<DateTime>, Error> {
206    Ok(match timestamp_format {
207        Format::EpochSeconds => expect_number_or_null(token)?
208            .map(|v| v.to_f64_lossy())
209            .map(|v| {
210                if v.is_nan() {
211                    Err(Error::custom("NaN is not a valid epoch"))
212                } else if v.is_infinite() {
213                    Err(Error::custom("infinity is not a valid epoch"))
214                } else {
215                    Ok(DateTime::from_secs_f64(v))
216                }
217            })
218            .transpose()?,
219        Format::DateTime | Format::HttpDate | Format::DateTimeWithOffset => {
220            expect_string_or_null(token)?
221                .map(|v| DateTime::from_str(v.as_escaped_str(), timestamp_format))
222                .transpose()
223                .map_err(|err| Error::custom_source("failed to parse timestamp", err))?
224        }
225    })
226}
227
228/// Expects and parses a complete document value.
229pub fn expect_document<'a, I>(tokens: &mut Peekable<I>) -> Result<Document, Error>
230where
231    I: Iterator<Item = Result<Token<'a>, Error>>,
232{
233    expect_document_inner(tokens, 0)
234}
235
236const MAX_DOCUMENT_RECURSION: usize = 256;
237
238fn expect_document_inner<'a, I>(tokens: &mut Peekable<I>, depth: usize) -> Result<Document, Error>
239where
240    I: Iterator<Item = Result<Token<'a>, Error>>,
241{
242    if depth >= MAX_DOCUMENT_RECURSION {
243        return Err(Error::custom(
244            "exceeded max recursion depth while parsing document",
245        ));
246    }
247    match tokens.next().transpose()? {
248        Some(Token::ValueNull { .. }) => Ok(Document::Null),
249        Some(Token::ValueBool { value, .. }) => Ok(Document::Bool(value)),
250        Some(Token::ValueNumber { value, .. }) => Ok(Document::Number(value)),
251        Some(Token::ValueString { value, .. }) => {
252            Ok(Document::String(value.to_unescaped()?.into_owned()))
253        }
254        Some(Token::StartObject { .. }) => {
255            let mut object = HashMap::new();
256            loop {
257                match tokens.next().transpose()? {
258                    Some(Token::EndObject { .. }) => break,
259                    Some(Token::ObjectKey { key, .. }) => {
260                        let key = key.to_unescaped()?.into_owned();
261                        let value = expect_document_inner(tokens, depth + 1)?;
262                        object.insert(key, value);
263                    }
264                    _ => return Err(Error::custom("expected object key or end object")),
265                }
266            }
267            Ok(Document::Object(object))
268        }
269        Some(Token::StartArray { .. }) => {
270            let mut array = Vec::new();
271            loop {
272                match tokens.peek() {
273                    Some(Ok(Token::EndArray { .. })) => {
274                        tokens.next().transpose().unwrap();
275                        break;
276                    }
277                    _ => array.push(expect_document_inner(tokens, depth + 1)?),
278                }
279            }
280            Ok(Document::Array(array))
281        }
282        Some(Token::EndObject { .. }) | Some(Token::ObjectKey { .. }) => {
283            unreachable!("end object and object key are handled in start object")
284        }
285        Some(Token::EndArray { .. }) => unreachable!("end array is handled in start array"),
286        None => Err(Error::custom("expected value")),
287    }
288}
289
290/// Skips an entire value in the token stream. Errors if it isn't a value.
291pub fn skip_value<'a>(
292    tokens: &mut impl Iterator<Item = Result<Token<'a>, Error>>,
293) -> Result<(), Error> {
294    skip_inner(0, tokens)
295}
296
297/// Assumes a start object/array token has already been consumed and skips tokens until
298/// until its corresponding end object/array token is found.
299pub fn skip_to_end<'a>(
300    tokens: &mut impl Iterator<Item = Result<Token<'a>, Error>>,
301) -> Result<(), Error> {
302    skip_inner(1, tokens)
303}
304
305fn skip_inner<'a>(
306    depth: isize,
307    tokens: &mut impl Iterator<Item = Result<Token<'a>, Error>>,
308) -> Result<(), Error> {
309    loop {
310        match tokens.next().transpose()? {
311            Some(Token::StartObject { .. }) | Some(Token::StartArray { .. }) => {
312                skip_inner(depth + 1, tokens)?;
313                if depth == 0 {
314                    break;
315                }
316            }
317            Some(Token::EndObject { .. }) | Some(Token::EndArray { .. }) => {
318                debug_assert!(depth > 0);
319                break;
320            }
321            Some(Token::ValueNull { .. })
322            | Some(Token::ValueBool { .. })
323            | Some(Token::ValueNumber { .. })
324            | Some(Token::ValueString { .. }) => {
325                if depth == 0 {
326                    break;
327                }
328            }
329            Some(Token::ObjectKey { .. }) => {}
330            _ => return Err(Error::custom("expected value")),
331        }
332    }
333    Ok(())
334}
335
336#[cfg(test)]
337pub mod test {
338    use super::*;
339    use crate::deserialize::error::DeserializeErrorKind as ErrorKind;
340    use crate::deserialize::error::DeserializeErrorKind::UnexpectedToken;
341    use crate::deserialize::json_token_iter;
342
343    pub fn start_array<'a>(offset: usize) -> Option<Result<Token<'a>, Error>> {
344        Some(Ok(Token::StartArray {
345            offset: Offset(offset),
346        }))
347    }
348
349    pub fn end_array<'a>(offset: usize) -> Option<Result<Token<'a>, Error>> {
350        Some(Ok(Token::EndArray {
351            offset: Offset(offset),
352        }))
353    }
354
355    pub fn start_object<'a>(offset: usize) -> Option<Result<Token<'a>, Error>> {
356        Some(Ok(Token::StartObject {
357            offset: Offset(offset),
358        }))
359    }
360
361    pub fn end_object<'a>(offset: usize) -> Option<Result<Token<'a>, Error>> {
362        Some(Ok(Token::EndObject {
363            offset: Offset(offset),
364        }))
365    }
366
367    pub fn object_key(offset: usize, key: &str) -> Option<Result<Token<'_>, Error>> {
368        Some(Ok(Token::ObjectKey {
369            offset: Offset(offset),
370            key: EscapedStr::new(key),
371        }))
372    }
373
374    pub fn value_bool<'a>(offset: usize, boolean: bool) -> Option<Result<Token<'a>, Error>> {
375        Some(Ok(Token::ValueBool {
376            offset: Offset(offset),
377            value: boolean,
378        }))
379    }
380
381    pub fn value_number<'a>(offset: usize, number: Number) -> Option<Result<Token<'a>, Error>> {
382        Some(Ok(Token::ValueNumber {
383            offset: Offset(offset),
384            value: number,
385        }))
386    }
387
388    pub fn value_null<'a>(offset: usize) -> Option<Result<Token<'a>, Error>> {
389        Some(Ok(Token::ValueNull {
390            offset: Offset(offset),
391        }))
392    }
393
394    pub fn value_string(offset: usize, string: &str) -> Option<Result<Token<'_>, Error>> {
395        Some(Ok(Token::ValueString {
396            offset: Offset(offset),
397            value: EscapedStr::new(string),
398        }))
399    }
400
401    #[track_caller]
402    fn expect_err_custom<T>(message: &str, offset: Option<usize>, result: Result<T, Error>) {
403        let err = result.err().expect("expected error");
404        let (actual_message, actual_offset) = match &err.kind {
405            ErrorKind::Custom { message, .. } => (message.as_ref(), err.offset),
406            _ => panic!("expected ErrorKind::Custom, got {:?}", err),
407        };
408        assert_eq!((message, offset), (actual_message, actual_offset));
409    }
410
411    #[test]
412    fn skip_simple_value() {
413        let mut tokens = json_token_iter(b"null true");
414        skip_value(&mut tokens).unwrap();
415        assert!(matches!(
416            tokens.next(),
417            Some(Ok(Token::ValueBool { value: true, .. }))
418        ))
419    }
420
421    #[test]
422    fn skip_array() {
423        let mut tokens = json_token_iter(b"[1, 2, 3, 4] true");
424        skip_value(&mut tokens).unwrap();
425        assert!(matches!(
426            tokens.next(),
427            Some(Ok(Token::ValueBool { value: true, .. }))
428        ))
429    }
430
431    #[test]
432    fn skip_object() {
433        let mut tokens = json_token_iter(b"{\"one\": 5, \"two\": 3} true");
434        skip_value(&mut tokens).unwrap();
435        assert!(matches!(
436            tokens.next(),
437            Some(Ok(Token::ValueBool { value: true, .. }))
438        ))
439    }
440
441    #[test]
442    fn test_skip_to_end() {
443        let tokens = json_token_iter(b"{\"one\": { \"two\": [] }, \"three\":2 }");
444        let mut tokens = tokens.skip(2);
445        assert!(matches!(tokens.next(), Some(Ok(Token::StartObject { .. }))));
446        skip_to_end(&mut tokens).unwrap();
447        match tokens.next() {
448            Some(Ok(Token::ObjectKey { key, .. })) => {
449                assert_eq!("three", key.as_escaped_str());
450            }
451            _ => panic!("expected object key three"),
452        }
453    }
454
455    #[test]
456    fn test_non_finite_floats() {
457        let mut tokens = json_token_iter(b"inf");
458        tokens
459            .next()
460            .expect("there is a token")
461            .expect_err("but it is invalid, ensure that Rust float boundary cases don't parse");
462    }
463
464    #[test]
465    fn mismatched_braces() {
466        // The skip_value function doesn't need to explicitly handle these cases since
467        // token iterator's parser handles them. This test confirms that assumption.
468        assert!(matches!(
469            skip_value(&mut json_token_iter(br#"[{"foo": 5]}"#)),
470            Err(Error {
471                kind: UnexpectedToken(']', "'}', ','"),
472                offset: Some(10)
473            })
474        ));
475        assert!(matches!(
476            skip_value(&mut json_token_iter(br#"{"foo": 5]}"#)),
477            Err(Error {
478                kind: UnexpectedToken(']', "'}', ','"),
479                offset: Some(9)
480            })
481        ));
482        assert!(matches!(
483            skip_value(&mut json_token_iter(br#"[5,6}"#)),
484            Err(Error {
485                kind: UnexpectedToken('}', "']', ','"),
486                offset: Some(4)
487            })
488        ));
489    }
490
491    #[test]
492    fn skip_nested() {
493        let mut tokens = json_token_iter(
494            br#"
495            {"struct": {"foo": 5, "bar": 11, "arr": [1, 2, 3, {}, 5, []]},
496             "arr": [[], [[]], [{"arr":[]}]],
497             "simple": "foo"}
498            true
499        "#,
500        );
501        skip_value(&mut tokens).unwrap();
502        assert!(matches!(
503            tokens.next(),
504            Some(Ok(Token::ValueBool { value: true, .. }))
505        ))
506    }
507
508    #[test]
509    fn test_expect_start_object() {
510        expect_err_custom(
511            "expected StartObject",
512            Some(2),
513            expect_start_object(value_bool(2, true)),
514        );
515        assert!(expect_start_object(start_object(0)).is_ok());
516    }
517
518    #[test]
519    fn test_expect_start_array() {
520        expect_err_custom(
521            "expected StartArray",
522            Some(2),
523            expect_start_array(value_bool(2, true)),
524        );
525        assert!(expect_start_array(start_array(0)).is_ok());
526    }
527
528    #[test]
529    fn test_expect_string_or_null() {
530        assert_eq!(None, expect_string_or_null(value_null(0)).unwrap());
531        assert_eq!(
532            Some(EscapedStr("test\\n")),
533            expect_string_or_null(value_string(0, "test\\n")).unwrap()
534        );
535        expect_err_custom(
536            "expected ValueString or ValueNull",
537            None,
538            expect_string_or_null(value_bool(0, true)),
539        );
540    }
541
542    #[test]
543    fn test_expect_number_or_null() {
544        assert_eq!(None, expect_number_or_null(value_null(0)).unwrap());
545        assert_eq!(
546            Some(Number::PosInt(5)),
547            expect_number_or_null(value_number(0, Number::PosInt(5))).unwrap()
548        );
549        expect_err_custom(
550            "expected ValueString, ValueNumber, or ValueNull",
551            None,
552            expect_number_or_null(value_bool(0, true)),
553        );
554        assert_eq!(
555            Some(Number::Float(f64::INFINITY)),
556            expect_number_or_null(value_string(0, "Infinity")).unwrap()
557        );
558        expect_err_custom(
559            "only `Infinity`, `-Infinity`, `NaN` can represent a float as a string but found `123`",
560            Some(0),
561            expect_number_or_null(value_string(0, "123")),
562        );
563        match expect_number_or_null(value_string(0, "NaN")) {
564            Ok(Some(Number::Float(v))) if v.is_nan() => {
565                // ok
566            }
567            not_ok => {
568                panic!("expected nan, found: {:?}", not_ok)
569            }
570        }
571    }
572
573    #[test]
574    fn test_expect_blob_or_null() {
575        assert_eq!(None, expect_blob_or_null(value_null(0)).unwrap());
576        assert_eq!(
577            Some(Blob::new(b"hello!".to_vec())),
578            expect_blob_or_null(value_string(0, "aGVsbG8h")).unwrap()
579        );
580        expect_err_custom(
581            "expected ValueString or ValueNull",
582            None,
583            expect_blob_or_null(value_bool(0, true)),
584        );
585    }
586
587    #[test]
588    fn test_expect_timestamp_or_null() {
589        assert_eq!(
590            None,
591            expect_timestamp_or_null(value_null(0), Format::HttpDate).unwrap()
592        );
593        for (invalid, display_name) in &[
594            ("NaN", "NaN"),
595            ("Infinity", "infinity"),
596            ("-Infinity", "infinity"),
597        ] {
598            expect_err_custom(
599                format!("{display_name} is not a valid epoch").as_str(),
600                None,
601                expect_timestamp_or_null(value_string(0, invalid), Format::EpochSeconds),
602            );
603        }
604        assert_eq!(
605            Some(DateTime::from_secs_f64(2048.0)),
606            expect_timestamp_or_null(value_number(0, Number::Float(2048.0)), Format::EpochSeconds)
607                .unwrap()
608        );
609        assert_eq!(
610            Some(DateTime::from_secs_f64(1445412480.0)),
611            expect_timestamp_or_null(
612                value_string(0, "Wed, 21 Oct 2015 07:28:00 GMT"),
613                Format::HttpDate
614            )
615            .unwrap()
616        );
617        assert_eq!(
618            Some(DateTime::from_secs_f64(1445412480.0)),
619            expect_timestamp_or_null(value_string(0, "2015-10-21T07:28:00Z"), Format::DateTime)
620                .unwrap()
621        );
622        expect_err_custom(
623                "only `Infinity`, `-Infinity`, `NaN` can represent a float as a string but found `wrong`",
624                Some(0),
625            expect_timestamp_or_null(value_string(0, "wrong"), Format::EpochSeconds)
626        );
627        expect_err_custom(
628            "expected ValueString or ValueNull",
629            None,
630            expect_timestamp_or_null(value_number(0, Number::Float(0.0)), Format::DateTime),
631        );
632    }
633
634    #[test]
635    fn test_expect_document() {
636        let test = |value| expect_document(&mut json_token_iter(value).peekable()).unwrap();
637        assert_eq!(Document::Null, test(b"null"));
638        assert_eq!(Document::Bool(true), test(b"true"));
639        assert_eq!(Document::Number(Number::Float(3.2)), test(b"3.2"));
640        assert_eq!(Document::String("Foo\nBar".into()), test(b"\"Foo\\nBar\""));
641        assert_eq!(Document::Array(Vec::new()), test(b"[]"));
642        assert_eq!(Document::Object(HashMap::new()), test(b"{}"));
643        assert_eq!(
644            Document::Array(vec![
645                Document::Number(Number::PosInt(1)),
646                Document::Bool(false),
647                Document::String("s".into()),
648                Document::Array(Vec::new()),
649                Document::Object(HashMap::new()),
650            ]),
651            test(b"[1,false,\"s\",[],{}]")
652        );
653        assert_eq!(
654            Document::Object(
655                vec![
656                    ("num".to_string(), Document::Number(Number::PosInt(1))),
657                    ("bool".to_string(), Document::Bool(true)),
658                    ("string".to_string(), Document::String("s".into())),
659                    (
660                        "array".to_string(),
661                        Document::Array(vec![
662                            Document::Object(
663                                vec![("foo".to_string(), Document::Bool(false))]
664                                    .into_iter()
665                                    .collect(),
666                            ),
667                            Document::Object(
668                                vec![("bar".to_string(), Document::Bool(true))]
669                                    .into_iter()
670                                    .collect(),
671                            ),
672                        ])
673                    ),
674                    (
675                        "nested".to_string(),
676                        Document::Object(
677                            vec![("test".to_string(), Document::Null),]
678                                .into_iter()
679                                .collect()
680                        )
681                    ),
682                ]
683                .into_iter()
684                .collect()
685            ),
686            test(
687                br#"
688                { "num": 1,
689                  "bool": true,
690                  "string": "s",
691                  "array":
692                      [{ "foo": false },
693                       { "bar": true }],
694                  "nested": { "test": null } }
695                "#
696            )
697        );
698    }
699
700    #[test]
701    fn test_document_recursion_limit() {
702        let mut value = String::new();
703        value.extend(std::iter::repeat('[').take(300));
704        value.extend(std::iter::repeat(']').take(300));
705        expect_err_custom(
706            "exceeded max recursion depth while parsing document",
707            None,
708            expect_document(&mut json_token_iter(value.as_bytes()).peekable()),
709        );
710
711        value = String::new();
712        value.extend(std::iter::repeat("{\"t\":").take(300));
713        value.push('1');
714        value.extend(std::iter::repeat('}').take(300));
715        expect_err_custom(
716            "exceeded max recursion depth while parsing document",
717            None,
718            expect_document(&mut json_token_iter(value.as_bytes()).peekable()),
719        );
720    }
721}