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