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