Skip to main content

bufjson/lexical/
fixed.rs

1//! Convert a fixed-size in-memory buffer into a stream of JSON lexical tokens.
2
3#[cfg(feature = "num")]
4use crate::lexical::{NumError, parse_f64_result, parse_int_err};
5use crate::{
6    Pos,
7    lexical::{
8        self, state, {Analyzer, ErrorKind, Token, Unescaped},
9    },
10    syntax,
11};
12use alloc::{string::String, sync::Arc, vec::Vec};
13#[cfg(feature = "num")]
14use core::str::FromStr;
15use core::{
16    cmp::Ordering,
17    fmt,
18    ops::{Deref, Range},
19};
20
21#[derive(Clone, Debug)]
22struct Ref<B> {
23    buf: Arc<B>,
24    rng: Range<usize>,
25}
26
27impl<B: Deref<Target = [u8]>> Ref<B> {
28    fn new(buf: Arc<B>, rng: Range<usize>) -> Ref<B> {
29        Self { buf, rng }
30    }
31
32    fn as_str(&self) -> &str {
33        unsafe { core::str::from_utf8_unchecked(&self.buf[self.rng.start..self.rng.end]) }
34    }
35}
36
37const INLINE_LEN: usize = 30;
38
39type InlineBuf = [u8; INLINE_LEN];
40
41#[derive(Clone, Debug)]
42enum InnerContent<B: Deref<Target = [u8]>> {
43    Static(&'static str),
44    Inline(u8, InlineBuf),
45    NotEscaped(Ref<B>),
46    Escaped(Ref<B>),
47}
48
49/// Text content of a JSON token identified by a [`FixedAnalyzer`].
50///
51/// See the [`lexical::Content`] trait, implemented by this struct, for detailed conceptual
52/// documentation.
53#[derive(Clone, Debug)]
54pub struct Content<B: Deref<Target = [u8]> + fmt::Debug>(InnerContent<B>);
55
56impl Content<Vec<u8>> {
57    /// Constructs a new `Content` value from a static lifetime string that contains a valid JSON
58    /// token.
59    ///
60    /// The entire string must be a single valid lexical token. It may be the empty string, which is
61    /// equivalent to `Token::Eof`; or may be all whitespace, equivalent to [`Token::White`]. String
62    /// token content must begin and end with a double quote character.
63    ///
64    /// # Panics
65    ///
66    /// Panics if the string is not valid JSON token content.
67    ///
68    /// # Example
69    ///
70    /// ```
71    /// # use bufjson::lexical::fixed::Content;
72    /// let obj_begin = Content::from_static("{");
73    /// assert_eq!("{", obj_begin.literal());
74    /// assert!(!obj_begin.is_escaped());
75    ///
76    /// let str_escaped = Content::from_static(r#""hello\nworld""#);
77    /// assert_eq!(r#""hello\nworld""#, str_escaped.literal());
78    /// assert!(str_escaped.is_escaped());
79    /// assert_eq!(r#""hello
80    /// world""#, str_escaped.unescaped());
81    /// ```
82    pub fn from_static(s: &'static str) -> Self {
83        let b = s.as_bytes();
84        match state::Machine::verify_static(b) {
85            false => Self(InnerContent::Static(s)),
86            true => Self(InnerContent::Escaped(Ref::new(
87                Arc::new(b.to_vec()),
88                0..b.len(),
89            ))),
90        }
91    }
92}
93
94impl<B: Deref<Target = [u8]> + fmt::Debug> Content<B> {
95    /// Returns the literal content of the token exactly as it appears in the JSON text.
96    ///
97    /// This is an inherent implementation of [`lexical::Content::literal`] for convenience, so it
98    /// is available even when you don't have the trait imported. Refer to the trait documentation
99    /// for conceptual details.
100    #[inline]
101    pub fn literal(&self) -> &str {
102        match &self.0 {
103            InnerContent::Static(s) => s,
104            InnerContent::Inline(len, buf) => Self::inline_str(*len, buf),
105            InnerContent::NotEscaped(r) | InnerContent::Escaped(r) => r.as_str(),
106        }
107    }
108
109    /// Returns the number of bytes in the [`literal`] value.
110    ///
111    /// [`literal`]: method@Self::literal
112    #[inline]
113    pub fn literal_len(&self) -> usize {
114        match &self.0 {
115            InnerContent::Static(s) => s.len(),
116            InnerContent::Inline(len, _) => *len as usize,
117            InnerContent::NotEscaped(r) | InnerContent::Escaped(r) => r.rng.end - r.rng.start,
118        }
119    }
120
121    /// Indicates whether the token content contains escape sequences.
122    ///
123    /// This is an inherent implementation of [`lexical::Content::is_escaped`] for convenience, so
124    /// it is available even when you don't have the trait imported. Refer to the trait
125    /// documentation for conceptual details.
126    #[inline(always)]
127    pub fn is_escaped(&self) -> bool {
128        matches!(self.0, InnerContent::Escaped(_))
129    }
130
131    /// Returns a normalized version of [`literal`]` with all escape sequences in the JSON text
132    /// fully expanded.
133    ///
134    /// This is an inherent implementation of [`lexical::Content::unescaped`] for convenience, so
135    /// it is available even when you don't have the trait imported. Refer to the trait
136    /// documentation for conceptual details.
137    ///
138    /// # Performance considerations
139    ///
140    /// - If this content belongs to a non-string token, or a string token that contains no escape
141    ///   sequences, does not allocate, and simply returns an [`Unescaped::Literal`] wrapping the
142    ///   borrow returned by [`literal`], which is a reference to the internals of this content.
143    /// - If this content belongs to a string token containing at least one escape sequence,
144    ///   allocates a new owned string value containing the unescaped string content and returns it
145    ///   wrapped in [`Unescaped::Expanded`].
146    ///
147    /// [`literal`]: method@Self::literal
148    pub fn unescaped(&self) -> Unescaped<&str> {
149        match &self.0 {
150            InnerContent::Static(s) => Unescaped::Literal(s),
151            InnerContent::Inline(len, buf) => Unescaped::Literal(Self::inline_str(*len, buf)),
152            InnerContent::NotEscaped(r) => Unescaped::Literal(r.as_str()),
153            InnerContent::Escaped(r) => {
154                let mut buf = Vec::new();
155                lexical::unescape(r.as_str(), &mut buf);
156
157                // SAFETY: `r` was valid UTF-8 before it was de-escaped, and the de-escaping process
158                //         maintains UTF-8 safety.
159                let s = unsafe { String::from_utf8_unchecked(buf) };
160
161                Unescaped::Expanded(s)
162            }
163        }
164    }
165
166    /// Compares the token content to another string, expanding embedded escape sequences.
167    ///
168    /// For non-string tokens, and string tokens for which [`is_escaped`] returns `false`, this
169    /// method returns the equivalent of `self.literal().cmp(other)`.
170    ///
171    /// For string tokens with one or more escape sequences, this method compares a normalized
172    /// version of the string value with escape sequences expanded to `other`. It gives the same
173    /// result as `self.unescaped().cmp(other)`, but is faster because it avoids the accompanying
174    /// allocations and copying.
175    ///
176    /// Note two important details. First, no unescaping is done on `other`, which is assumed to
177    /// contain a string with escape sequences fully expanded. Second, apart from expanding escape
178    /// sequences, `self` is compared byte-for-byte against `other`, so if `self` contains the
179    /// content of a string token, then `other` will need to begin and end with a quotation mark
180    /// character, `"` (U+0022) in order to compare equal.
181    ///
182    /// # Performance considerations
183    ///
184    /// Does not allocate.
185    ///
186    /// Since this method is marginally less efficient than comparing directly against the literal
187    /// value, it is preferable to use it only when `is_escaped` returns `true`.
188    ///
189    /// # Example
190    ///
191    /// ```
192    /// use bufjson::lexical::{Token, fixed::FixedAnalyzer};
193    /// use std::cmp::Ordering;
194    ///
195    /// let mut an = FixedAnalyzer::new(&br#""hello\nworld! \ud83c\udf0d""#[..]);
196    ///
197    /// assert_eq!(Token::Str, an.next());
198    /// assert_eq!(
199    ///     Ordering::Equal, an.content().unescaped_cmp(r#""hello
200    /// world! 🌍""#));
201    /// ```
202    ///
203    /// [`is_escaped`]: method@Self::is_escaped
204    pub fn unescaped_cmp(&self, other: &str) -> Ordering {
205        let mut a = self.literal().as_bytes();
206        let mut b = other.as_bytes();
207        loop {
208            match a.iter().position(|&b| b == b'\\') {
209                None => return a.cmp(b),
210                Some(i) => {
211                    let o = a[..i].cmp(&b[..i.min(b.len())]);
212                    if o != Ordering::Equal {
213                        return o;
214                    } else if i >= b.len() {
215                        return Ordering::Greater;
216                    }
217                    let y = b[i];
218                    match lexical::unescape_byte(a[i + 1]) {
219                        lexical::UnescapeByte::Byte(x) if x != y => return x.cmp(&y),
220                        lexical::UnescapeByte::Byte(_) => {
221                            a = &a[i + 2..];
222                            b = &b[i + 1..];
223                        }
224                        lexical::UnescapeByte::Unicode => {
225                            a = &a[i + 2..];
226                            let (x, n) = lexical::unescape_unicode(&mut a);
227                            let n = n as usize;
228                            let o = x[..n].cmp(&b[i..i + n.min(b.len() - i)]);
229                            if o != Ordering::Equal {
230                                return o;
231                            }
232                            b = &b[i + n..];
233                        }
234                    }
235                }
236            }
237        }
238    }
239
240    /// Converts the token content to a 64-bit signed integer.
241    ///
242    /// This is an inherent implementation of [`lexical::Content::parse_i64`] for convenience, so it
243    /// is available even when you don't have the trait imported.
244    ///
245    /// # Performance considerations
246    ///
247    /// This implementation is faster than [`lexical::parse_i64`] because it is optimized for the
248    /// fixed-size buffer case and does not need to handle the possibility that the number text
249    /// might be split across multiple buffers. It never allocates or copies.
250    ///
251    /// # Example
252    ///
253    /// ```
254    /// use bufjson::lexical::{Token, fixed::FixedAnalyzer};
255    ///
256    /// let mut an = FixedAnalyzer::new(&b"[123]"[..]);
257    ///
258    /// assert_eq!(Token::ArrBegin, an.next());
259    /// assert_eq!(Token::Num, an.next());
260    /// assert_eq!(Ok(123), an.content().parse_i64());
261    /// assert_eq!(Token::ArrEnd, an.next());
262    /// ```
263    #[cfg(feature = "num")]
264    #[inline]
265    pub fn parse_i64(&self) -> Result<i64, NumError> {
266        let chunk = self.literal().as_bytes();
267
268        parse_int!(one_slice, chunk, i64, 1, i64::MIN)
269    }
270
271    /// Converts the token content to a 64-bit unsigned integer.
272    ///
273    /// This is an inherent implementation of [`lexical::Content::parse_u64`] for convenience, so it
274    /// is available even when you don't have the trait imported.
275    ///
276    /// # Performance considerations
277    ///
278    /// This implementation is faster than [`lexical::parse_u64`] because it is optimized for the
279    /// fixed-size buffer case and does not need to handle the possibility that the number text
280    /// might be split across multiple buffers. It never allocates or copies.
281    ///
282    /// # Example
283    ///
284    /// ```
285    /// use bufjson::lexical::{Token, fixed::FixedAnalyzer};
286    ///
287    /// let mut an = FixedAnalyzer::new(&b"[123]"[..]);
288    ///
289    /// assert_eq!(Token::ArrBegin, an.next());
290    /// assert_eq!(Token::Num, an.next());
291    /// assert_eq!(Ok(123), an.content().parse_u64());
292    /// assert_eq!(Token::ArrEnd, an.next());
293    /// ```
294    #[cfg(feature = "num")]
295    #[inline]
296    pub fn parse_u64(&self) -> Result<u64, NumError> {
297        let chunk = self.literal().as_bytes();
298
299        parse_int!(one_slice, chunk, u64, 0, u64::MAX)
300    }
301
302    /// Converts the token content to a 128-bit signed integer.
303    ///
304    /// This is an inherent implementation of [`lexical::Content::parse_i128`] for convenience, so
305    /// it is available even when you don't have the trait imported.
306    ///
307    /// # Performance considerations
308    ///
309    /// This method is faster than [`lexical::parse_i128`] because it is optimized for the
310    /// fixed-size buffer case and does not need to handle the possibility that the number text
311    /// might be split across multiple buffers. It never allocates or copies.
312    ///
313    /// # Example
314    ///
315    /// ```
316    /// use bufjson::lexical::{Token, fixed::FixedAnalyzer};
317    ///
318    /// const TEXT: &str = r#"{"10^38":100000000000000000000000000000000000000}"#;
319    ///
320    /// let mut an = FixedAnalyzer::new(TEXT.as_bytes());
321    ///
322    /// assert_eq!(Token::ObjBegin, an.next());
323    /// assert_eq!(Token::Str, an.next());
324    /// assert_eq!(Token::NameSep, an.next());
325    /// assert_eq!(Token::Num, an.next());
326    /// assert_eq!(Ok(10_i128.pow(38)), an.content().parse_i128());
327    /// assert_eq!(Token::ObjEnd, an.next());
328    /// ```
329    #[cfg(feature = "num_ext")]
330    #[inline]
331    pub fn parse_i128(&self) -> Result<i128, NumError> {
332        let chunk = self.literal().as_bytes();
333
334        parse_int!(one_slice, chunk, i128, 1, i128::MIN)
335    }
336
337    /// Converts the token content to a 64-bit IEEE double precision floating point number.
338    ///
339    /// This is an inherent implementation of [`lexical::Content::parse_f64`] for convenience, so it
340    /// is available even when you don't have the trait imported.
341    ///
342    /// # Performance considerations
343    ///
344    /// This method is faster than [`lexical::parse_f64`] because it is optimized for the fixed-size
345    /// buffer case and does not need to handle the possibility that the number text might be split
346    /// across multiple buffers. It never allocates or copies.
347    ///
348    /// # Example
349    ///
350    /// ```
351    /// use bufjson::lexical::{Token, fixed::FixedAnalyzer};
352    ///
353    /// let mut an = FixedAnalyzer::new(&br#"{"pi":3.14159}"#[..]);
354    ///
355    /// assert_eq!(Token::ObjBegin, an.next());
356    /// assert_eq!(Token::Str, an.next());
357    /// assert_eq!(Token::NameSep, an.next());
358    /// assert_eq!(Token::Num, an.next());
359    /// assert_eq!(Ok(3.14159), an.content().parse_f64());
360    /// assert_eq!(Token::ObjEnd, an.next());
361    /// ```
362    #[cfg(feature = "num")]
363    #[inline]
364    pub fn parse_f64(&self) -> Result<f64, NumError> {
365        parse_f64_result(f64::from_str(self.literal()))
366    }
367}
368
369impl<B: Deref<Target = [u8]> + fmt::Debug> Content<B> {
370    fn from_buf(buf: &Arc<B>, r: Range<usize>, escaped: bool) -> Self {
371        debug_assert!(r.start <= r.end);
372        debug_assert!(r.end <= buf.len());
373
374        let len = r.end - r.start;
375
376        if len <= INLINE_LEN && !escaped {
377            let mut inner: InlineBuf = [0; INLINE_LEN];
378            inner[..len].copy_from_slice(&buf[r]);
379
380            Self(InnerContent::Inline(len as u8, inner))
381        } else {
382            let r = Ref::new(Arc::clone(buf), r);
383
384            Self(if !escaped {
385                InnerContent::NotEscaped(r)
386            } else {
387                InnerContent::Escaped(r)
388            })
389        }
390    }
391
392    fn inline_str(len: u8, buf: &InlineBuf) -> &str {
393        unsafe { core::str::from_utf8_unchecked(&buf[0..len as usize]) }
394    }
395}
396
397impl Default for Content<Vec<u8>> {
398    fn default() -> Self {
399        Self(InnerContent::Static("")) // Equivalent to EOF
400    }
401}
402
403impl<B: Deref<Target = [u8]> + fmt::Debug> fmt::Display for Content<B> {
404    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
405        f.write_str(self.literal())
406    }
407}
408
409impl<B: Deref<Target = [u8]> + fmt::Debug> super::Content for Content<B> {
410    type Literal<'a>
411        = &'a str
412    where
413        Self: 'a;
414
415    #[inline(always)]
416    fn literal<'a>(&'a self) -> Self::Literal<'a> {
417        Content::literal(self)
418    }
419
420    #[inline(always)]
421    fn literal_len(&self) -> usize {
422        Content::literal_len(self)
423    }
424
425    #[inline(always)]
426    fn is_escaped(&self) -> bool {
427        Content::is_escaped(self)
428    }
429
430    #[inline(always)]
431    fn unescaped<'a>(&'a self) -> Unescaped<Self::Literal<'a>> {
432        Content::unescaped(self)
433    }
434
435    #[inline(always)]
436    fn unescaped_cmp(&self, other: &str) -> Ordering {
437        Content::unescaped_cmp(self, other)
438    }
439
440    #[cfg(feature = "num")]
441    #[inline(always)]
442    fn parse_i64(&self) -> Result<i64, NumError> {
443        Content::parse_i64(self)
444    }
445
446    #[cfg(feature = "num")]
447    #[inline(always)]
448    fn parse_u64(&self) -> Result<u64, NumError> {
449        Content::parse_u64(self)
450    }
451
452    #[cfg(feature = "num_ext")]
453    #[inline(always)]
454    fn parse_i128(&self) -> Result<i128, NumError> {
455        Content::parse_i128(self)
456    }
457
458    #[cfg(feature = "num")]
459    #[inline(always)]
460    fn parse_f64(&self) -> Result<f64, NumError> {
461        Content::parse_f64(self)
462    }
463}
464
465// Assert that `Content` does not grow beyond 32 bytes (four 64-bit words).
466#[cfg(target_pointer_width = "64")]
467const _: [(); 32] = [(); core::mem::size_of::<Content<Vec<u8>>>()];
468
469/// Lexical analysis error detected by a [`FixedAnalyzer`].
470///
471/// See the [`lexical::Error`] trait, implemented by this struct, for further documentation.
472#[derive(Copy, Clone, Debug)]
473pub struct Error {
474    kind: ErrorKind,
475    pos: Pos,
476}
477
478impl Error {
479    /// Returns the category of error.
480    ///
481    /// This is an inherent implementation of [`lexical::Error::kind`] for convenience, so it is
482    /// available even when you don't have the trait imported.
483    #[inline(always)]
484    pub fn kind(&self) -> ErrorKind {
485        self.kind
486    }
487
488    /// Returns the position in the JSON text where the error was encountered.
489    ///
490    /// This is an inherent implementation of [`lexical::Error::pos`] for convenience, so it is
491    /// available even when you don't have the trait imported.
492    #[inline(always)]
493    pub fn pos(&self) -> &Pos {
494        &self.pos
495    }
496}
497
498impl fmt::Display for Error {
499    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
500        self.kind.fmt_at(f, Some(&self.pos))
501    }
502}
503
504impl core::error::Error for Error {}
505
506impl lexical::Error for Error {
507    #[inline(always)]
508    fn kind(&self) -> ErrorKind {
509        Error::kind(self)
510    }
511
512    #[inline(always)]
513    fn pos(&self) -> &Pos {
514        Error::pos(self)
515    }
516}
517
518#[derive(Copy, Clone, Debug)]
519struct StoredContent {
520    len: usize,
521    escaped: bool,
522}
523
524impl StoredContent {
525    #[inline(always)]
526    fn new(len: usize, escaped: bool) -> Self {
527        Self { len, escaped }
528    }
529}
530
531impl Default for StoredContent {
532    fn default() -> Self {
533        Self::new(0, false)
534    }
535}
536
537/// A [`lexical::Analyzer`] to tokenize fixed buffers of JSON text.
538///
539/// Use `FixedAnalyzer` for zero-allocation, low-copy, stream-oriented lexical analysis of any
540/// pre-allocated fixed-size buffer of JSON text.
541///
542/// As with any [`lexical::Analyzer`] implementation, you can construct a [`syntax::Parser`] from a
543/// `FixedAnalyzer` to unlock richer stream-oriented syntactic analysis while retaining low overhead
544/// guarantees of the underlying lexical analyzer.
545///
546/// # Performance considerations
547///
548/// The [`next`] method never allocates or copies and has very low overhead, above and beyond just
549/// examining the bytes of the next token in the buffer, for doing state transitions and remembering
550/// state.
551///
552/// The [`content`] method never allocates. For punctuation and literal tokens, it never copies. For
553/// number and string tokens, it may copy if the token is very short; otherwise, it just returns a
554/// reference-counted slice of the internal buffer that was passed to [`new`].
555///
556/// It should be noted that the `Content` structure returned by [`content`] is somewhat "fat", at 32
557/// bytes; it is preferable not to fetch it for tokens where the content is either statically
558/// knowable (literals and punctuation) or not required (*e.g.*, whitespace in some applications).
559///
560/// [Unescaping][`lexical::Content::unescaped`] a [`Content`] value that contains an escaped string
561/// token always allocates; but calling `unescaped` on a `Content` value that does not contain any
562/// escape sequences is a no-op that neither allocates nor does any other work.
563///
564/// # Memory considerations
565///
566/// Because the [`Content`] for longer string and number tokens directly reference slices of the
567/// buffer, the buffer will not be dropped until all of these [`Content`] values are dropped.
568///
569/// # Examples
570///
571/// Scan a static string slice into tokens:
572///
573/// ```
574/// use bufjson::lexical::{Token, fixed::FixedAnalyzer};
575///
576/// let mut lexer = FixedAnalyzer::new(r#"[123, "abc"]"#.as_bytes());
577///
578/// assert_eq!(Token::ArrBegin, lexer.next());
579/// assert_eq!(Token::Num, lexer.next());
580/// assert_eq!(Token::ValueSep, lexer.next());
581/// assert_eq!(Token::White, lexer.next());
582/// assert_eq!(Token::Str, lexer.next());
583/// assert_eq!(Token::ArrEnd, lexer.next());
584/// assert_eq!(Token::Eof, lexer.next());
585/// ```
586///
587/// Create a parser wrapping a `FixedAnalyzer` that scans a `Vec<u8>`.
588///
589/// ```
590/// use bufjson::{lexical::{Token, fixed::FixedAnalyzer}, syntax::Parser};
591///
592/// let vec = b"  {\"flag\": true}".to_vec();
593/// let mut parser = FixedAnalyzer::new(vec).into_parser();
594///
595/// assert_eq!(Token::ObjBegin, parser.next_meaningful());
596/// assert_eq!(Token::Str, parser.next_meaningful());
597/// assert_eq!(Token::LitTrue, parser.next_meaningful());
598/// assert_eq!(Token::ObjEnd, parser.next_meaningful());
599/// assert_eq!(Token::Eof, parser.next_meaningful());
600/// ```
601///
602/// [`syntax::Parser`]: crate::syntax::Parser
603/// [`new`]: method@Self::new
604/// [`next`]: method@Self::next
605/// [`content`]: method@Self::content
606pub struct FixedAnalyzer<B: Deref<Target = [u8]> + fmt::Debug> {
607    buf: Arc<B>,
608    content: StoredContent,
609    err: Option<Error>,
610    mach: state::Machine<state::DerefBuf<B, Arc<B>>>,
611    pos: Pos,
612}
613
614impl<B: Deref<Target = [u8]> + fmt::Debug> Clone for FixedAnalyzer<B> {
615    fn clone(&self) -> Self {
616        Self {
617            buf: Arc::clone(&self.buf),
618            content: self.content,
619            err: self.err,
620            mach: self.mach.clone(),
621            pos: self.pos,
622        }
623    }
624}
625
626impl<B: Deref<Target = [u8]> + fmt::Debug> FixedAnalyzer<B> {
627    /// Constructs a new lexer to tokenize a fixed in-memory buffer.
628    ///
629    /// The buffer can be anything that implements `Deref<Target = [u8]>`, including `&[u8]`,
630    /// `Vec<u8>`, `Cow<'_, [u8]>` and data types such as `bytes::Bytes` from the `bytes` crate.
631    /// For non-trivial tokens, the token [content][method@Self::content] is referenced directly
632    /// into the buffer.
633    ///
634    /// # Examples
635    ///
636    /// ```
637    /// # use bufjson::lexical::fixed::FixedAnalyzer;
638    /// let mut lexer: FixedAnalyzer<Vec<u8>> = FixedAnalyzer::new(vec![b'n', b'u', b'l', b'l']);
639    /// ```
640    pub fn new(buf: B) -> Self {
641        let buf = Arc::new(buf);
642        let mach = state::Machine::new(state::DerefBuf::new(Arc::clone(&buf)));
643        let content = StoredContent::default();
644        let err = None;
645        let pos = Pos::default();
646
647        Self {
648            buf,
649            content,
650            err,
651            pos,
652            mach,
653        }
654    }
655
656    /// Recognizes the next lexical token in the buffer without allocating or copying.
657    ///
658    /// This is an inherent implementation of [`lexical::Analyzer::next`] for convenience, so it is
659    /// available even when you don't have the trait imported.
660    ///
661    /// # Example
662    ///
663    /// ```
664    /// # use bufjson::lexical::{Token, fixed::FixedAnalyzer};
665    /// let mut lexer = FixedAnalyzer::new(&b"99.9e-1"[..]);
666    /// assert_eq!(Token::Num, lexer.next());
667    /// assert_eq!(Token::Eof, lexer.next());
668    /// assert_eq!(Token::Eof, lexer.next()); // Once EOF is reached, it is returned to infinity.
669    /// ```
670    #[allow(clippy::should_implement_trait)]
671    pub fn next(&mut self) -> Token {
672        if self.err.is_some() {
673            return Token::Err;
674        }
675
676        self.pos = *self.mach.pos();
677
678        match self.mach.next() {
679            state::Next::Done(token, escaped, n) => {
680                self.content = StoredContent::new(n, escaped);
681
682                token
683            }
684            state::Next::Part(token, n) => match self.mach.end() {
685                state::End::Done => {
686                    self.content = StoredContent::new(n, false);
687
688                    token
689                }
690                state::End::Nil => unreachable!(),
691                state::End::Err => {
692                    let kind = self.mach.err_kind().expect("there should be an error kind");
693                    let pos = *self.mach.pos();
694                    self.err = Some(Error { kind, pos });
695
696                    Token::Err
697                }
698            },
699            state::Next::Nil => {
700                self.content = StoredContent::default();
701
702                Token::Eof
703            }
704            state::Next::Err(_) => {
705                let kind = self.mach.err_kind().expect("there should be an error kind");
706                let pos = *self.mach.pos();
707                self.err = Some(Error { kind, pos });
708
709                Token::Err
710            }
711        }
712    }
713
714    /// Fetches the text content of the most recent non-error token without allocating.
715    ///
716    /// No copying is done except possibly for very small number and string tokens. Larger number
717    /// and string tokens directly reference slices of the buffer, without any copying.
718    ///
719    /// This is an inherent implementation of [`lexical::Analyzer::content`] for convenience, so it
720    /// is available even when you don't have the trait imported.
721    ///
722    /// # Panics
723    ///
724    /// Panics if the most recent token returned by [`next`] was [`Token::Err`].
725    ///
726    /// # Examples
727    ///
728    /// ```
729    /// # use bufjson::lexical::{Token, fixed::FixedAnalyzer};
730    /// let mut lexer = FixedAnalyzer::new(&b"  1.0"[..]);
731    ///
732    /// assert_eq!(Token::White, lexer.next());
733    /// assert_eq!("  ", lexer.content().literal());
734    ///
735    /// assert_eq!(Token::Num, lexer.next());
736    /// assert_eq!("1.0", lexer.content().literal());
737    /// ```
738    ///
739    /// [`next`]: method@Self::next
740    #[inline]
741    pub fn content(&self) -> Content<B> {
742        if let Ok(content) = self.try_content() {
743            content
744        } else {
745            panic!("no content: last `next()` returned `Token::Err` (use `err()` instead)");
746        }
747    }
748
749    /// Fetches the error value associated with the most recent error token.
750    ///
751    /// No copying or allocation is done.
752    ///
753    /// This is an inherent implementation of [`lexical::Analyzer::err`] for convenience, so it is
754    /// available even when you don't have the trait imported.
755    ///
756    /// # Panics
757    ///
758    /// Panics if the most recent token returned by [`next`] was not [`Token::Err`].
759    ///
760    /// # Examples
761    ///
762    /// ```
763    /// use bufjson::lexical::{ErrorKind, Expect, Token, fixed::FixedAnalyzer};
764    ///
765    /// let mut lexer = FixedAnalyzer::new(&b"error!"[..]);
766    ///
767    /// assert_eq!(Token::Err, lexer.next());
768    /// assert!(matches!(
769    ///     lexer.err().kind(),
770    ///     ErrorKind::UnexpectedByte { token: None, expect: Expect::TokenStartChar, actual: b'e'}
771    /// ));
772    /// ```
773    ///
774    /// [`next`]: method@Self::next
775    #[inline]
776    pub fn err(&self) -> Error {
777        if let Err(err) = self.try_content() {
778            err
779        } else {
780            panic!("no error: last `next()` did not return `Token::Err` (use `content()` instead)");
781        }
782    }
783
784    /// Returns the position of the start of the token most recently scanned by [`next`].
785    ///
786    /// This is an inherent implementation of [`lexical::Analyzer::pos`] for convenience, so it is
787    /// available even when you don't have the trait imported.
788    ///
789    /// # Examples
790    ///
791    /// Before any token is scanned, the position is the default position.
792    ///
793    /// ```
794    /// # use bufjson::{Pos, lexical::fixed::FixedAnalyzer};
795    /// assert_eq!(Pos::default(), *FixedAnalyzer::new(&b""[..]).pos());
796    /// ```
797    ///
798    /// The position of the first token returned is always the start of the buffer.
799    ///
800    /// ```
801    /// use bufjson::{Pos, lexical::{Token, fixed::FixedAnalyzer}};
802    ///
803    /// let mut lexer = FixedAnalyzer::new(&b" \n"[..]);
804    ///
805    /// // Read the two-byte whitespace token that starts at offset 0.
806    /// assert_eq!(Token::White, lexer.next());
807    /// assert_eq!(Pos::default(), *lexer.pos());
808    ///
809    /// // The EOF token starts at the end of the whitespace token.
810    /// assert_eq!(Token::Eof, lexer.next());
811    /// assert_eq!(Pos { offset: 2, line: 2, col: 1}, *lexer.pos());
812    /// ```
813    ///
814    /// On errors, the position reported by `pos` may be different from the position reported by the
815    /// error returned from [`err`]. This is because the `pos` indicates the start of the token
816    /// where the error occurred, and the error position is the exact position of the error.
817    ///
818    /// ```
819    /// use bufjson::{Pos, lexical::{Token, fixed::FixedAnalyzer}};
820    ///
821    /// let mut lexer = FixedAnalyzer::new(&b"123_"[..]);
822    ///
823    /// assert_eq!(Token::Err, lexer.next());
824    /// // `pos` is at the start of the number token that has the problem...
825    /// assert_eq!(Pos::default(), *lexer.pos());
826    /// // ...but the error contains the exact problem position: offset 3, column 4.
827    /// assert_eq!(Pos { offset: 3, line: 1, col: 4 }, *lexer.err().pos())
828    /// ```
829    ///
830    /// [`next`]: method@Self::next
831    /// [`err`]: method@Self::err
832    #[inline(always)]
833    pub fn pos(&self) -> &Pos {
834        &self.pos
835    }
836
837    /// Fetches the content or error associated with the most recent token, without allocating.
838    ///
839    /// This is an inherent implementation of [`lexical::Analyzer::try_content`] for convenience, so
840    /// it is available even when you don't have the trait imported.
841    ///
842    /// # Examples
843    ///
844    /// An `Ok` value is returned as long as the lexical analyzer isn't in an error state.
845    ///
846    /// ```
847    /// # use bufjson::lexical::{Token, fixed::FixedAnalyzer};
848    /// let mut lexer = FixedAnalyzer::new(&b"99.9e-1"[..]);
849    /// assert_eq!(Token::Num, lexer.next());
850    /// assert!(matches!(lexer.try_content(), Ok(c) if c.literal() == "99.9e-1"));
851    /// ```
852    ///
853    /// Once the lexical analyzer encounters a lexical error, it will return an `Err` value
854    /// describing that error.
855    ///
856    /// ```
857    /// use bufjson::{Pos, lexical::{Token, fixed::FixedAnalyzer}};
858    ///
859    /// let mut lexer = FixedAnalyzer::new(&b"[unquoted]"[..]);
860    /// assert_eq!(Token::ArrBegin, lexer.next());
861    /// assert_eq!(Token::Err, lexer.next());
862    /// assert_eq!(Pos { offset: 1, line: 1, col: 2}, *lexer.try_content().unwrap_err().pos());
863    /// ```
864    pub fn try_content(&self) -> Result<Content<B>, Error> {
865        match self.err {
866            None => {
867                let offset = self.pos.offset;
868
869                Ok(Content::from_buf(
870                    &self.buf,
871                    offset..offset + self.content.len,
872                    self.content.escaped,
873                ))
874            }
875            Some(err) => Err(err),
876        }
877    }
878
879    /// Converts a lexical analyzer into a syntax parser, consuming the lexical analyzer in the
880    /// process.
881    ///
882    /// You can convert the parser back into the underlying lexical analyzer using
883    /// [`Parser::into_inner`].
884    ///
885    /// # Examples
886    ///
887    /// ```
888    /// use bufjson::lexical::{Token, fixed::FixedAnalyzer};
889    ///
890    /// // Create a lexical analyzer and consume the first token.
891    /// let mut lexer = FixedAnalyzer::new(&b"true false"[..]);
892    /// assert_eq!(Token::LitTrue, lexer.next());
893    ///
894    /// // Convert the lexer into a parser. Since `true` is consumed, the next meaningful token is
895    /// // `false`.
896    /// let mut parser = lexer.into_parser();
897    /// assert_eq!(Token::LitFalse, parser.next_meaningful());
898    /// ```
899    ///
900    /// [`Parser::into_inner`]: syntax::Parser::into_inner
901    pub fn into_parser(self) -> syntax::Parser<FixedAnalyzer<B>> {
902        syntax::Parser::new(self)
903    }
904}
905
906impl<B: Deref<Target = [u8]> + fmt::Debug> Analyzer for FixedAnalyzer<B> {
907    type Content = Content<B>;
908    type Error = Error;
909
910    #[inline(always)]
911    fn next(&mut self) -> Token {
912        FixedAnalyzer::next(self)
913    }
914
915    #[inline(always)]
916    fn try_content(&self) -> Result<Self::Content, Error> {
917        FixedAnalyzer::try_content(self)
918    }
919
920    #[inline(always)]
921    fn pos(&self) -> &Pos {
922        FixedAnalyzer::pos(self)
923    }
924}
925
926#[cfg(test)]
927mod tests {
928    use super::*;
929    use crate::lexical::Expect;
930    use rstest::rstest;
931    use std::error::Error as _;
932
933    #[rstest]
934    #[case::invalid_char("a")]
935    #[case::f("f")]
936    #[case::fa("fa")]
937    #[case::fal("fal")]
938    #[case::fals("fals")]
939    #[case::false_leading_space(" false")]
940    #[case::false_trailing_space("false ")]
941    #[case::n("n")]
942    #[case::nu("nu")]
943    #[case::nul("nul")]
944    #[case::null_leading_space(" null")]
945    #[case::null_trailing_space("null ")]
946    #[case::t("t")]
947    #[case::tr("tr")]
948    #[case::tru("tru")]
949    #[case::true_leading_space(" true")]
950    #[case::true_trailing_space("true ")]
951    #[case::num_dot(".")]
952    #[case::num_zero_dot("0.")]
953    #[case::num_zero_zero("00")]
954    #[case::num_leading_space(" 0")]
955    #[case::num_trailing_space("0 ")]
956    #[case::str_unterminated_0(r#"""#)]
957    #[case::str_unterminated_1(r#""a"#)]
958    #[case::str_leading_space(r#" "a""#)]
959    #[case::str_trailing_space(r#""a" "#)]
960    #[should_panic(expected = "invalid JSON content")]
961    fn test_content_from_static_panic(#[case] s: &'static str) {
962        let c = Content::from_static(s);
963
964        panic!("content unexpectedly created: {c:?}");
965    }
966
967    #[rstest]
968    #[case::eof("", None)]
969    #[case::arr_begin("[", None)]
970    #[case::arr_end("]", None)]
971    #[case::obj_begin("{", None)]
972    #[case::obj_end("}", None)]
973    #[case::value_sep(",", None)]
974    #[case::name_sep(":", None)]
975    #[case::white_space(" ", None)]
976    #[case::white_tab("\t", None)]
977    #[case::white_lf("\n", None)]
978    #[case::white_cr("\r", None)]
979    #[case::white_lots("   \t\t   \r  \r\n  \t\n", None)]
980    #[case::lit_false("false", None)]
981    #[case::lit_null("null", None)]
982    #[case::lit_true("true", None)]
983    #[case::num_zero("0", None)]
984    #[case::num_zero_point_one("0.1", None)]
985    #[case::num_123("123", None)]
986    #[case::num_neg_zero("-0", None)]
987    #[case::num_neg_zero_point_one("-0.1", None)]
988    #[case::num_neg_123("-123", None)]
989    #[case::num_1e1("1e1", None)]
990    #[case::num_1e_plus_1("1e+1", None)]
991    #[case::num_1e_minus_1("1e-1", None)]
992    #[case::str_empty(r#""""#, None)]
993    #[case::str_a(r#""a""#, None)]
994    #[case::str_emoji(r#""🤠""#, None)]
995    #[case::str_escaped_nul(r#""\u0000""#, Some("\"\u{00}\""))]
996    fn test_content_from_static_ok(
997        #[case] s: &'static str,
998        #[case] unescaped: Option<&'static str>,
999    ) {
1000        let c = Content::from_static(s);
1001
1002        assert_eq!(s, c.literal());
1003        assert_eq!(s, c.to_string());
1004        assert_eq!(s.len(), c.literal_len());
1005        assert_eq!(s.len(), lexical::Content::literal_len(&c));
1006
1007        match unescaped {
1008            Some(u) => assert_eq!(u, c.unescaped()),
1009            None => assert!(!c.is_escaped()),
1010        };
1011    }
1012
1013    #[rstest]
1014    #[case::static_a(Content(InnerContent::Static("a")), "a", "a")]
1015    #[case::inline_empty(Content(inline_buf(b"").into()), "", "")]
1016    #[case::inline_a_1(Content(inline_buf(b"a").into()), "a", "a")]
1017    #[case::inline_a_inline_len(Content(inline_buf(&[b'a'; INLINE_LEN]).into()), "a".repeat(INLINE_LEN), "a".repeat(INLINE_LEN))]
1018    #[case::not_escaped_empty(Content(InnerContent::NotEscaped(Ref::new(Arc::new(b"".to_vec()), 0..0))), "", "")]
1019    #[case::not_escaped_a(Content(InnerContent::NotEscaped(Ref::new(Arc::new(b"a".to_vec()), 0..1))), "a", "a")]
1020    #[case::escaped_empty(Content(InnerContent::Escaped(Ref::new(Arc::new(b"".to_vec()), 0..0))), "", "")]
1021    #[case::escaped_a(Content(InnerContent::Escaped(Ref::new(Arc::new(b"a".to_vec()), 0..1))), "a", "a")]
1022    #[case::escaped_nl(Content(InnerContent::Escaped(Ref::new(Arc::new(b"\\n".to_vec()), 0..2))), "\\n", "\n")]
1023    #[case::escaped_nul(Content(InnerContent::Escaped(Ref::new(Arc::new(b"\\u0000".to_vec()), 0..6))), "\\u0000", "\u{0000}")]
1024    fn test_content(
1025        #[case] content: Content<Vec<u8>>,
1026        #[case] literal: impl AsRef<str>,
1027        #[case] unescaped: impl AsRef<str>,
1028    ) {
1029        let literal = literal.as_ref();
1030        let unescaped = unescaped.as_ref();
1031
1032        assert_eq!(literal, content.literal());
1033        assert_eq!(literal, content.to_string());
1034        assert_eq!(literal.len(), content.literal_len());
1035        assert_eq!(literal.len(), lexical::Content::literal_len(&content));
1036        assert_eq!(unescaped, content.unescaped());
1037        assert_eq!(unescaped, lexical::Content::unescaped(&content));
1038        assert_eq!(Ordering::Equal, content.unescaped_cmp(unescaped));
1039    }
1040
1041    #[rstest]
1042    #[case::arr_begin("[")]
1043    #[case::arr_end("]")]
1044    #[case::empty("")]
1045    #[case::lit_false("false")]
1046    #[case::lit_false("null")]
1047    #[case::lit_false("true")]
1048    #[case::name_sep(":")]
1049    #[case::num_0("1")]
1050    #[case::num_1("1")]
1051    #[case::num_pi("3.14159")]
1052    #[case::num_minus_1("-1")]
1053    #[case::num_big1("1234567890.1234567890")]
1054    #[case::num_big2("1e100")]
1055    #[case::num_big3("10.000e+99")]
1056    #[case::str_empty(r#""""#)]
1057    #[case::str_a(r#""a""#)]
1058    #[case::str_utf8_2_bytes(r#""è""#)]
1059    #[case::str_utf8_3_bytes(r#""€""#)]
1060    #[case::str_utf8_4_bytes(r#""🇮🇹""#)]
1061    #[case::str_utf8_all(r#""🇮🇹 Questo caffè costa 3€. ☕""#)]
1062    #[case::obj_begin("{")]
1063    #[case::obj_end("}")]
1064    #[case::value_sep(",")]
1065    #[case::white1(" ")]
1066    #[case::white2("\t")]
1067    #[case::white3("\r")]
1068    #[case::white4("\n")]
1069    #[case::white5("   \t\r\n \n\t\t\r \r\n\r")]
1070    fn test_content_unescaped_cmp_identity(#[case] input: &'static str) {
1071        let content = Content::from_static(input);
1072
1073        assert_eq!(
1074            Ordering::Equal,
1075            lexical::unescaped_cmp(content.literal(), input)
1076        );
1077        assert_eq!(Ordering::Equal, content.unescaped_cmp(input));
1078        assert_eq!(
1079            Ordering::Equal,
1080            lexical::Content::unescaped_cmp(&content, input)
1081        );
1082    }
1083
1084    #[rstest]
1085    #[case::empty_str_empty("", r#""""#, Ordering::Less)]
1086    #[case::empty_num("", "1", Ordering::Less)]
1087    #[case::empty_white("", " ", Ordering::Less)]
1088    #[case::num_empty("0", "", Ordering::Greater)]
1089    #[case::str_a_str_b(r#""a""#, r#""b""#, Ordering::Less)]
1090    #[case::str_a_str_empty(r#""a""#, r#""""#, Ordering::Greater)]
1091    #[case::str_b_str_a(r#""b""#, r#""a""#, Ordering::Greater)]
1092    #[case::str_bar_str_bard(r#""bar""#, r#""bard""#, Ordering::Less)]
1093    #[case::str_bar_str_bark(r#""bar""#, r#""bark""#, Ordering::Less)]
1094    #[case::str_bard_str_bar(r#""bard""#, r#""bar""#, Ordering::Greater)]
1095    #[case::str_bard_str_bark(r#""bard""#, r#""bark""#, Ordering::Less)]
1096    #[case::str_bark_str_bar(r#""bark""#, r#""bar""#, Ordering::Greater)]
1097    #[case::str_bark_str_bard(r#""bark""#, r#""bard""#, Ordering::Greater)]
1098    #[case::str_empty_empty(r#""""#, "", Ordering::Greater)]
1099    #[case::str_empty_str_a(r#""""#, r#""a""#, Ordering::Less)]
1100    #[case::str_esc_quot_str_quot(r#""\"""#, "\"\"\"", Ordering::Equal)]
1101    #[case::str_esc_bsol_str_bsol(r#""\\""#, "\"\\\"", Ordering::Equal)]
1102    #[case::str_esc_sol_str_sol(r#""\/""#, "\"/\"", Ordering::Equal)]
1103    #[case::str_esc_bs_str_bs(r#""\b""#, "\"\x08\"", Ordering::Equal)]
1104    #[case::str_esc_ff_str_ff(r#""\f""#, "\"\x0c\"", Ordering::Equal)]
1105    #[case::str_esc_nl_str_nl(r#""\n""#, "\"\n\"", Ordering::Equal)]
1106    #[case::str_esc_nl_str_cr(r#""\n""#, "\"\r\"", Ordering::Less)]
1107    #[case::str_esc_cr_str_cr(r#""\r""#, "\"\r\"", Ordering::Equal)]
1108    #[case::str_esc_cr_str_nl(r#""\r""#, "\"\n\"", Ordering::Greater)]
1109    #[case::str_esc_tab_str_tab(r#""\t""#, "\"\t\"", Ordering::Equal)]
1110    #[case::str_esc_u_0008_str_bs(r#""\u0008""#, "\"\x08\"", Ordering::Equal)]
1111    #[case::str_esc_u_0009_str_tab(r#""\u0009""#, "\"\t\"", Ordering::Equal)]
1112    #[case::str_esc_u_000a_str_nl(r#""\u000a""#, "\"\n\"", Ordering::Equal)]
1113    #[case::str_esc_u_000c_str_ff(r#""\u000c""#, "\"\x0c\"", Ordering::Equal)]
1114    #[case::str_esc_u_000d_str_cr(r#""\u000d""#, "\"\r\"", Ordering::Equal)]
1115    #[case::str_esc_u_0022_str_quot(r#""\u0022""#, "\"\"\"", Ordering::Equal)]
1116    #[case::str_esc_u_002f_str_sol(r#""\u002f""#, "\"/\"", Ordering::Equal)]
1117    #[case::str_esc_u_005c_str_bsol(r#""\u005c""#, "\"\\\"", Ordering::Equal)]
1118    #[case::str_esc_u_0062_str_a(r#""\u0063""#, r#""a""#, Ordering::Greater)]
1119    #[case::str_esc_u_00e8_str_e_grave(r#""\u00e8""#, "\"\u{00e8}\"", Ordering::Equal)]
1120    #[case::str_esc_u_20ac_str_euro(r#""\u20ac""#, "\"\u{20ac}\"", Ordering::Equal)]
1121    #[case::str_esc_u_surrogate_str_globe(r#""\ud83c\udf0d""#, "\"\u{1f30d}\"", Ordering::Equal)]
1122    #[case::str_esc_at_end_of_longer_str(r#""abcde\n""#, r#""abc""#, Ordering::Greater)]
1123    #[case::str_esc_consecutive(r#""\n\t""#, "\"\n\t\"", Ordering::Equal)]
1124    #[case::str_where_other_terminates_early(r#""\n""#, "\"", Ordering::Greater)]
1125    #[case::white_empty(" ", "", Ordering::Greater)]
1126    #[case::smoke_1(
1127        r#""Path: C:\\Users\\alice\/docs""#,
1128        "\"Path: C:\\Users\\alice/docs\"",
1129        Ordering::Equal
1130    )]
1131    #[case::smoke_2(
1132        r#""At the caff\u00e8 counter, he paid the 10,50\u00a0\u20ac and\nquickly downed the cappucino. Then,\r\n\twith a quick\"ciao\u0022, he turned and walked out.""#,
1133        "\"At the caffè counter, he paid the 10,50\u{00a0}€ and\nquickly downed the cappucino. Then,\r\n\twith a quick\"ciao\", he turned and walked out.\"",
1134        Ordering::Equal,
1135    )]
1136    #[case::smoke_3(
1137        r#""At the caff\u00e8 counter, he paid the 10,50\u00a0\u20ac and\nquickly downed the cappucino. Then,\r\n\twith a quick\"ciao\u0022, he turned and ran out.""#,
1138        "\"At the caffè counter, he paid the 10,50\u{00a0}€ and\nquickly downed the cappucino. Then,\r\n\twith a quick\"ciao\", he turned and walked out.\"",
1139        Ordering::Less,
1140    )]
1141    fn test_unescaped_cmp_ok(#[case] a: &'static str, #[case] b: &str, #[case] expect: Ordering) {
1142        let content = Content::from_static(a);
1143
1144        assert_eq!(expect, lexical::unescaped_cmp(content.literal(), b));
1145        assert_eq!(expect, content.unescaped_cmp(b));
1146        assert_eq!(expect, lexical::Content::unescaped_cmp(&content, b));
1147    }
1148
1149    #[cfg(feature = "num")]
1150    #[rstest]
1151    #[case::zero("0", 0)]
1152    #[case::minus_zero("-0", 0)]
1153    #[case::one("1", 1)]
1154    #[case::minus_one("-1", -1)]
1155    #[case::forty_two("42", 42)]
1156    #[case::minus_forty_two("-42", -42)]
1157    #[case::all_digits("9876543210", 9876543210)]
1158    #[case::max_minus_1(format!("{}", i64::MAX-1), i64::MAX-1)]
1159    #[case::max(format!("{}", i64::MAX), i64::MAX)]
1160    #[case::min_plus_1(format!("{}", i64::MIN+1), i64::MIN+1)]
1161    #[case::min(format!("{}", i64::MIN), i64::MIN)]
1162    fn test_content_parse_i64_ok(#[case] input: impl AsRef<str>, #[case] expect: i64) {
1163        let mut an = FixedAnalyzer::new(input.as_ref().as_bytes().to_vec());
1164        assert_eq!(Token::Num, an.next());
1165        let content = an.content();
1166        assert_eq!(Ok(expect), content.parse_i64());
1167        assert_eq!(Ok(expect), lexical::Content::parse_i64(&content));
1168    }
1169
1170    #[cfg(feature = "num")]
1171    #[rstest]
1172    #[case::decimal_zero("10.0", NumError::Format)]
1173    #[case::decimal("3.14159", NumError::Format)]
1174    #[case::exponent_zero("0e0", NumError::Format)]
1175    #[case::exponent_positive("10E+1", NumError::Format)]
1176    #[case::exponent_negative("1E-98", NumError::Format)]
1177    #[case::range_i64_min_minus_1(format!("{}", i64::MIN as i128 - 1), NumError::Range)]
1178    #[case::range_i128_min(format!("{}", i128::MIN), NumError::Range)]
1179    #[case::range_i64_max_plus_1(format!("{}", i64::MAX as i128 + 1), NumError::Range)]
1180    #[case::range_i128_max(format!("{}", i128::MAX), NumError::Range)]
1181    fn test_content_parse_i64_err(#[case] input: impl AsRef<str>, #[case] expect: NumError) {
1182        let mut an = FixedAnalyzer::new(input.as_ref().as_bytes().to_vec());
1183        assert_eq!(Token::Num, an.next());
1184        let content = an.content();
1185        assert_eq!(Err(expect), content.parse_i64());
1186        assert_eq!(Err(expect), lexical::Content::parse_i64(&content));
1187    }
1188
1189    #[cfg(feature = "num")]
1190    #[rstest]
1191    #[case::zero("0", 0)]
1192    #[case::one("1", 1)]
1193    #[case::forty_two("42", 42)]
1194    #[case::all_digits("9876543210", 9876543210)]
1195    #[case::max_minus_1(format!("{}", u64::MAX-1), u64::MAX-1)]
1196    #[case::max(format!("{}", u64::MAX), u64::MAX)]
1197    fn test_content_parse_u64_ok(#[case] input: impl AsRef<str>, #[case] expect: u64) {
1198        let mut an = FixedAnalyzer::new(input.as_ref().as_bytes().to_vec());
1199        assert_eq!(Token::Num, an.next());
1200        let content = an.content();
1201        assert_eq!(Ok(expect), content.parse_u64());
1202        assert_eq!(Ok(expect), lexical::Content::parse_u64(&content));
1203    }
1204
1205    #[cfg(feature = "num")]
1206    #[rstest]
1207    #[case::minus_zero("-0", NumError::Format)]
1208    #[case::minus_one("-1", NumError::Format)]
1209    #[case::minus_forty_two("-42", NumError::Format)]
1210    #[case::decimal_zero("10.0", NumError::Format)]
1211    #[case::decimal("3.14159", NumError::Format)]
1212    #[case::exponent_zero("0e0", NumError::Format)]
1213    #[case::exponent_positive("10E+1", NumError::Format)]
1214    #[case::exponent_negative("1E-98", NumError::Format)]
1215    #[case::range_u64_max_plus_1(format!("{}", u64::MAX as i128 + 1), NumError::Range)]
1216    #[case::range_i128_max(format!("{}", i128::MAX), NumError::Range)]
1217    fn test_content_parse_u64_err(#[case] input: impl AsRef<str>, #[case] expect: NumError) {
1218        let mut an = FixedAnalyzer::new(input.as_ref().as_bytes().to_vec());
1219        assert_eq!(Token::Num, an.next());
1220        let content = an.content();
1221        assert_eq!(Err(expect), content.parse_u64());
1222        assert_eq!(Err(expect), lexical::Content::parse_u64(&content));
1223    }
1224
1225    #[cfg(feature = "num_ext")]
1226    #[rstest]
1227    #[case::zero("0", 0)]
1228    #[case::minus_zero("-0", 0)]
1229    #[case::one("1", 1)]
1230    #[case::minus_one("-1", -1)]
1231    #[case::forty_two("42", 42)]
1232    #[case::minus_forty_two("-42", -42)]
1233    #[case::all_digits("9876543210", 9876543210)]
1234    #[case::i64_max(format!("{}", i64::MAX), i64::MAX as i128)]
1235    #[case::i64_min(format!("{}", i64::MIN), i64::MIN as i128)]
1236    #[case::beyond_i64_max(format!("{}", i64::MAX as i128 + 1), i64::MAX as i128 + 1)]
1237    #[case::beyond_i64_min(format!("{}", i64::MIN as i128 - 1), i64::MIN as i128 - 1)]
1238    #[case::pow10_38(format!("{}", 10_i128.pow(38)), 10_i128.pow(38))]
1239    #[case::neg_pow10_38(format!("{}", -10_i128.pow(38)), -10_i128.pow(38))]
1240    #[case::max_minus_1(format!("{}", i128::MAX - 1), i128::MAX - 1)]
1241    #[case::max(format!("{}", i128::MAX), i128::MAX)]
1242    #[case::min_plus_1(format!("{}", i128::MIN + 1), i128::MIN + 1)]
1243    #[case::min(format!("{}", i128::MIN), i128::MIN)]
1244    fn test_content_parse_i128_ok(#[case] input: impl AsRef<str>, #[case] expect: i128) {
1245        let mut an = FixedAnalyzer::new(input.as_ref().as_bytes().to_vec());
1246        assert_eq!(Token::Num, an.next());
1247        let content = an.content();
1248        assert_eq!(Ok(expect), content.parse_i128());
1249        assert_eq!(Ok(expect), lexical::Content::parse_i128(&content));
1250    }
1251
1252    #[cfg(feature = "num_ext")]
1253    #[rstest]
1254    #[case::decimal_zero("10.0", NumError::Format)]
1255    #[case::decimal("3.14159", NumError::Format)]
1256    #[case::exponent_zero("0e0", NumError::Format)]
1257    #[case::exponent_positive("10E+1", NumError::Format)]
1258    #[case::exponent_negative("1E-98", NumError::Format)]
1259    #[case::range_i128_max_plus_1(format!("{}", i128::MAX as u128 + 1), NumError::Range)]
1260    #[case::range_u128_max(format!("{}", u128::MAX), NumError::Range)]
1261    fn test_content_parse_i128_err(#[case] input: impl AsRef<str>, #[case] expect: NumError) {
1262        let mut an = FixedAnalyzer::new(input.as_ref().as_bytes().to_vec());
1263        assert_eq!(Token::Num, an.next());
1264        let content = an.content();
1265        assert_eq!(Err(expect), content.parse_i128());
1266        assert_eq!(Err(expect), lexical::Content::parse_i128(&content));
1267    }
1268
1269    #[cfg(feature = "num")]
1270    #[rstest]
1271    #[case::zero("0", 0.0)]
1272    #[case::minus_zero("-0", 0.0)]
1273    #[case::one("1", 1.0)]
1274    #[case::minus_one("-1", -1.0)]
1275    #[case::forty_two("42", 42.0)]
1276    #[case::pi("3.14159", 3.14159)]
1277    #[case::negative_decimal("-2.5", -2.5)]
1278    #[case::exponent_zero("0e0", 0.0)]
1279    #[case::exponent_positive("1e2", 100.0)]
1280    #[case::exponent_negative("1e-2", 0.01)]
1281    #[case::exponent_upper("1E2", 100.0)]
1282    #[case::exponent_plus_sign("1e+2", 100.0)]
1283    #[case::decimal_and_exponent("1.5e2", 150.0)]
1284    #[case::large_integer("9876543210", 9876543210.0)]
1285    #[case::f64_max(format!("{}", f64::MAX), f64::MAX)]
1286    #[case::f64_min_positive(format!("{}", f64::MIN_POSITIVE), f64::MIN_POSITIVE)]
1287    #[case::subnormal("5e-324", 5e-324)]
1288    fn test_content_parse_f64_ok(#[case] input: impl AsRef<str>, #[case] expect: f64) {
1289        let mut an = FixedAnalyzer::new(input.as_ref().as_bytes().to_vec());
1290        assert_eq!(Token::Num, an.next());
1291        let content = an.content();
1292        assert_eq!(Ok(expect), content.parse_f64());
1293        assert_eq!(Ok(expect), lexical::Content::parse_f64(&content));
1294    }
1295
1296    #[cfg(feature = "num")]
1297    #[rstest]
1298    #[case::range_positive_overflow("1e309", NumError::Range)]
1299    #[case::range_negative_overflow("-1e309", NumError::Range)]
1300    fn test_content_parse_f64_err(#[case] input: impl AsRef<str>, #[case] expect: NumError) {
1301        let mut an = FixedAnalyzer::new(input.as_ref().as_bytes().to_vec());
1302        assert_eq!(Token::Num, an.next());
1303        let content = an.content();
1304        assert_eq!(Err(expect), content.parse_f64());
1305        assert_eq!(Err(expect), lexical::Content::parse_f64(&content));
1306    }
1307
1308    #[rstest]
1309    #[case(
1310        ErrorKind::BadSurrogate { first: 0xd800, second: Some(0xd800), },
1311        "bad Unicode escape sequence surrogate pair: high surrogate '\\uD800' followed by invalid low surrogate '\\uD800' at line",
1312    )]
1313    #[case(
1314        ErrorKind::BadUtf8ContByte { seq_len: 3, offset: 2, value: 0x80 },
1315        "bad UTF-8 continuation byte 0x80 in 3-byte UTF-8 sequence (byte #2) at line",
1316    )]
1317    #[case(
1318        ErrorKind::UnexpectedByte { token: None, expect: Expect::TokenStartChar, actual: b'e' },
1319        "expected token start character but got character 'e' (ASCII 0x65) at line",
1320    )]
1321    #[case(
1322        ErrorKind::UnexpectedEof(Token::LitNull),
1323        "unexpected EOF in null token at line"
1324    )]
1325    fn test_error(#[case] kind: ErrorKind, #[case] expect: &str) {
1326        let pos = Pos::new(10, 2, 5);
1327        let err = Error { kind, pos };
1328
1329        assert_eq!(kind, err.kind());
1330        assert_eq!(kind, lexical::Error::kind(&err));
1331        assert_eq!(pos, *err.pos());
1332        assert_eq!(pos, *lexical::Error::pos(&err));
1333        assert!(err.source().is_none());
1334
1335        let actual = format!("{err}");
1336        assert!(
1337            actual.starts_with(expect),
1338            "expected {actual:?} to start with {expect:?}"
1339        );
1340    }
1341
1342    #[test]
1343    fn test_analyzer_initial_state_content() {
1344        let an = FixedAnalyzer::new(vec![]);
1345
1346        for _ in 0..5 {
1347            let content = an.content();
1348            assert_eq!("", content.literal());
1349            assert!(!content.is_escaped());
1350            assert_eq!("", content.unescaped());
1351
1352            let content = an.try_content().unwrap();
1353            assert_eq!("", content.literal());
1354            assert!(!content.is_escaped());
1355            assert_eq!("", content.unescaped());
1356        }
1357    }
1358
1359    #[test]
1360    #[should_panic(
1361        expected = "no error: last `next()` did not return `Token::Err` (use `content()` instead)"
1362    )]
1363    fn test_analyzer_initial_state_err() {
1364        let _ = FixedAnalyzer::new(vec![]).err();
1365    }
1366
1367    #[test]
1368    fn test_analyzer_clone_forks_state() {
1369        let mut analyzer = FixedAnalyzer::new(&b"[1,2]"[..]);
1370        assert_eq!(Token::ArrBegin, analyzer.next());
1371
1372        let mut fork = analyzer.clone();
1373
1374        assert_eq!(Token::Num, analyzer.next());
1375        assert_eq!("1", analyzer.content().literal());
1376        assert_eq!(Token::ValueSep, analyzer.next());
1377
1378        assert_eq!(Token::Num, fork.next());
1379        assert_eq!("1", fork.content().literal());
1380        assert_eq!(Token::ValueSep, fork.next());
1381
1382        assert_eq!(Token::Num, analyzer.next());
1383        assert_eq!("2", analyzer.content().literal());
1384        assert_eq!(Token::ArrEnd, analyzer.next());
1385        assert_eq!(Token::Eof, analyzer.next());
1386    }
1387
1388    #[rstest]
1389    #[case("", Token::Eof, None)]
1390    #[case("{", Token::ObjBegin, None)]
1391    #[case("}", Token::ObjEnd, None)]
1392    #[case("[", Token::ArrBegin, None)]
1393    #[case("]", Token::ArrEnd, None)]
1394    #[case(":", Token::NameSep, None)]
1395    #[case(",", Token::ValueSep, None)]
1396    #[case("false", Token::LitFalse, None)]
1397    #[case("null", Token::LitNull, None)]
1398    #[case("true", Token::LitTrue, None)]
1399    #[case("0", Token::Num, None)]
1400    #[case("-0", Token::Num, None)]
1401    #[case("1", Token::Num, None)]
1402    #[case("-1", Token::Num, None)]
1403    #[case("12", Token::Num, None)]
1404    #[case("-12", Token::Num, None)]
1405    #[case("0.0", Token::Num, None)]
1406    #[case("-0.0", Token::Num, None)]
1407    #[case("0.123456789", Token::Num, None)]
1408    #[case("-123.456789", Token::Num, None)]
1409    #[case("0E0", Token::Num, None)]
1410    #[case("0e0", Token::Num, None)]
1411    #[case("0E+0", Token::Num, None)]
1412    #[case("0e+0", Token::Num, None)]
1413    #[case("0E-0", Token::Num, None)]
1414    #[case("0e-0", Token::Num, None)]
1415    #[case("0.0E0", Token::Num, None)]
1416    #[case("0.0e0", Token::Num, None)]
1417    #[case("0.0E+0", Token::Num, None)]
1418    #[case("0.0e+0", Token::Num, None)]
1419    #[case("0.0E0", Token::Num, None)]
1420    #[case("0.0e0", Token::Num, None)]
1421    #[case("0E0", Token::Num, None)]
1422    #[case("0e0", Token::Num, None)]
1423    #[case("-0E+0", Token::Num, None)]
1424    #[case("-0e+0", Token::Num, None)]
1425    #[case("-0E-0", Token::Num, None)]
1426    #[case("-0e-0", Token::Num, None)]
1427    #[case("-0.0E0", Token::Num, None)]
1428    #[case("-0.0e0", Token::Num, None)]
1429    #[case("-0.0E+0", Token::Num, None)]
1430    #[case("-0.0e+0", Token::Num, None)]
1431    #[case("-0.0E0", Token::Num, None)]
1432    #[case("-0.0e0", Token::Num, None)]
1433    #[case("123E456", Token::Num, None)]
1434    #[case("123e456", Token::Num, None)]
1435    #[case("123.456E+7", Token::Num, None)]
1436    #[case("123.456e+7", Token::Num, None)]
1437    #[case("123.456E-89", Token::Num, None)]
1438    #[case("123.456e-89", Token::Num, None)]
1439    #[case("-123E456", Token::Num, None)]
1440    #[case("-123e456", Token::Num, None)]
1441    #[case("-123.456E+7", Token::Num, None)]
1442    #[case("-123.456e+7", Token::Num, None)]
1443    #[case("-123.456E-89", Token::Num, None)]
1444    #[case("-123.456e-89", Token::Num, None)]
1445    #[case(r#""""#, Token::Str, None)]
1446    #[case(r#"" ""#, Token::Str, None)]
1447    #[case(r#""foo""#, Token::Str, None)]
1448    #[case(r#""The quick brown fox jumped over the lazy dog!""#, Token::Str, None)]
1449    #[case(r#""\"""#, Token::Str, Some(r#"""""#))]
1450    #[case(r#""\\""#, Token::Str, Some(r#""\""#))]
1451    #[case(r#""\/""#, Token::Str, Some(r#""/""#))]
1452    #[case(r#""\t""#, Token::Str, Some("\"\t\""))]
1453    #[case(r#""\r""#, Token::Str, Some("\"\r\""))]
1454    #[case(r#""\n""#, Token::Str, Some("\"\n\""))]
1455    #[case(r#""\f""#, Token::Str, Some("\"\u{000c}\""))]
1456    #[case(r#""\b""#, Token::Str, Some("\"\u{0008}\""))]
1457    #[case(r#""\r\n""#, Token::Str, Some("\"\r\n\""))]
1458    #[case(r#""\u0000""#, Token::Str, Some("\"\u{0000}\""))]
1459    #[case(r#""\u001f""#, Token::Str, Some("\"\u{001f}\""))]
1460    #[case(r#""\u0020""#, Token::Str, Some(r#"" ""#))]
1461    #[case(r#""\u007E""#, Token::Str, Some(r#""~""#))]
1462    #[case(r#""\u007F""#, Token::Str, Some("\"\u{007f}\""))]
1463    #[case(r#""\u0080""#, Token::Str, Some("\"\u{0080}\""))]
1464    #[case(r#""\u0100""#, Token::Str, Some("\"\u{0100}\""))]
1465    #[case(r#""\ud7FF""#, Token::Str, Some("\"\u{d7ff}\""))]
1466    #[case(r#""\uE000""#, Token::Str, Some("\"\u{e000}\""))]
1467    #[case(r#""\ufDCf""#, Token::Str, Some("\"\u{fdcf}\""))]
1468    #[case(r#""\uFdeF""#, Token::Str, Some("\"\u{fdef}\""))]
1469    #[case(r#""\ufffd""#, Token::Str, Some("\"\u{fffd}\""))]
1470    #[case(r#""\uFFFE""#, Token::Str, Some("\"\u{fffe}\""))]
1471    #[case(r#""\uFFFF""#, Token::Str, Some("\"\u{ffff}\""))]
1472    #[case(r#""\ud800\udc00""#, Token::Str, Some("\"\u{10000}\""))] // Lowest valid surrogate pair → U+10000
1473    #[case(r#""\uD800\uDFFF""#, Token::Str, Some("\"\u{103ff}\""))] // High surrogate with highest low surrogate → U+103FF
1474    #[case(r#""\uDBFF\uDC00""#, Token::Str, Some("\"\u{10fc00}\""))] // Highest high surrogate with lowest low surrogate → U+10FC00
1475    #[case(r#""\udbFf\udfff""#, Token::Str, Some("\"\u{10ffff}\""))] // Highest valid surrogate pair → U+10FFFF (max Unicode scalar value)
1476    #[case(r#""\u0061b""#, Token::Str, Some(r#""ab""#))]
1477    #[case(r#""\uD800\uDC00a""#, Token::Str, Some("\"\u{10000}a\""))]
1478    #[case(r#""hello\nworld""#, Token::Str, Some("\"hello\nworld\""))]
1479    #[case(" ", Token::White, None)]
1480    #[case("\t", Token::White, None)]
1481    #[case("  ", Token::White, None)]
1482    #[case("\t\t", Token::White, None)]
1483    #[case(" \t \t    \t          \t\t", Token::White, None)]
1484    fn test_analyzer_single_token(
1485        #[case] input: &str,
1486        #[case] expect: Token,
1487        #[case] unescaped: Option<&str>,
1488    ) {
1489        // With content fetch.
1490        {
1491            let mut an = FixedAnalyzer::new(input.as_bytes());
1492            assert_eq!(Pos::default(), *an.pos());
1493
1494            assert_eq!(expect, an.next());
1495            assert_eq!(Pos::default(), *an.pos());
1496
1497            let content = an.content();
1498            assert_eq!(input, content.literal());
1499            assert_eq!(unescaped.is_some(), content.is_escaped());
1500            if let Some(u) = unescaped {
1501                assert_eq!(u, content.unescaped());
1502            } else {
1503                assert_eq!(input, content.unescaped());
1504            }
1505
1506            assert_eq!(Token::Eof, an.next());
1507            assert_eq!(
1508                Pos {
1509                    offset: input.len(),
1510                    line: 1,
1511                    col: input.len() + 1
1512                },
1513                *an.pos()
1514            );
1515
1516            assert_eq!(Token::Eof, an.next());
1517            assert_eq!(
1518                Pos {
1519                    offset: input.len(),
1520                    line: 1,
1521                    col: input.len() + 1
1522                },
1523                *an.pos()
1524            );
1525        }
1526
1527        // Without content fetch.
1528        {
1529            let mut an = FixedAnalyzer::new(input.as_bytes());
1530            assert_eq!(Pos::default(), *an.pos());
1531
1532            assert_eq!(expect, an.next());
1533            assert_eq!(Pos::default(), *an.pos());
1534
1535            assert_eq!(Token::Eof, an.next());
1536            assert_eq!(
1537                Pos {
1538                    offset: input.len(),
1539                    line: 1,
1540                    col: input.len() + 1
1541                },
1542                *an.pos()
1543            );
1544
1545            assert_eq!(Token::Eof, an.next());
1546            assert_eq!(
1547                Pos {
1548                    offset: input.len(),
1549                    line: 1,
1550                    col: input.len() + 1
1551                },
1552                *an.pos()
1553            );
1554        }
1555    }
1556
1557    #[rstest]
1558    #[case("1".repeat(INLINE_LEN-1), Token::Num, None)]
1559    #[case("2".repeat(INLINE_LEN), Token::Num, None)]
1560    #[case("3".repeat(INLINE_LEN+1), Token::Num, None)]
1561    #[case(format!(r#""{}""#, "a".repeat(INLINE_LEN-3)), Token::Str, None)]
1562    #[case(format!(r#""{}""#, "b".repeat(INLINE_LEN-2)), Token::Str, None)]
1563    #[case(format!(r#""{}""#, "c".repeat(INLINE_LEN-1)), Token::Str, None)]
1564    #[case(format!(r#""{}""#, r#"\/"#.repeat(INLINE_LEN/2)), Token::Str, Some(format!(r#""{}""#, "/".repeat(INLINE_LEN/2))))]
1565    #[case(" ".repeat(INLINE_LEN-1), Token::White, None)]
1566    #[case("\t".repeat(INLINE_LEN), Token::White, None)]
1567    #[case(" ".repeat(INLINE_LEN+1), Token::White, None)]
1568    #[case(" \t".repeat(INLINE_LEN/2+1), Token::White, None)]
1569    fn test_analyzer_single_token_inline_len_boundary(
1570        #[case] input: String,
1571        #[case] expect: Token,
1572        #[case] unescaped: Option<String>,
1573    ) {
1574        let mut an = FixedAnalyzer::new(input.as_bytes());
1575        assert_eq!(Pos::default(), *an.pos());
1576
1577        assert_eq!(expect, an.next());
1578        assert_eq!(Pos::default(), *an.pos());
1579
1580        let content = an.content();
1581        assert_eq!(input, content.literal());
1582        assert_eq!(unescaped.is_some(), content.is_escaped());
1583        if let Some(u) = unescaped {
1584            assert_eq!(u, content.unescaped());
1585        } else {
1586            assert_eq!(input, content.unescaped());
1587        }
1588
1589        assert_eq!(Token::Eof, an.next());
1590        assert_eq!(
1591            Pos {
1592                offset: input.len(),
1593                line: 1,
1594                col: input.len() + 1
1595            },
1596            *an.pos()
1597        );
1598
1599        assert_eq!(Token::Eof, an.next());
1600        assert_eq!(
1601            Pos {
1602                offset: input.len(),
1603                line: 1,
1604                col: input.len() + 1
1605            },
1606            *an.pos()
1607        );
1608    }
1609
1610    #[rstest]
1611    #[case(r#"["#)]
1612    #[case(r#"]"#)]
1613    #[case(r#"false"#)]
1614    #[case(r#":"#)]
1615    #[case(r#"null"#)]
1616    #[case(r#"3.14159e+0"#)]
1617    #[case(r#"{"#)]
1618    #[case(r#"}"#)]
1619    #[case(r#""foo\/\u1234\/bar""#)]
1620    #[case(r#"true"#)]
1621    #[case(r#","#)]
1622    #[case("\n\n\n   ")]
1623    #[should_panic(
1624        expected = "no error: last `next()` did not return `Token::Err` (use `content()` instead)"
1625    )]
1626    fn test_analyzer_single_token_panic_no_err(#[case] input: &str) {
1627        let mut an = FixedAnalyzer::new(input.as_bytes());
1628
1629        let token = an.next();
1630        assert!(!token.is_terminal(), "input = {input:?}, token = {token:?}");
1631
1632        let _ = an.err();
1633    }
1634
1635    #[rstest]
1636    #[case("\"\u{0020}\"")]
1637    #[case("\"\u{007f}\"")] // DEL, the highest 1-byte UTF-8 character
1638    #[case("\"\u{0080}\"")] // Lowest two-byte UTF-8 character
1639    #[case("\"\u{07ff}\"")] // Highest two-byte UTF-8 character
1640    #[case("\"\u{0800}\"")] // Lowest three-byte UTF-8 character
1641    #[case("\"\u{d7ff}\"")] // Highest BMP code point before surrogates
1642    #[case("\"\u{e000}\"")] // Lowest BMP code point after surrogates
1643    #[case("\"\u{ffff}\"")] // Highest BMP code point: non-character but still valid JSON
1644    #[case("\"\u{10000}\"")] // Lowest four-byte UTF-8 character
1645    #[case("\"\u{10ffff}\"")] // Highest valid Unicode scalar value
1646    #[case("\"\u{3f086}\"")] // Regression test: 2026-02-14 🌹
1647    fn test_analyzer_utf8_char_1(#[case] input: &str) {
1648        // With content fetch.
1649        {
1650            let mut an = FixedAnalyzer::new(input.as_bytes());
1651            assert_eq!(Pos::default(), *an.pos());
1652
1653            assert_eq!(Token::Str, an.next());
1654            assert_eq!(Pos::default(), *an.pos());
1655
1656            let content = an.content();
1657            assert_eq!(input, content.literal());
1658            assert!(!content.is_escaped());
1659            assert_eq!(input, content.unescaped());
1660
1661            assert_eq!(Token::Eof, an.next());
1662            assert_eq!(
1663                Pos {
1664                    offset: input.len(),
1665                    line: 1,
1666                    col: 4,
1667                },
1668                *an.pos()
1669            );
1670
1671            assert_eq!(Token::Eof, an.next());
1672            assert_eq!(
1673                Pos {
1674                    offset: input.len(),
1675                    line: 1,
1676                    col: 4,
1677                },
1678                *an.pos()
1679            );
1680        }
1681
1682        // Without content fetch.
1683        {
1684            let mut an = FixedAnalyzer::new(input.as_bytes());
1685            assert_eq!(Pos::default(), *an.pos());
1686
1687            assert_eq!(Token::Str, an.next());
1688            assert_eq!(Pos::default(), *an.pos());
1689
1690            assert_eq!(Token::Eof, an.next());
1691            assert_eq!(
1692                Pos {
1693                    offset: input.len(),
1694                    line: 1,
1695                    col: 4,
1696                },
1697                *an.pos()
1698            );
1699
1700            assert_eq!(Token::Eof, an.next());
1701            assert_eq!(
1702                Pos {
1703                    offset: input.len(),
1704                    line: 1,
1705                    col: 4,
1706                },
1707                *an.pos()
1708            );
1709        }
1710    }
1711
1712    #[rstest]
1713    // 2-byte followed by 1, 2, 3, 4-byte
1714    #[case::two_1("\"\u{00e4}a\"")]
1715    #[case::two_2("\"\u{00e4}\u{00e4}\"")]
1716    #[case::two_3("\"\u{00e4}\u{3042}\"")]
1717    #[case::two_4("\"\u{00e4}\u{10000}\"")]
1718    // 3-byte followed by 1, 2, 3, 4-byte
1719    #[case::three_1("\"\u{3042}a\"")]
1720    #[case::three_2("\"\u{3042}\u{00e4}\"")]
1721    #[case::three_3("\"\u{3042}\u{3042}\"")]
1722    #[case::three_4("\"\u{3042}\u{10000}\"")]
1723    // 4-byte followed by 1, 2, 3, 4-byte
1724    #[case::four_1("\"\u{10000}a\"")]
1725    #[case::four_2("\"\u{10000}\u{00e4}\"")]
1726    #[case::four_3("\"\u{10000}\u{3042}\"")]
1727    #[case::four_4("\"\u{10000}\u{10000}\"")]
1728    fn test_analyzer_utf8_char_2(#[case] input: &str) {
1729        // With content fetch.
1730        {
1731            let mut an = FixedAnalyzer::new(input.as_bytes());
1732            assert_eq!(Pos::default(), *an.pos());
1733
1734            assert_eq!(Token::Str, an.next());
1735            assert_eq!(Pos::default(), *an.pos());
1736
1737            let content = an.content();
1738            assert_eq!(input, content.literal());
1739            assert!(!content.is_escaped());
1740            assert_eq!(input, content.unescaped());
1741
1742            assert_eq!(Token::Eof, an.next());
1743            assert_eq!(
1744                Pos {
1745                    offset: input.len(),
1746                    line: 1,
1747                    col: 5,
1748                },
1749                *an.pos()
1750            );
1751
1752            assert_eq!(Token::Eof, an.next());
1753            assert_eq!(
1754                Pos {
1755                    offset: input.len(),
1756                    line: 1,
1757                    col: 5,
1758                },
1759                *an.pos()
1760            );
1761        }
1762
1763        // Without content fetch.
1764        {
1765            let mut an = FixedAnalyzer::new(input.as_bytes());
1766            assert_eq!(Pos::default(), *an.pos());
1767
1768            assert_eq!(Token::Str, an.next());
1769            assert_eq!(Pos::default(), *an.pos());
1770
1771            assert_eq!(Token::Eof, an.next());
1772            assert_eq!(
1773                Pos {
1774                    offset: input.len(),
1775                    line: 1,
1776                    col: 5,
1777                },
1778                *an.pos()
1779            );
1780
1781            assert_eq!(Token::Eof, an.next());
1782            assert_eq!(
1783                Pos {
1784                    offset: input.len(),
1785                    line: 1,
1786                    col: 5,
1787                },
1788                *an.pos()
1789            );
1790        }
1791    }
1792
1793    #[rstest]
1794    #[case("\n", 2, 1)]
1795    #[case("\n\n", 3, 1)]
1796    #[case("\r", 2, 1)]
1797    #[case("\r\r", 3, 1)]
1798    #[case("\r\n", 2, 1)]
1799    #[case("\n\r", 3, 1)]
1800    #[case("\n\n\r\r", 5, 1)]
1801    #[case("\r\n\r", 3, 1)]
1802    #[case("\n\r\n", 3, 1)]
1803    #[case(" \n", 2, 1)]
1804    #[case("\n ", 2, 2)]
1805    #[case(" \r", 2, 1)]
1806    #[case("\r ", 2, 2)]
1807    #[case("\t\n", 2, 1)]
1808    #[case("\n ", 2, 2)]
1809    #[case("\t\r", 2, 1)]
1810    #[case("\r\t", 2, 2)]
1811    fn test_analyzer_whitespace_multiline(
1812        #[case] input: &str,
1813        #[case] line: usize,
1814        #[case] col: usize,
1815    ) {
1816        // With content fetch.
1817        {
1818            let mut an = FixedAnalyzer::new(input.as_bytes());
1819            assert_eq!(Pos::default(), *an.pos());
1820
1821            assert_eq!(Token::White, an.next());
1822            assert_eq!(Pos::default(), *an.pos());
1823
1824            let content = an.content();
1825            assert_eq!(input, content.literal());
1826            assert!(!content.is_escaped());
1827            assert_eq!(input, content.unescaped());
1828
1829            assert_eq!(Token::Eof, an.next());
1830            assert_eq!(
1831                Pos {
1832                    offset: input.len(),
1833                    line,
1834                    col
1835                },
1836                *an.pos()
1837            );
1838        }
1839
1840        // Without content fetch.
1841        {
1842            let mut an = FixedAnalyzer::new(input.as_bytes());
1843            assert_eq!(Pos::default(), *an.pos());
1844
1845            assert_eq!(Token::White, an.next());
1846            assert_eq!(Pos::default(), *an.pos());
1847
1848            assert_eq!(Token::Eof, an.next());
1849            assert_eq!(
1850                Pos {
1851                    offset: input.len(),
1852                    line,
1853                    col
1854                },
1855                *an.pos()
1856            );
1857        }
1858    }
1859
1860    #[rstest]
1861    #[case("", T::t(Token::Eof, ""), T::t(Token::Eof, ""), 1, 1)]
1862    // =============================================================================================
1863    // Object start character `{` followed by something...
1864    // =============================================================================================
1865    #[case("{{", T::t(Token::ObjBegin, "{"), T::t(Token::ObjBegin, "{").pos(1, 1, 2), 1, 3)]
1866    #[case("{}", T::t(Token::ObjBegin, "{"), T::t(Token::ObjEnd, "}").pos(1, 1, 2), 1, 3)]
1867    #[case("{[", T::t(Token::ObjBegin, "{"), T::t(Token::ArrBegin, "[").pos(1, 1, 2), 1, 3)]
1868    #[case("{]", T::t(Token::ObjBegin, "{"), T::t(Token::ArrEnd, "]").pos(1, 1, 2), 1, 3)]
1869    #[case("{:", T::t(Token::ObjBegin, "{"), T::t(Token::NameSep, ":").pos(1, 1, 2), 1, 3)]
1870    #[case("{,", T::t(Token::ObjBegin, "{"), T::t(Token::ValueSep, ",").pos(1, 1, 2), 1, 3)]
1871    #[case("{false", T::t(Token::ObjBegin, "{"), T::t(Token::LitFalse, "false").pos(1, 1, 2), 1, 7)]
1872    #[case("{null", T::t(Token::ObjBegin, "{"), T::t(Token::LitNull, "null").pos(1, 1, 2), 1, 6)]
1873    #[case("{true", T::t(Token::ObjBegin, "{"), T::t(Token::LitTrue, "true").pos(1, 1, 2), 1, 6)]
1874    #[case("{0", T::t(Token::ObjBegin, "{"), T::t(Token::Num, "0").pos(1, 1, 2), 1, 3)]
1875    #[case("{-1.9", T::t(Token::ObjBegin, "{"), T::t(Token::Num, "-1.9").pos(1, 1, 2), 1, 6)]
1876    #[case("{3.14e+0", T::t(Token::ObjBegin, "{"), T::t(Token::Num, "3.14e+0").pos(1, 1, 2), 1, 9)]
1877    #[case(r#"{"""#, T::t(Token::ObjBegin, "{"), T::t(Token::Str, r#""""#).pos(1, 1, 2), 1, 4)]
1878    #[case(r#"{"foo""#, T::t(Token::ObjBegin, "{"), T::t(Token::Str, r#""foo""#).pos(1, 1, 2), 1, 7)]
1879    #[case(r#"{"hello\u0020there,\nworld!""#, T::t(Token::ObjBegin, "{"), T::t(Token::Str, r#""hello\u0020there,\nworld!""#).pos(1, 1, 2).unescaped("\"hello there,\nworld!\""), 1,29)]
1880    #[case("{ ", T::t(Token::ObjBegin, "{"), T::t(Token::White, " ").pos(1, 1, 2), 1, 3)]
1881    #[case("{\t\t\r\n\n ", T::t(Token::ObjBegin, "{"), T::t(Token::White, "\t\t\r\n\n ").pos(1, 1, 2), 3, 2)]
1882    // =============================================================================================
1883    // Object end character `}` followed by something...
1884    // =============================================================================================
1885    #[case("}{", T::t(Token::ObjEnd, "}"), T::t(Token::ObjBegin, "{").pos(1, 1, 2), 1, 3)]
1886    #[case("}}", T::t(Token::ObjEnd, "}"), T::t(Token::ObjEnd, "}").pos(1, 1, 2), 1, 3)]
1887    #[case("}[", T::t(Token::ObjEnd, "}"), T::t(Token::ArrBegin, "[").pos(1, 1, 2), 1, 3)]
1888    #[case("}]", T::t(Token::ObjEnd, "}"), T::t(Token::ArrEnd, "]").pos(1, 1, 2), 1, 3)]
1889    #[case("}:", T::t(Token::ObjEnd, "}"), T::t(Token::NameSep, ":").pos(1, 1, 2), 1, 3)]
1890    #[case("},", T::t(Token::ObjEnd, "}"), T::t(Token::ValueSep, ",").pos(1, 1, 2), 1, 3)]
1891    #[case("}false", T::t(Token::ObjEnd, "}"), T::t(Token::LitFalse, "false").pos(1, 1, 2), 1, 7)]
1892    #[case("}null", T::t(Token::ObjEnd, "}"), T::t(Token::LitNull, "null").pos(1, 1, 2), 1, 6)]
1893    #[case("}true", T::t(Token::ObjEnd, "}"), T::t(Token::LitTrue, "true").pos(1, 1, 2), 1, 6)]
1894    #[case("}0", T::t(Token::ObjEnd, "}"), T::t(Token::Num, "0").pos(1, 1, 2), 1, 3)]
1895    #[case("}-1.9", T::t(Token::ObjEnd, "}"), T::t(Token::Num, "-1.9").pos(1, 1, 2), 1, 6)]
1896    #[case("}3.14e+0", T::t(Token::ObjEnd, "}"), T::t(Token::Num, "3.14e+0").pos(1, 1, 2), 1, 9)]
1897    #[case(r#"}"""#, T::t(Token::ObjEnd, "}"), T::t(Token::Str, r#""""#).pos(1, 1, 2), 1, 4)]
1898    #[case(r#"}"foo""#, T::t(Token::ObjEnd, "}"), T::t(Token::Str, r#""foo""#).pos(1, 1, 2), 1, 7)]
1899    #[case(r#"}"hello\u0020there,\nworld!""#, T::t(Token::ObjEnd, "}"), T::t(Token::Str, r#""hello\u0020there,\nworld!""#).pos(1, 1, 2).unescaped("\"hello there,\nworld!\""), 1,29)]
1900    #[case("} ", T::t(Token::ObjEnd, "}"), T::t(Token::White, " ").pos(1, 1, 2), 1, 3)]
1901    #[case("}\t\t\r\n\n ", T::t(Token::ObjEnd, "}"), T::t(Token::White, "\t\t\r\n\n ").pos(1, 1, 2), 3, 2)]
1902    // =============================================================================================
1903    // Array start character `[` followed by something...
1904    // =============================================================================================
1905    #[case("[{", T::t(Token::ArrBegin, "["), T::t(Token::ObjBegin, "{").pos(1, 1, 2), 1, 3)]
1906    #[case("[}", T::t(Token::ArrBegin, "["), T::t(Token::ObjEnd, "}").pos(1, 1, 2), 1, 3)]
1907    #[case("[[", T::t(Token::ArrBegin, "["), T::t(Token::ArrBegin, "[").pos(1, 1, 2), 1, 3)]
1908    #[case("[]", T::t(Token::ArrBegin, "["), T::t(Token::ArrEnd, "]").pos(1, 1, 2), 1, 3)]
1909    #[case("[:", T::t(Token::ArrBegin, "["), T::t(Token::NameSep, ":").pos(1, 1, 2), 1, 3)]
1910    #[case("[,", T::t(Token::ArrBegin, "["), T::t(Token::ValueSep, ",").pos(1, 1, 2), 1, 3)]
1911    #[case("[false", T::t(Token::ArrBegin, "["), T::t(Token::LitFalse, "false").pos(1, 1, 2), 1, 7)]
1912    #[case("[null", T::t(Token::ArrBegin, "["), T::t(Token::LitNull, "null").pos(1, 1, 2), 1, 6)]
1913    #[case("[true", T::t(Token::ArrBegin, "["), T::t(Token::LitTrue, "true").pos(1, 1, 2), 1, 6)]
1914    #[case("[0", T::t(Token::ArrBegin, "["), T::t(Token::Num, "0").pos(1, 1, 2), 1, 3)]
1915    #[case("[-1.9", T::t(Token::ArrBegin, "["), T::t(Token::Num, "-1.9").pos(1, 1, 2), 1, 6)]
1916    #[case("[3.14e+0", T::t(Token::ArrBegin, "["), T::t(Token::Num, "3.14e+0").pos(1, 1, 2), 1, 9)]
1917    #[case(r#"["""#, T::t(Token::ArrBegin, "["), T::t(Token::Str, r#""""#).pos(1, 1, 2), 1, 4)]
1918    #[case(r#"["foo""#, T::t(Token::ArrBegin, "["), T::t(Token::Str, r#""foo""#).pos(1, 1, 2), 1, 7)]
1919    #[case(r#"["hello\u0020there,\nworld!""#, T::t(Token::ArrBegin, "["), T::t(Token::Str, r#""hello\u0020there,\nworld!""#).pos(1, 1, 2).unescaped("\"hello there,\nworld!\""), 1,29)]
1920    #[case("[ ", T::t(Token::ArrBegin, "["), T::t(Token::White, " ").pos(1, 1, 2), 1, 3)]
1921    #[case("[\t\t\r\n\n ", T::t(Token::ArrBegin, "["), T::t(Token::White, "\t\t\r\n\n ").pos(1, 1, 2), 3, 2)]
1922    // =============================================================================================
1923    // Array end character `]` followed by something...
1924    // =============================================================================================
1925    #[case("]{", T::t(Token::ArrEnd, "]"), T::t(Token::ObjBegin, "{").pos(1, 1, 2), 1, 3)]
1926    #[case("]}", T::t(Token::ArrEnd, "]"), T::t(Token::ObjEnd, "}").pos(1, 1, 2), 1, 3)]
1927    #[case("][", T::t(Token::ArrEnd, "]"), T::t(Token::ArrBegin, "[").pos(1, 1, 2), 1, 3)]
1928    #[case("]]", T::t(Token::ArrEnd, "]"), T::t(Token::ArrEnd, "]").pos(1, 1, 2), 1, 3)]
1929    #[case("]:", T::t(Token::ArrEnd, "]"), T::t(Token::NameSep, ":").pos(1, 1, 2), 1, 3)]
1930    #[case("],", T::t(Token::ArrEnd, "]"), T::t(Token::ValueSep, ",").pos(1, 1, 2), 1, 3)]
1931    #[case("]false", T::t(Token::ArrEnd, "]"), T::t(Token::LitFalse, "false").pos(1, 1, 2), 1, 7)]
1932    #[case("]null", T::t(Token::ArrEnd, "]"), T::t(Token::LitNull, "null").pos(1, 1, 2), 1, 6)]
1933    #[case("]true", T::t(Token::ArrEnd, "]"), T::t(Token::LitTrue, "true").pos(1, 1, 2), 1, 6)]
1934    #[case("]0", T::t(Token::ArrEnd, "]"), T::t(Token::Num, "0").pos(1, 1, 2), 1, 3)]
1935    #[case("]-1.9", T::t(Token::ArrEnd, "]"), T::t(Token::Num, "-1.9").pos(1, 1, 2), 1, 6)]
1936    #[case("]31.4e-1", T::t(Token::ArrEnd, "]"), T::t(Token::Num, "31.4e-1").pos(1, 1, 2), 1, 9)]
1937    #[case(r#"]"""#, T::t(Token::ArrEnd, "]"), T::t(Token::Str, r#""""#).pos(1, 1, 2), 1, 4)]
1938    #[case(r#"]"foo""#, T::t(Token::ArrEnd, "]"), T::t(Token::Str, r#""foo""#).pos(1, 1, 2), 1, 7)]
1939    #[case(r#"]"hello\u0020there,\nworld!""#, T::t(Token::ArrEnd, "]"), T::t(Token::Str, r#""hello\u0020there,\nworld!""#).pos(1, 1, 2).unescaped("\"hello there,\nworld!\""), 1,29)]
1940    #[case("] ", T::t(Token::ArrEnd, "]"), T::t(Token::White, " ").pos(1, 1, 2), 1, 3)]
1941    #[case("]\t\t\r\n\n ", T::t(Token::ArrEnd, "]"), T::t(Token::White, "\t\t\r\n\n ").pos(1, 1, 2), 3, 2)]
1942    // =============================================================================================
1943    // Name separator `:` followed by something...
1944    // =============================================================================================
1945    #[case(":{", T::t(Token::NameSep, ":"), T::t(Token::ObjBegin, "{").pos(1, 1, 2), 1, 3)]
1946    #[case(":}", T::t(Token::NameSep, ":"), T::t(Token::ObjEnd, "}").pos(1, 1, 2), 1, 3)]
1947    #[case(":[", T::t(Token::NameSep, ":"), T::t(Token::ArrBegin, "[").pos(1, 1, 2), 1, 3)]
1948    #[case(":]", T::t(Token::NameSep, ":"), T::t(Token::ArrEnd, "]").pos(1, 1, 2), 1, 3)]
1949    #[case("::", T::t(Token::NameSep, ":"), T::t(Token::NameSep, ":").pos(1, 1, 2), 1, 3)]
1950    #[case(":,", T::t(Token::NameSep, ":"), T::t(Token::ValueSep, ",").pos(1, 1, 2), 1, 3)]
1951    #[case(":false", T::t(Token::NameSep, ":"), T::t(Token::LitFalse, "false").pos(1, 1, 2), 1, 7)]
1952    #[case(":null", T::t(Token::NameSep, ":"), T::t(Token::LitNull, "null").pos(1, 1, 2), 1, 6)]
1953    #[case(":true", T::t(Token::NameSep, ":"), T::t(Token::LitTrue, "true").pos(1, 1, 2), 1, 6)]
1954    #[case(":0", T::t(Token::NameSep, ":"), T::t(Token::Num, "0").pos(1, 1, 2), 1, 3)]
1955    #[case(":-1.9", T::t(Token::NameSep, ":"), T::t(Token::Num, "-1.9").pos(1, 1, 2), 1, 6)]
1956    #[case(":31.4e-1", T::t(Token::NameSep, ":"), T::t(Token::Num, "31.4e-1").pos(1, 1, 2), 1, 9)]
1957    #[case(r#":"""#, T::t(Token::NameSep, ":"), T::t(Token::Str, r#""""#).pos(1, 1, 2), 1, 4)]
1958    #[case(r#":"foo""#, T::t(Token::NameSep, ":"), T::t(Token::Str, r#""foo""#).pos(1, 1, 2), 1, 7)]
1959    #[case(r#":"hello\u0020there,\nworld!""#, T::t(Token::NameSep, ":"), T::t(Token::Str, r#""hello\u0020there,\nworld!""#).pos(1, 1, 2).unescaped("\"hello there,\nworld!\""), 1,29)]
1960    #[case(": ", T::t(Token::NameSep, ":"), T::t(Token::White, " ").pos(1, 1, 2), 1, 3)]
1961    #[case(":\t\t\r\n\n ", T::t(Token::NameSep, ":"), T::t(Token::White, "\t\t\r\n\n ").pos(1, 1, 2), 3, 2)]
1962    // =============================================================================================
1963    // Value separator `,` followed by something...
1964    // =============================================================================================
1965    #[case(",{", T::t(Token::ValueSep, ","), T::t(Token::ObjBegin, "{").pos(1, 1, 2), 1, 3)]
1966    #[case(",}", T::t(Token::ValueSep, ","), T::t(Token::ObjEnd, "}").pos(1, 1, 2), 1, 3)]
1967    #[case(",[", T::t(Token::ValueSep, ","), T::t(Token::ArrBegin, "[").pos(1, 1, 2), 1, 3)]
1968    #[case(",]", T::t(Token::ValueSep, ","), T::t(Token::ArrEnd, "]").pos(1, 1, 2), 1, 3)]
1969    #[case(",:", T::t(Token::ValueSep, ","), T::t(Token::NameSep, ":").pos(1, 1, 2), 1, 3)]
1970    #[case(",,", T::t(Token::ValueSep, ","), T::t(Token::ValueSep, ",").pos(1, 1, 2), 1, 3)]
1971    #[case(",false", T::t(Token::ValueSep, ","), T::t(Token::LitFalse, "false").pos(1, 1, 2), 1, 7)]
1972    #[case(",null", T::t(Token::ValueSep, ","), T::t(Token::LitNull, "null").pos(1, 1, 2), 1, 6)]
1973    #[case(",true", T::t(Token::ValueSep, ","), T::t(Token::LitTrue, "true").pos(1, 1, 2), 1, 6)]
1974    #[case(",-0.0", T::t(Token::ValueSep, ","), T::t(Token::Num, "-0.0").pos(1, 1, 2), 1, 6)]
1975    #[case(",1.9", T::t(Token::ValueSep, ","), T::t(Token::Num, "1.9").pos(1, 1, 2), 1, 5)]
1976    #[case(",314e-2", T::t(Token::ValueSep, ","), T::t(Token::Num, "314e-2").pos(1, 1, 2), 1, 8)]
1977    #[case(r#","""#, T::t(Token::ValueSep, ","), T::t(Token::Str, r#""""#).pos(1, 1, 2), 1, 4)]
1978    #[case(r#","foo""#, T::t(Token::ValueSep, ","), T::t(Token::Str, r#""foo""#).pos(1, 1, 2), 1, 7)]
1979    #[case(r#","hello\u0020there,\nworld!""#, T::t(Token::ValueSep, ","), T::t(Token::Str, r#""hello\u0020there,\nworld!""#).pos(1, 1, 2).unescaped("\"hello there,\nworld!\""), 1,29)]
1980    #[case(", ", T::t(Token::ValueSep, ","), T::t(Token::White, " ").pos(1, 1, 2), 1, 3)]
1981    #[case(",\t\t\r\n\n ", T::t(Token::ValueSep, ","), T::t(Token::White, "\t\t\r\n\n ").pos(1, 1, 2), 3, 2)]
1982    // =============================================================================================
1983    // Literal `false` followed by something...
1984    // =============================================================================================
1985    #[case("false{", T::t(Token::LitFalse, "false"), T::t(Token::ObjBegin, "{").pos(5, 1, 6), 1, 7)]
1986    #[case("false}", T::t(Token::LitFalse, "false"), T::t(Token::ObjEnd, "}").pos(5, 1, 6), 1, 7)]
1987    #[case("false[", T::t(Token::LitFalse, "false"), T::t(Token::ArrBegin, "[").pos(5, 1, 6), 1, 7)]
1988    #[case("false]", T::t(Token::LitFalse, "false"), T::t(Token::ArrEnd, "]").pos(5, 1, 6), 1, 7)]
1989    #[case("false:", T::t(Token::LitFalse, "false"), T::t(Token::NameSep, ":").pos(5, 1, 6), 1, 7)]
1990    #[case("false,", T::t(Token::LitFalse, "false"), T::t(Token::ValueSep, ",").pos(5, 1, 6), 1, 7)]
1991    #[case("false ", T::t(Token::LitFalse, "false"), T::t(Token::White, " ").pos(5, 1, 6), 1, 7)]
1992    #[case("false\t", T::t(Token::LitFalse, "false"), T::t(Token::White, "\t").pos(5, 1, 6), 1, 7)]
1993    #[case("false\r", T::t(Token::LitFalse, "false"), T::t(Token::White, "\r").pos(5, 1, 6), 2, 1)]
1994    #[case("false\n", T::t(Token::LitFalse, "false"), T::t(Token::White, "\n").pos(5, 1, 6), 2, 1)]
1995    #[case("false\r\n", T::t(Token::LitFalse, "false"), T::t(Token::White, "\r\n").pos(5, 1, 6), 2, 1)]
1996    #[case("false\n\r", T::t(Token::LitFalse, "false"), T::t(Token::White, "\n\r").pos(5, 1, 6), 3, 1)]
1997    #[case("false\r\n ", T::t(Token::LitFalse, "false"), T::t(Token::White, "\r\n ").pos(5, 1, 6), 2, 2)]
1998    #[case("false\n\r ", T::t(Token::LitFalse, "false"), T::t(Token::White, "\n\r ").pos(5, 1, 6), 3, 2)]
1999    #[case("false \r\n", T::t(Token::LitFalse, "false"), T::t(Token::White, " \r\n").pos(5, 1, 6), 2, 1)]
2000    #[case("false \n\r", T::t(Token::LitFalse, "false"), T::t(Token::White, " \n\r").pos(5, 1, 6), 3, 1)]
2001    #[case(r#"false"""#, T::t(Token::LitFalse, "false"), T::t(Token::Str, r#""""#).pos(5, 1, 6), 1, 8)]
2002    // =============================================================================================
2003    // Literal `null` followed by something...
2004    // =============================================================================================
2005    #[case("null{", T::t(Token::LitNull, "null"), T::t(Token::ObjBegin, "{").pos(4, 1, 5), 1, 6)]
2006    #[case("null}", T::t(Token::LitNull, "null"), T::t(Token::ObjEnd, "}").pos(4, 1, 5), 1, 6)]
2007    #[case("null[", T::t(Token::LitNull, "null"), T::t(Token::ArrBegin, "[").pos(4, 1, 5), 1, 6)]
2008    #[case("null]", T::t(Token::LitNull, "null"), T::t(Token::ArrEnd, "]").pos(4, 1, 5), 1, 6)]
2009    #[case("null:", T::t(Token::LitNull, "null"), T::t(Token::NameSep, ":").pos(4, 1, 5), 1, 6)]
2010    #[case("null,", T::t(Token::LitNull, "null"), T::t(Token::ValueSep, ",").pos(4, 1, 5), 1, 6)]
2011    #[case("null ", T::t(Token::LitNull, "null"), T::t(Token::White, " ").pos(4, 1, 5), 1, 6)]
2012    #[case("null\t", T::t(Token::LitNull, "null"), T::t(Token::White, "\t").pos(4, 1, 5), 1, 6)]
2013    #[case("null\r", T::t(Token::LitNull, "null"), T::t(Token::White, "\r").pos(4, 1, 5), 2, 1)]
2014    #[case("null\n", T::t(Token::LitNull, "null"), T::t(Token::White, "\n").pos(4, 1, 5), 2, 1)]
2015    #[case(r#"null"x""#, T::t(Token::LitNull, "null"), T::t(Token::Str, r#""x""#).pos(4, 1, 5), 1, 8)]
2016    // =============================================================================================
2017    // Literal `true` followed by something...
2018    // =============================================================================================
2019    #[case("true{", T::t(Token::LitTrue, "true"), T::t(Token::ObjBegin, "{").pos(4, 1, 5), 1, 6)]
2020    #[case("true}", T::t(Token::LitTrue, "true"), T::t(Token::ObjEnd, "}").pos(4, 1, 5), 1, 6)]
2021    #[case("true[", T::t(Token::LitTrue, "true"), T::t(Token::ArrBegin, "[").pos(4, 1, 5), 1, 6)]
2022    #[case("true]", T::t(Token::LitTrue, "true"), T::t(Token::ArrEnd, "]").pos(4, 1, 5), 1, 6)]
2023    #[case("true:", T::t(Token::LitTrue, "true"), T::t(Token::NameSep, ":").pos(4, 1, 5), 1, 6)]
2024    #[case("true,", T::t(Token::LitTrue, "true"), T::t(Token::ValueSep, ",").pos(4, 1, 5), 1, 6)]
2025    #[case("true ", T::t(Token::LitTrue, "true"), T::t(Token::White, " ").pos(4, 1, 5), 1, 6)]
2026    #[case("true\t", T::t(Token::LitTrue, "true"), T::t(Token::White, "\t").pos(4, 1, 5), 1, 6)]
2027    #[case("true\r", T::t(Token::LitTrue, "true"), T::t(Token::White, "\r").pos(4, 1, 5), 2, 1)]
2028    #[case("true\n", T::t(Token::LitTrue, "true"), T::t(Token::White, "\n").pos(4, 1, 5), 2, 1)]
2029    #[case(r#"true"🧶""#, T::t(Token::LitTrue, "true"), T::t(Token::Str, r#""🧶""#).pos(4, 1, 5), 1, 8)]
2030    // =============================================================================================
2031    // Number followed by something...
2032    // =============================================================================================
2033    #[case("0{", T::t(Token::Num, "0"), T::t(Token::ObjBegin, "{").pos(1, 1, 2), 1, 3)]
2034    #[case("0}", T::t(Token::Num, "0"), T::t(Token::ObjEnd, "}").pos(1, 1, 2), 1, 3)]
2035    #[case("0[", T::t(Token::Num, "0"), T::t(Token::ArrBegin, "[").pos(1, 1, 2), 1, 3)]
2036    #[case("0]", T::t(Token::Num, "0"), T::t(Token::ArrEnd, "]").pos(1, 1, 2), 1, 3)]
2037    #[case("0:", T::t(Token::Num, "0"), T::t(Token::NameSep, ":").pos(1, 1, 2), 1, 3)]
2038    #[case("0,", T::t(Token::Num, "0"), T::t(Token::ValueSep, ",").pos(1, 1, 2), 1, 3)]
2039    #[case("0 ", T::t(Token::Num, "0"), T::t(Token::White, " ").pos(1, 1, 2), 1, 3)]
2040    #[case("0\t", T::t(Token::Num, "0"), T::t(Token::White, "\t").pos(1, 1, 2), 1, 3)]
2041    #[case("0\r", T::t(Token::Num, "0"), T::t(Token::White, "\r").pos(1, 1, 2), 2, 1)]
2042    #[case("0\n", T::t(Token::Num, "0"), T::t(Token::White, "\n").pos(1, 1, 2), 2, 1)]
2043    #[case(r#"0"""#, T::t(Token::Num, "0"), T::t(Token::Str, r#""""#).pos(1, 1, 2), 1, 4)]
2044    #[case("1{", T::t(Token::Num, "1"), T::t(Token::ObjBegin, "{").pos(1, 1, 2), 1, 3)]
2045    #[case("-9}", T::t(Token::Num, "-9"), T::t(Token::ObjEnd, "}").pos(2, 1, 3), 1, 4)]
2046    #[case("0.0[", T::t(Token::Num, "0.0"), T::t(Token::ArrBegin, "[").pos(3, 1, 4), 1, 5)]
2047    #[case("-0]", T::t(Token::Num, "-0"), T::t(Token::ArrEnd, "]").pos(2, 1, 3), 1, 4)]
2048    #[case(r#"-0"a""#, T::t(Token::Num, "-0"), T::t(Token::Str, r#""a""#).pos(2, 1, 3), 1, 6)]
2049    #[case("-0.0123456789:", T::t(Token::Num, "-0.0123456789"), T::t(Token::NameSep, ":").pos(13, 1, 14), 1, 15)]
2050    #[case("123456789e10,", T::t(Token::Num, "123456789e10"), T::t(Token::ValueSep, ",").pos(12, 1, 13), 1, 14)]
2051    #[case("0e-1 ", T::t(Token::Num, "0e-1"), T::t(Token::White, " ").pos(4, 1, 5), 1, 6)]
2052    #[case("2e+3\t", T::t(Token::Num, "2e+3"), T::t(Token::White, "\t").pos(4, 1, 5), 1, 6)]
2053    #[case("-5e6\r", T::t(Token::Num, "-5e6"), T::t(Token::White, "\r").pos(4, 1, 5), 2, 1)]
2054    #[case("6.7e89\n", T::t(Token::Num, "6.7e89"), T::t(Token::White, "\n").pos(6, 1, 7), 2, 1)]
2055    #[case(r#"1"a""#, T::t(Token::Num, "1"), T::t(Token::Str, r#""a""#).pos(1, 1, 2), 1, 5)]
2056    #[case(r#"2.5"a""#, T::t(Token::Num, "2.5"), T::t(Token::Str, r#""a""#).pos(3, 1, 4), 1, 7)]
2057    #[case(r#"3e4"a""#, T::t(Token::Num, "3e4"), T::t(Token::Str, r#""a""#).pos(3, 1, 4), 1, 7)]
2058    // =============================================================================================
2059    // String followed by something...
2060    // =============================================================================================
2061    #[case(r#"""{"#, T::t(Token::Str, r#""""#), T::t(Token::ObjBegin, "{").pos(2, 1, 3), 1, 4)]
2062    #[case(r#"""}"#, T::t(Token::Str, r#""""#), T::t(Token::ObjEnd, "}").pos(2, 1, 3), 1, 4)]
2063    #[case(r#"""["#, T::t(Token::Str, r#""""#), T::t(Token::ArrBegin, "[").pos(2, 1, 3), 1, 4)]
2064    #[case(r#"""]"#, T::t(Token::Str, r#""""#), T::t(Token::ArrEnd, "]").pos(2, 1, 3), 1, 4)]
2065    #[case(r#""":"#, T::t(Token::Str, r#""""#), T::t(Token::NameSep, ":").pos(2, 1, 3), 1, 4)]
2066    #[case(r#""","#, T::t(Token::Str, r#""""#), T::t(Token::ValueSep, ",").pos(2, 1, 3), 1, 4)]
2067    #[case(r#""" "#, T::t(Token::Str, r#""""#), T::t(Token::White, " ").pos(2, 1, 3), 1, 4)]
2068    #[case("\"\"\t", T::t(Token::Str, r#""""#), T::t(Token::White, "\t").pos(2, 1, 3), 1, 4)]
2069    #[case("\"\"\r", T::t(Token::Str, r#""""#), T::t(Token::White, "\r").pos(2, 1, 3), 2, 1)]
2070    #[case("\"\"\n", T::t(Token::Str, r#""""#), T::t(Token::White, "\n").pos(2, 1, 3), 2, 1)]
2071    #[case(r#""x"}"#, T::t(Token::Str, r#""x""#), T::t(Token::ObjEnd, "}").pos(3, 1, 4), 1, 5)]
2072    #[case(r#""foo bar"]"#, T::t(Token::Str, r#""foo bar""#), T::t(Token::ArrEnd, "]").pos(9, 1, 10), 1, 11)]
2073    #[case(r#""🧶":"#, T::t(Token::Str, r#""🧶""#), T::t(Token::NameSep, ":").pos(6, 1, 4), 1, 5)]
2074    #[case(r#""\"\t\r\n\\\/\u0020\"","#, T::t(Token::Str, r#""\"\t\r\n\\\/\u0020\"""#).unescaped("\"\"\t\r\n\\/ \"\""), T::t(Token::ValueSep, ",").pos(22, 1, 23), 1, 24)]
2075    #[case(r#""treble \uD834\uDD1E""clef""#, T::t(Token::Str, r#""treble \uD834\uDD1E""#).unescaped("\"treble 𝄞\""), T::t(Token::Str, r#""clef""#).pos(21, 1, 22), 1, 28)]
2076    #[case(r#""a"0e+12"#, T::t(Token::Str, r#""a""#), T::t(Token::Num, "0e+12").pos(3, 1, 4), 1, 9)]
2077    #[case(r#""❤😊"-0"#, T::t(Token::Str, r#""❤😊""#), T::t(Token::Num, "-0").pos(9, 1, 5), 1, 7)]
2078    #[case(r#""❤️😊"1"#, T::t(Token::Str, r#""❤️😊""#), T::t(Token::Num, "1").pos(12, 1, 6), 1, 7)]
2079    #[case(r#""""a""#, T::t(Token::Str, r#""""#), T::t(Token::Str, r#""a""#).pos(2, 1, 3), 1, 6)]
2080    #[case(r#""""café""#, T::t(Token::Str, r#""""#), T::t(Token::Str, r#""café""#).pos(2, 1, 3), 1, 9)]
2081    #[case(r#""a""""#, T::t(Token::Str, r#""a""#), T::t(Token::Str, r#""""#).pos(3, 1, 4), 1, 6)]
2082    #[case(r#""€10""""#, T::t(Token::Str, r#""€10""#), T::t(Token::Str, r#""""#).pos(7, 1, 6), 1, 8)]
2083    // =============================================================================================
2084    // Whitespace followed by something...
2085    // =============================================================================================
2086    #[case(" {", T::t(Token::White, " "), T::t(Token::ObjBegin, "{").pos(1, 1, 2), 1, 3)]
2087    #[case(" }", T::t(Token::White, " "), T::t(Token::ObjEnd, "}").pos(1, 1, 2), 1, 3)]
2088    #[case(" [", T::t(Token::White, " "), T::t(Token::ArrBegin, "[").pos(1, 1, 2), 1, 3)]
2089    #[case(" ]", T::t(Token::White, " "), T::t(Token::ArrEnd, "]").pos(1, 1, 2), 1, 3)]
2090    #[case(" :", T::t(Token::White, " "), T::t(Token::NameSep, ":").pos(1, 1, 2), 1, 3)]
2091    #[case(" ,", T::t(Token::White, " "), T::t(Token::ValueSep, ",").pos(1, 1, 2), 1, 3)]
2092    #[case(" false", T::t(Token::White, " "), T::t(Token::LitFalse, "false").pos(1, 1, 2), 1, 7)]
2093    #[case(" null", T::t(Token::White, " "), T::t(Token::LitNull, "null").pos(1, 1, 2), 1, 6)]
2094    #[case(" true", T::t(Token::White, " "), T::t(Token::LitTrue, "true").pos(1, 1, 2), 1, 6)]
2095    #[case(" 0", T::t(Token::White, " "), T::t(Token::Num, "0").pos(1, 1, 2), 1, 3)]
2096    #[case(" -0", T::t(Token::White, " "), T::t(Token::Num, "-0").pos(1, 1, 2), 1, 4)]
2097    #[case(r#" """#, T::t(Token::White, " "), T::t(Token::Str, r#""""#).pos(1, 1, 2), 1, 4)]
2098    #[case("\t{", T::t(Token::White, "\t"), T::t(Token::ObjBegin, "{").pos(1, 1, 2), 1, 3)]
2099    #[case("  {", T::t(Token::White, "  "), T::t(Token::ObjBegin, "{").pos(2, 1, 3), 1, 4)]
2100    #[case("\n{", T::t(Token::White, "\n"), T::t(Token::ObjBegin, "{").pos(1, 2, 1), 2, 2)]
2101    #[case("\r{", T::t(Token::White, "\r"), T::t(Token::ObjBegin, "{").pos(1, 2, 1), 2, 2)]
2102    #[case("\r\n{", T::t(Token::White, "\r\n"), T::t(Token::ObjBegin, "{").pos(2, 2, 1), 2, 2)]
2103    #[case("\n\r{", T::t(Token::White, "\n\r"), T::t(Token::ObjBegin, "{").pos(2, 3, 1), 3, 2)]
2104    #[case("\n\n{", T::t(Token::White, "\n\n"), T::t(Token::ObjBegin, "{").pos(2, 3, 1), 3, 2)]
2105    #[case("\r\r{", T::t(Token::White, "\r\r"), T::t(Token::ObjBegin, "{").pos(2, 3, 1), 3, 2)]
2106    fn test_analyzer_two_tokens(
2107        #[case] input: &str,
2108        #[case] t1: T,
2109        #[case] t2: T,
2110        #[case] line: usize,
2111        #[case] col: usize,
2112    ) {
2113        // With content fetch.
2114        {
2115            let mut an = FixedAnalyzer::new(input.as_bytes());
2116            assert_eq!(Pos::default(), *an.pos());
2117
2118            assert_eq!(t1.token, an.next());
2119            assert_eq!(t1.pos, *an.pos());
2120
2121            let content1 = an.content();
2122            assert_eq!(t1.literal, content1.literal());
2123            assert_eq!(t1.is_escaped(), content1.is_escaped());
2124            assert_eq!(t1.unescaped, content1.unescaped());
2125
2126            assert_eq!(t2.token, an.next());
2127            assert_eq!(t2.pos, *an.pos());
2128
2129            let content2 = an.content();
2130            assert_eq!(t2.literal, content2.literal());
2131            assert_eq!(t2.is_escaped(), content2.is_escaped());
2132            assert_eq!(t2.unescaped, content2.unescaped());
2133
2134            assert_eq!(Token::Eof, an.next());
2135            assert_eq!(
2136                Pos {
2137                    offset: input.len(),
2138                    line,
2139                    col
2140                },
2141                *an.pos()
2142            );
2143        }
2144
2145        // Without content fetch.
2146        {
2147            let mut an = FixedAnalyzer::new(input.as_bytes());
2148            assert_eq!(Pos::default(), *an.pos());
2149
2150            assert_eq!(t1.token, an.next());
2151            assert_eq!(t1.pos, *an.pos());
2152
2153            assert_eq!(t2.token, an.next());
2154            assert_eq!(t2.pos, *an.pos());
2155
2156            assert_eq!(Token::Eof, an.next());
2157            assert_eq!(
2158                Pos {
2159                    offset: input.len(),
2160                    line,
2161                    col
2162                },
2163                *an.pos()
2164            );
2165        }
2166    }
2167
2168    #[derive(Debug)]
2169    struct T {
2170        token: Token,
2171        pos: Pos,
2172        literal: &'static str,
2173        unescaped: &'static str,
2174    }
2175
2176    impl T {
2177        fn t(token: Token, literal: &'static str) -> Self {
2178            Self {
2179                token,
2180                pos: Pos::default(),
2181                literal,
2182                unescaped: literal,
2183            }
2184        }
2185
2186        fn pos(mut self, offset: usize, line: usize, col: usize) -> Self {
2187            self.pos = Pos { offset, line, col };
2188            self
2189        }
2190
2191        fn unescaped(mut self, unescaped: &'static str) -> Self {
2192            self.unescaped = unescaped;
2193            self
2194        }
2195
2196        fn is_escaped(&self) -> bool {
2197            self.unescaped != self.literal
2198        }
2199    }
2200
2201    #[rstest]
2202    #[case(r#""\uDC00""#, 0xdc00, None, 3)]
2203    #[case(r#""\udc00""#, 0xdc00, None, 3)]
2204    #[case(r#""\uDFFF""#, 0xdfff, None, 3)]
2205    #[case(r#""\udfff""#, 0xdfff, None, 3)]
2206    #[case(r#""\uD800""#, 0xd800, None, 3)]
2207    #[case(r#""\ud800""#, 0xd800, None, 3)]
2208    #[case(r#""\uDBFF""#, 0xdbff, None, 3)]
2209    #[case(r#""\udbff""#, 0xdbff, None, 3)]
2210    #[case(r#""\uD800x""#, 0xd800, None, 3)]
2211    #[case(r#""\ud800x""#, 0xd800, None, 3)]
2212    #[case(r#""\uDBFFx""#, 0xdbff, None, 3)]
2213    #[case(r#""\udbffx""#, 0xdbff, None, 3)]
2214    #[case(r#""\uD800\""#, 0xd800, None, 3)]
2215    #[case(r#""\ud800\""#, 0xd800, None, 3)]
2216    #[case(r#""\uDBFF\""#, 0xdbff, None, 3)]
2217    #[case(r#""\udbff\""#, 0xdbff, None, 3)]
2218    #[case(r#""\uD800\/""#, 0xd800, None, 3)]
2219    #[case(r#""\ud800\t""#, 0xd800, None, 3)]
2220    #[case(r#""\uDBFF\r""#, 0xdbff, None, 3)]
2221    #[case(r#""\udbff\n""#, 0xdbff, None, 3)]
2222    #[case(r#""\uD800\ud800""#, 0xd800, Some(0xd800), 9)]
2223    #[case(r#""\uD800\uDBFF""#, 0xd800, Some(0xdbff), 9)]
2224    #[case(r#""\udbff\ue000""#, 0xdbff, Some(0xe000), 9)]
2225    #[case(r#""\udbff\u0000""#, 0xdbff, Some(0x0000), 9)]
2226    fn test_analyzer_single_error_bad_surrogate(
2227        #[case] input: &str,
2228        #[case] first: u16,
2229        #[case] second: Option<u16>,
2230        #[case] pos_offset: usize,
2231    ) {
2232        // With error fetch.
2233        {
2234            let mut an = FixedAnalyzer::new(input.as_bytes());
2235            assert_eq!(Pos::default(), *an.pos());
2236
2237            assert_eq!(Token::Err, an.next());
2238            assert_eq!(Pos::default(), *an.pos());
2239
2240            let err = an.err();
2241            assert_eq!(ErrorKind::BadSurrogate { first, second }, err.kind());
2242            assert_eq!(
2243                Pos {
2244                    offset: pos_offset,
2245                    line: 1,
2246                    col: pos_offset + 1
2247                },
2248                *err.pos()
2249            );
2250
2251            assert_eq!(Token::Err, an.next());
2252            assert_eq!(Pos::default(), *an.pos());
2253        }
2254
2255        // Without error fetch.
2256        {
2257            let mut an = FixedAnalyzer::new(input.as_bytes());
2258            assert_eq!(Pos::default(), *an.pos());
2259
2260            assert_eq!(Token::Err, an.next());
2261            assert_eq!(Pos::default(), *an.pos());
2262
2263            assert_eq!(Token::Err, an.next());
2264            assert_eq!(Pos::default(), *an.pos());
2265        }
2266    }
2267
2268    #[rstest]
2269    #[case(&[0xc2, 0xc0], 1)]
2270    #[case(&[0xdf, 0xd0], 1)]
2271    #[case(&[0xe0, 0x7f, 0x80], 1)]
2272    #[case(&[0xe0, 0x80, 0x80], 1)]
2273    #[case(&[0xe0, 0xc0, 0x80], 1)]
2274    #[case(&[0xed, 0xa0, 0x80], 1)]
2275    #[case(&[0xed, 0xa0, 0xbf], 1)]
2276    #[case(&[0xed, 0xb0, 0x80], 1)]
2277    #[case(&[0xed, 0xb0, 0xbf], 1)]
2278    #[case(&[0xef, 0x7f, 0x80], 1)]
2279    #[case(&[0xef, 0xc0, 0x80], 1)]
2280    #[case(&[0xe0, 0x80, 0x7f], 2)]
2281    #[case(&[0xe0, 0x80, 0xc0], 2)]
2282    #[case(&[0xe0, 0xbf, 0x7f], 2)]
2283    #[case(&[0xe0, 0xbf, 0xc0], 2)]
2284    #[case(&[0xf0, 0x7f, 0x80, 0x80], 1)]
2285    #[case(&[0xf0, 0x80, 0x80, 0x80], 1)]
2286    #[case(&[0xf0, 0xc0, 0x80, 0x80], 1)]
2287    #[case(&[0xf4, 0x7f, 0x80, 0x80], 1)]
2288    #[case(&[0xf4, 0xc0, 0x80, 0x80], 1)]
2289    #[case(&[0xf4, 0x90, 0x80, 0x80], 1)]
2290    #[case(&[0xf0, 0x80, 0x7f, 0x80], 2)]
2291    #[case(&[0xf0, 0x80, 0xc0, 0x80], 2)]
2292    #[case(&[0xf0, 0xbf, 0x7f, 0x80], 2)]
2293    #[case(&[0xf0, 0xbf, 0xc0, 0x80], 2)]
2294    #[case(&[0xf0, 0x80, 0x80, 0x7f], 3)]
2295    #[case(&[0xf0, 0x80, 0x80, 0xc0], 3)]
2296    #[case(&[0xf0, 0xbf, 0xbf, 0x7f], 3)]
2297    #[case(&[0xf0, 0xbf, 0xbf, 0xc0], 3)]
2298    fn test_analyzer_single_error_bad_utf8_cont_byte(#[case] input: &[u8], #[case] offset: u8) {
2299        // Construct input buffer.
2300        let mut buf = Vec::with_capacity(input.len() + 1);
2301        buf.push(b'"');
2302        buf.extend_from_slice(input);
2303
2304        // With error fetch.
2305        {
2306            let mut an = FixedAnalyzer::new(buf.clone());
2307            assert_eq!(Pos::default(), *an.pos());
2308
2309            assert_eq!(Token::Err, an.next());
2310            assert_eq!(Pos::default(), *an.pos());
2311
2312            let err = an.err();
2313            assert_eq!(
2314                ErrorKind::BadUtf8ContByte {
2315                    seq_len: input.len() as u8,
2316                    offset,
2317                    value: input[offset as usize]
2318                },
2319                err.kind()
2320            );
2321            assert_eq!(
2322                Pos {
2323                    offset: 1,
2324                    line: 1,
2325                    col: 2, // Second column is the entire multi-byte UTF-8 sequence.
2326                },
2327                *err.pos()
2328            );
2329
2330            assert_eq!(Token::Err, an.next());
2331            assert_eq!(Pos::default(), *an.pos());
2332        }
2333
2334        // Without error fetch.
2335        {
2336            let mut an = FixedAnalyzer::new(buf.clone());
2337            assert_eq!(Pos::default(), *an.pos());
2338
2339            assert_eq!(Token::Err, an.next());
2340            assert_eq!(Pos::default(), *an.pos());
2341
2342            assert_eq!(Token::Err, an.next());
2343            assert_eq!(Pos::default(), *an.pos());
2344        }
2345    }
2346
2347    #[rstest]
2348    // =============================================================================================
2349    // Continuation bytes...
2350    // =============================================================================================
2351    #[case(0x80)]
2352    #[case(0x81)]
2353    #[case(0x82)]
2354    #[case(0x83)]
2355    #[case(0x84)]
2356    #[case(0x85)]
2357    #[case(0x86)]
2358    #[case(0x87)]
2359    #[case(0x88)]
2360    #[case(0x89)]
2361    #[case(0x8a)]
2362    #[case(0x8b)]
2363    #[case(0x8c)]
2364    #[case(0x8d)]
2365    #[case(0x8e)]
2366    #[case(0x8f)]
2367    #[case(0x90)]
2368    #[case(0x91)]
2369    #[case(0x92)]
2370    #[case(0x93)]
2371    #[case(0x94)]
2372    #[case(0x95)]
2373    #[case(0x96)]
2374    #[case(0x97)]
2375    #[case(0x98)]
2376    #[case(0x99)]
2377    #[case(0x9a)]
2378    #[case(0x9b)]
2379    #[case(0x9c)]
2380    #[case(0x9d)]
2381    #[case(0x9e)]
2382    #[case(0x9f)]
2383    #[case(0xa0)]
2384    #[case(0xa1)]
2385    #[case(0xa2)]
2386    #[case(0xa3)]
2387    #[case(0xa4)]
2388    #[case(0xa5)]
2389    #[case(0xa6)]
2390    #[case(0xa7)]
2391    #[case(0xa8)]
2392    #[case(0xa9)]
2393    #[case(0xaa)]
2394    #[case(0xab)]
2395    #[case(0xac)]
2396    #[case(0xad)]
2397    #[case(0xae)]
2398    #[case(0xaf)]
2399    #[case(0xb0)]
2400    #[case(0xb1)]
2401    #[case(0xb2)]
2402    #[case(0xb3)]
2403    #[case(0xb4)]
2404    #[case(0xb5)]
2405    #[case(0xb6)]
2406    #[case(0xb7)]
2407    #[case(0xb8)]
2408    #[case(0xb9)]
2409    #[case(0xba)]
2410    #[case(0xbb)]
2411    #[case(0xbc)]
2412    #[case(0xbd)]
2413    #[case(0xbe)]
2414    #[case(0xbf)]
2415    // =============================================================================================
2416    // Always produce overlong encodings...
2417    // =============================================================================================
2418    #[case(0xc0)]
2419    #[case(0xc1)]
2420    // =============================================================================================
2421    // Always produce code points beyond the Unicode range...
2422    // =============================================================================================
2423    #[case(0xf5)]
2424    #[case(0xf6)]
2425    #[case(0xf7)]
2426    #[case(0xf8)]
2427    #[case(0xf9)]
2428    #[case(0xfa)]
2429    #[case(0xfb)]
2430    #[case(0xfc)]
2431    #[case(0xfd)]
2432    #[case(0xfe)]
2433    #[case(0xff)]
2434    fn test_analyzer_single_error_bad_utf8_start_byte(#[case] b: u8) {
2435        // Construct input buffer.
2436        let mut buf = Vec::with_capacity(2);
2437        buf.push(b'"');
2438        buf.push(b);
2439
2440        // With error fetch.
2441        {
2442            let mut an = FixedAnalyzer::new(buf.clone());
2443            assert_eq!(Pos::default(), *an.pos());
2444
2445            assert_eq!(Token::Err, an.next());
2446            assert_eq!(Pos::default(), *an.pos());
2447
2448            let err = an.err();
2449            assert_eq!(
2450                ErrorKind::UnexpectedByte {
2451                    token: Some(Token::Str),
2452                    expect: Expect::StrChar,
2453                    actual: b,
2454                },
2455                err.kind()
2456            );
2457            assert_eq!(
2458                Pos {
2459                    offset: 1,
2460                    line: 1,
2461                    col: 2,
2462                },
2463                *err.pos()
2464            );
2465
2466            assert_eq!(Token::Err, an.next());
2467            assert_eq!(Pos::default(), *an.pos());
2468        }
2469
2470        // Without error fetch.
2471        {
2472            let mut an = FixedAnalyzer::new(buf.clone());
2473            assert_eq!(Pos::default(), *an.pos());
2474
2475            assert_eq!(Token::Err, an.next());
2476            assert_eq!(Pos::default(), *an.pos());
2477
2478            assert_eq!(Token::Err, an.next());
2479            assert_eq!(Pos::default(), *an.pos());
2480        }
2481    }
2482
2483    #[rstest]
2484    // =============================================================================================
2485    // Leading minus sign followed by bad character
2486    // =============================================================================================
2487    #[case("-}", Expect::Digit)]
2488    #[case("-]", Expect::Digit)]
2489    #[case("-a", Expect::Digit)]
2490    #[case("- ", Expect::Digit)]
2491    // =============================================================================================
2492    // Integer part starts with zero then followed by another digit
2493    // =============================================================================================
2494    #[case("00", Expect::DotExpOrBoundary)]
2495    #[case("01", Expect::DotExpOrBoundary)]
2496    #[case("02", Expect::DotExpOrBoundary)]
2497    #[case("03", Expect::DotExpOrBoundary)]
2498    #[case("04", Expect::DotExpOrBoundary)]
2499    #[case("05", Expect::DotExpOrBoundary)]
2500    #[case("06", Expect::DotExpOrBoundary)]
2501    #[case("07", Expect::DotExpOrBoundary)]
2502    #[case("08", Expect::DotExpOrBoundary)]
2503    #[case("09", Expect::DotExpOrBoundary)]
2504    #[case("-00", Expect::DotExpOrBoundary)]
2505    #[case("-01", Expect::DotExpOrBoundary)]
2506    #[case("-02", Expect::DotExpOrBoundary)]
2507    #[case("-03", Expect::DotExpOrBoundary)]
2508    #[case("-04", Expect::DotExpOrBoundary)]
2509    #[case("-05", Expect::DotExpOrBoundary)]
2510    #[case("-06", Expect::DotExpOrBoundary)]
2511    #[case("-07", Expect::DotExpOrBoundary)]
2512    #[case("-08", Expect::DotExpOrBoundary)]
2513    #[case("-09", Expect::DotExpOrBoundary)]
2514    // =============================================================================================
2515    // Integer part followed by a bad character
2516    // =============================================================================================
2517    #[case("0x", Expect::DotExpOrBoundary)]
2518    #[case("1x", Expect::DigitDotExpOrBoundary)]
2519    #[case("9/", Expect::DigitDotExpOrBoundary)]
2520    #[case("13456789000a", Expect::DigitDotExpOrBoundary)]
2521    // =============================================================================================
2522    // Integer part followed by a bad character
2523    // =============================================================================================
2524    #[case("0E,", Expect::DigitOrExpSign)]
2525    #[case("0e:", Expect::DigitOrExpSign)]
2526    #[case("1E ", Expect::DigitOrExpSign)]
2527    #[case("9ex", Expect::DigitOrExpSign)]
2528    // =============================================================================================
2529    // Dot followed by a bad character
2530    // =============================================================================================
2531    #[case("0.a", Expect::Digit)]
2532    #[case("0.{", Expect::Digit)]
2533    #[case("0.:", Expect::Digit)]
2534    #[case("0.-", Expect::Digit)]
2535    #[case("-0.a", Expect::Digit)]
2536    #[case("-0.{", Expect::Digit)]
2537    #[case("-0.:", Expect::Digit)]
2538    #[case("-0.-", Expect::Digit)]
2539    #[case("1.E", Expect::Digit)]
2540    #[case("2.e", Expect::Digit)]
2541    #[case("3.a", Expect::Digit)]
2542    #[case("4.a", Expect::Digit)]
2543    #[case("5.a", Expect::Digit)]
2544    #[case("6.a", Expect::Digit)]
2545    #[case("7.a", Expect::Digit)]
2546    #[case("8.a", Expect::Digit)]
2547    #[case("9.a", Expect::Digit)]
2548    #[case("-1.E", Expect::Digit)]
2549    #[case("-2.e", Expect::Digit)]
2550    #[case("-3.a", Expect::Digit)]
2551    #[case("-4.a", Expect::Digit)]
2552    #[case("-5.a", Expect::Digit)]
2553    #[case("-6.a", Expect::Digit)]
2554    #[case("-7.a", Expect::Digit)]
2555    #[case("-8.a", Expect::Digit)]
2556    #[case("-9.a", Expect::Digit)]
2557    #[case("10.E", Expect::Digit)]
2558    #[case("20.e", Expect::Digit)]
2559    #[case("30.a", Expect::Digit)]
2560    #[case("40.a", Expect::Digit)]
2561    #[case("50.a", Expect::Digit)]
2562    #[case("60.a", Expect::Digit)]
2563    #[case("70.a", Expect::Digit)]
2564    #[case("80.a", Expect::Digit)]
2565    #[case("90.a", Expect::Digit)]
2566    #[case("-10.E", Expect::Digit)]
2567    #[case("-20.e", Expect::Digit)]
2568    #[case("-30.a", Expect::Digit)]
2569    #[case("-40.a", Expect::Digit)]
2570    #[case("-50.a", Expect::Digit)]
2571    #[case("-60.a", Expect::Digit)]
2572    #[case("-70.a", Expect::Digit)]
2573    #[case("-80.a", Expect::Digit)]
2574    #[case("-90.a", Expect::Digit)]
2575    // =============================================================================================
2576    // Fractional part followed by bad character
2577    // =============================================================================================
2578    #[case("0.0|", Expect::DigitExpOrBoundary)]
2579    #[case("-0.0-", Expect::DigitExpOrBoundary)]
2580    #[case("1.0D", Expect::DigitExpOrBoundary)]
2581    #[case("-1.5d", Expect::DigitExpOrBoundary)]
2582    #[case("9.01F", Expect::DigitExpOrBoundary)]
2583    #[case("-9.001f", Expect::DigitExpOrBoundary)]
2584    #[case("100.001x", Expect::DigitExpOrBoundary)]
2585    // =============================================================================================
2586    // Exponent indicator 'E' or 'e' followed by a bad character
2587    // =============================================================================================
2588    #[case("0Ee", Expect::DigitOrExpSign)]
2589    #[case("-0e.", Expect::DigitOrExpSign)]
2590    #[case("1Ee", Expect::DigitOrExpSign)]
2591    #[case("-1e.", Expect::DigitOrExpSign)]
2592    #[case("2.0Ef", Expect::DigitOrExpSign)]
2593    #[case("-2.0ef", Expect::DigitOrExpSign)]
2594    #[case("3.01e.", Expect::DigitOrExpSign)]
2595    #[case("-456789.10111213141516171819E\"", Expect::DigitOrExpSign)]
2596    // =============================================================================================
2597    // Exponent sign '+' or '-' followed by a bad character
2598    // =============================================================================================
2599    #[case("0E++", Expect::Digit)]
2600    #[case("0e--", Expect::Digit)]
2601    #[case("1E+x", Expect::Digit)]
2602    #[case("2e+\"", Expect::Digit)]
2603    #[case("3E+:", Expect::Digit)]
2604    #[case("4e+,", Expect::Digit)]
2605    #[case("5E+{", Expect::Digit)]
2606    #[case("6e-}", Expect::Digit)]
2607    #[case("7E-[", Expect::Digit)]
2608    #[case("8e-]", Expect::Digit)]
2609    #[case("9E- ", Expect::Digit)]
2610    #[case("-0E+\t", Expect::Digit)]
2611    #[case("-0e-e", Expect::Digit)]
2612    #[case("-1E+E", Expect::Digit)]
2613    #[case("-2e+.", Expect::Digit)]
2614    #[case("-3E+!", Expect::Digit)]
2615    #[case("-4e+@", Expect::Digit)]
2616    #[case("-5E+#", Expect::Digit)]
2617    #[case("-6e-$", Expect::Digit)]
2618    #[case("-7E-%", Expect::Digit)]
2619    #[case("-8e-^", Expect::Digit)]
2620    #[case("-9E-&", Expect::Digit)]
2621    #[case("0.1E++", Expect::Digit)]
2622    #[case("0.1e--", Expect::Digit)]
2623    #[case("1.1E+x", Expect::Digit)]
2624    #[case("2.1e+\"", Expect::Digit)]
2625    #[case("3.1E+:", Expect::Digit)]
2626    #[case("4.1e+,", Expect::Digit)]
2627    #[case("5.1E+{", Expect::Digit)]
2628    #[case("6.1e-}", Expect::Digit)]
2629    #[case("7.1E-[", Expect::Digit)]
2630    #[case("8.1e-]", Expect::Digit)]
2631    #[case("9.1E- ", Expect::Digit)]
2632    #[case("-0.234E+\t", Expect::Digit)]
2633    #[case("-0.234e-e", Expect::Digit)]
2634    #[case("-1.234E+E", Expect::Digit)]
2635    #[case("-2.234e+.", Expect::Digit)]
2636    #[case("-3.234E+!", Expect::Digit)]
2637    #[case("-4.234e+@", Expect::Digit)]
2638    #[case("-5.234E+#", Expect::Digit)]
2639    #[case("-6.234e-$", Expect::Digit)]
2640    #[case("-7.234E-%", Expect::Digit)]
2641    #[case("-8.234e-^", Expect::Digit)]
2642    #[case("-9.234E-&", Expect::Digit)]
2643    // =============================================================================================
2644    // Exponent part followed by a bad character
2645    // =============================================================================================
2646    #[case("0E0e", Expect::DigitOrBoundary)]
2647    #[case("0E+0e", Expect::DigitOrBoundary)]
2648    #[case("0E-0e", Expect::DigitOrBoundary)]
2649    #[case("0.0e0e", Expect::DigitOrBoundary)]
2650    #[case("0.00e00e", Expect::DigitOrBoundary)]
2651    #[case("1.1E+1e", Expect::DigitOrBoundary)]
2652    #[case("11.11E+11e", Expect::DigitOrBoundary)]
2653    #[case("99.999E-999e", Expect::DigitOrBoundary)]
2654    fn test_analyzer_single_error_bad_number(#[case] input: &str, #[case] expect: Expect) {
2655        let mut an = FixedAnalyzer::new(input.as_bytes());
2656
2657        assert_eq!(Token::Err, an.next());
2658        assert_eq!(Pos::default(), *an.pos());
2659
2660        let err = an.err();
2661        assert_eq!(
2662            ErrorKind::UnexpectedByte {
2663                token: Some(Token::Num),
2664                expect,
2665                actual: *input.as_bytes().last().unwrap(),
2666            },
2667            err.kind(),
2668            "input={input:?}"
2669        );
2670        assert_eq!(
2671            Pos {
2672                offset: input.len() - 1,
2673                line: 1,
2674                col: input.len(),
2675            },
2676            *err.pos(),
2677            "input={input:?}"
2678        );
2679
2680        assert_eq!(Token::Err, an.next(), "input={input:?}");
2681        assert_eq!(Pos::default(), *an.pos(), "input={input:?}");
2682    }
2683
2684    #[rstest]
2685    #[case(r#"\0"#, Expect::EscChar)]
2686    #[case(r#"\a"#, Expect::EscChar)]
2687    #[case(r#"\v"#, Expect::EscChar)]
2688    #[case(r#"\x"#, Expect::EscChar)]
2689    #[case(r#"\uG"#, Expect::UnicodeEscHexDigit)]
2690    #[case(r#"\u:"#, Expect::UnicodeEscHexDigit)]
2691    #[case(r#"\u_"#, Expect::UnicodeEscHexDigit)]
2692    #[case(r#"\u0G"#, Expect::UnicodeEscHexDigit)]
2693    #[case(r#"\u1:"#, Expect::UnicodeEscHexDigit)]
2694    #[case(r#"\u2,"#, Expect::UnicodeEscHexDigit)]
2695    #[case(r#"\u3["#, Expect::UnicodeEscHexDigit)]
2696    #[case(r#"\u4]"#, Expect::UnicodeEscHexDigit)]
2697    #[case(r#"\u5{"#, Expect::UnicodeEscHexDigit)]
2698    #[case(r#"\u6}"#, Expect::UnicodeEscHexDigit)]
2699    #[case(r#"\u7."#, Expect::UnicodeEscHexDigit)]
2700    #[case(r#"\u8""#, Expect::UnicodeEscHexDigit)]
2701    #[case(r#"\u9g"#, Expect::UnicodeEscHexDigit)]
2702    #[case(r#"\uAG"#, Expect::UnicodeEscHexDigit)]
2703    #[case(r#"\ua_"#, Expect::UnicodeEscHexDigit)]
2704    #[case(r#"\uB_"#, Expect::UnicodeEscHexDigit)]
2705    #[case(r#"\ub_"#, Expect::UnicodeEscHexDigit)]
2706    #[case(r#"\uC_"#, Expect::UnicodeEscHexDigit)]
2707    #[case(r#"\uc_"#, Expect::UnicodeEscHexDigit)]
2708    #[case(r#"\uD_"#, Expect::UnicodeEscHexDigit)]
2709    #[case(r#"\ud_"#, Expect::UnicodeEscHexDigit)]
2710    #[case(r#"\uE_"#, Expect::UnicodeEscHexDigit)]
2711    #[case(r#"\ue_"#, Expect::UnicodeEscHexDigit)]
2712    #[case(r#"\uF_"#, Expect::UnicodeEscHexDigit)]
2713    #[case(r#"\uf_"#, Expect::UnicodeEscHexDigit)]
2714    #[case(r#"\u1a_"#, Expect::UnicodeEscHexDigit)]
2715    #[case(r#"\ub2C_"#, Expect::UnicodeEscHexDigit)]
2716    #[case(r#"\ud800\ug"#, Expect::UnicodeEscHexDigit)]
2717    #[case(r#"\ud800\u0:"#, Expect::UnicodeEscHexDigit)]
2718    #[case(r#"\ud800\u00:"#, Expect::UnicodeEscHexDigit)]
2719    #[case(r#"\ud800\u000:"#, Expect::UnicodeEscHexDigit)]
2720    fn test_analyzer_single_error_bad_escape(#[case] input: &str, #[case] expect: Expect) {
2721        let mut s = String::with_capacity(1 + input.len());
2722        s.push('"');
2723        s.push_str(input);
2724
2725        let mut an = FixedAnalyzer::new(s.as_bytes());
2726
2727        assert_eq!(Token::Err, an.next());
2728        assert_eq!(Pos::default(), *an.pos());
2729
2730        let err = an.err();
2731        assert_eq!(
2732            ErrorKind::UnexpectedByte {
2733                token: Some(Token::Str),
2734                expect,
2735                actual: *input.as_bytes().last().unwrap(),
2736            },
2737            err.kind(),
2738            "input={input:?}"
2739        );
2740        assert_eq!(
2741            Pos {
2742                offset: s.len() - 1,
2743                line: 1,
2744                col: s.len(),
2745            },
2746            *err.pos(),
2747            "input={input:?}"
2748        );
2749
2750        assert_eq!(Token::Err, an.next(), "input={input:?}");
2751        assert_eq!(Pos::default(), *an.pos(), "input={input:?}");
2752    }
2753
2754    #[rstest]
2755    #[case::nul(0x00)]
2756    #[case::soh(0x01)]
2757    #[case::stx(0x02)]
2758    #[case::etx(0x03)]
2759    #[case::eot(0x04)]
2760    #[case::enq(0x05)]
2761    #[case::ack(0x06)]
2762    #[case::bel(0x07)]
2763    #[case::bs(0x08)]
2764    #[case::ht(0x09)]
2765    #[case::lf(0x0A)]
2766    #[case::vt(0x0B)]
2767    #[case::ff(0x0C)]
2768    #[case::cr(0x0D)]
2769    #[case::so(0x0E)]
2770    #[case::si(0x0F)]
2771    #[case::dle(0x10)]
2772    #[case::dc1(0x11)]
2773    #[case::dc2(0x12)]
2774    #[case::dc3(0x13)]
2775    #[case::dc4(0x14)]
2776    #[case::nak(0x15)]
2777    #[case::syn(0x16)]
2778    #[case::etb(0x17)]
2779    #[case::can(0x18)]
2780    #[case::em(0x19)]
2781    #[case::sub(0x1A)]
2782    #[case::esc(0x1B)]
2783    #[case::fs(0x1C)]
2784    #[case::gs(0x1D)]
2785    #[case::rs(0x1E)]
2786    #[case::us(0x1F)]
2787    fn test_analyzer_single_error_control_char(#[case] ctrl: u8) {
2788        static PREFIXES: [&str; 6] = ["", "a", r#"\u1234"#, "café", "𝄞", "🧶"];
2789        static COLS: [usize; 6] = [0, 1, 6, 4, 1, 1];
2790        let mut s: String = '"'.into();
2791
2792        for (prefix, cols) in PREFIXES.iter().zip(COLS.iter().copied()) {
2793            s.truncate(1);
2794            s.push_str(prefix);
2795            s.push(ctrl as char);
2796
2797            let mut an = FixedAnalyzer::new(s.as_bytes());
2798
2799            assert_eq!(Token::Err, an.next());
2800            assert_eq!(Pos::default(), *an.pos());
2801
2802            let err = an.err();
2803            assert_eq!(
2804                ErrorKind::UnexpectedByte {
2805                    token: Some(Token::Str),
2806                    expect: Expect::StrChar,
2807                    actual: ctrl,
2808                },
2809                err.kind(),
2810                "s={s:?}"
2811            );
2812            assert_eq!(
2813                Pos {
2814                    offset: s.len() - 1,
2815                    line: 1,
2816                    col: 2 + cols,
2817                },
2818                *err.pos(),
2819                "s={s:?}"
2820            );
2821        }
2822    }
2823
2824    #[rstest]
2825    #[case("f", 'a', Token::LitFalse)]
2826    #[case("fa", 'l', Token::LitFalse)]
2827    #[case("fal", 's', Token::LitFalse)]
2828    #[case("fals", 'e', Token::LitFalse)]
2829    #[case("n", 'u', Token::LitNull)]
2830    #[case("nu", 'l', Token::LitNull)]
2831    #[case("nul", 'l', Token::LitNull)]
2832    #[case("t", 'r', Token::LitTrue)]
2833    #[case("tr", 'u', Token::LitTrue)]
2834    #[case("tru", 'e', Token::LitTrue)]
2835    fn test_analyzer_single_error_expect_char(
2836        #[case] input: &str,
2837        #[case] expect: char,
2838        #[case] expect_token: Token,
2839    ) {
2840        let bad_chars = &[
2841            b'[', b']', b':', b'{', b'}', b',', b'"', b'\\', b'$', b' ', b'\0', b'\t', b'A', b'x',
2842            b'X', b'0', b'9',
2843        ];
2844        let mut buf = Vec::with_capacity(input.len() + 1);
2845        buf.extend_from_slice(input.as_bytes());
2846        buf.push(b'_');
2847
2848        for (i, actual) in bad_chars.into_iter().enumerate() {
2849            buf[input.len()] = *actual;
2850
2851            let mut an = FixedAnalyzer::new(buf.clone());
2852
2853            assert_eq!(Token::Err, an.next());
2854            assert_eq!(Pos::default(), *an.pos());
2855
2856            let err = an.err();
2857            assert_eq!(
2858                ErrorKind::UnexpectedByte {
2859                    token: Some(expect_token),
2860                    expect: Expect::Char(expect),
2861                    actual: *actual,
2862                },
2863                err.kind(),
2864                "input={input:?}, i={i}, actual={actual:02x}"
2865            );
2866            assert_eq!(
2867                Pos {
2868                    offset: input.len(),
2869                    line: 1,
2870                    col: buf.len(),
2871                },
2872                *err.pos(),
2873                "input={input:?}, i={i}, actual={actual:02x}"
2874            );
2875
2876            assert_eq!(
2877                Token::Err,
2878                an.next(),
2879                "input={input:?}, i={i}, actual={actual:02x}"
2880            );
2881            assert_eq!(
2882                Pos::default(),
2883                *an.pos(),
2884                "input={input:?}, i={i}, actual={actual:02x}"
2885            );
2886        }
2887    }
2888
2889    #[rstest]
2890    #[case("falsep", Token::LitFalse)]
2891    #[case("nullE", Token::LitNull)]
2892    #[case("true0", Token::LitTrue)]
2893    fn test_analyzer_single_error_expect_boundary(
2894        #[case] input: &str,
2895        #[case] expect_token: Token,
2896    ) {
2897        let actual = input.as_bytes().last().copied().unwrap();
2898        let mut an = FixedAnalyzer::new(input.as_bytes());
2899
2900        assert_eq!(Token::Err, an.next());
2901        assert_eq!(Pos::default(), *an.pos());
2902
2903        let err = an.err();
2904        assert_eq!(
2905            ErrorKind::UnexpectedByte {
2906                token: Some(expect_token),
2907                expect: Expect::Boundary,
2908                actual,
2909            },
2910            err.kind(),
2911        );
2912        assert_eq!(
2913            Pos {
2914                offset: input.len() - 1,
2915                line: 1,
2916                col: input.len(),
2917            },
2918            *err.pos(),
2919        );
2920    }
2921
2922    #[rstest]
2923    #[case(r#"f"#, Token::LitFalse)]
2924    #[case(r#"fa"#, Token::LitFalse)]
2925    #[case(r#"fal"#, Token::LitFalse)]
2926    #[case(r#"n"#, Token::LitNull)]
2927    #[case(r#"nu"#, Token::LitNull)]
2928    #[case(r#"nul"#, Token::LitNull)]
2929    #[case(r#"-"#, Token::Num)]
2930    #[case(r#"0."#, Token::Num)]
2931    #[case(r#"1."#, Token::Num)]
2932    #[case(r#"2."#, Token::Num)]
2933    #[case(r#"3."#, Token::Num)]
2934    #[case(r#"4."#, Token::Num)]
2935    #[case(r#"5."#, Token::Num)]
2936    #[case(r#"6."#, Token::Num)]
2937    #[case(r#"7."#, Token::Num)]
2938    #[case(r#"8."#, Token::Num)]
2939    #[case(r#"9."#, Token::Num)]
2940    #[case(r#"10."#, Token::Num)]
2941    #[case(r#"0E"#, Token::Num)]
2942    #[case(r#"0E+"#, Token::Num)]
2943    #[case(r#"0E-"#, Token::Num)]
2944    #[case(r#"0e"#, Token::Num)]
2945    #[case(r#"0e+"#, Token::Num)]
2946    #[case(r#"0e-"#, Token::Num)]
2947    #[case(r#"1.0E"#, Token::Num)]
2948    #[case(r#"1.0E+"#, Token::Num)]
2949    #[case(r#"1.0E-"#, Token::Num)]
2950    #[case(r#"1.0e"#, Token::Num)]
2951    #[case(r#"1.0e+"#, Token::Num)]
2952    #[case(r#"1.0e-"#, Token::Num)]
2953    #[case(r#"""#, Token::Str)]
2954    #[case(r#""a"#, Token::Str)]
2955    #[case(r#""\"#, Token::Str)]
2956    #[case(r#""\u"#, Token::Str)]
2957    #[case(r#""\u1"#, Token::Str)]
2958    #[case(r#""\u12"#, Token::Str)]
2959    #[case(r#""\u123"#, Token::Str)]
2960    #[case(r#""\u1234"#, Token::Str)]
2961    #[case(r#""\u1234 foo bar"#, Token::Str)]
2962    #[case(r#"t"#, Token::LitTrue)]
2963    #[case(r#"tr"#, Token::LitTrue)]
2964    #[case(r#"tru"#, Token::LitTrue)]
2965    fn test_analyzer_single_error_unexpected_eof(#[case] input: &str, #[case] expect: Token) {
2966        // With error fetch.
2967        {
2968            let mut an = FixedAnalyzer::new(input.as_bytes());
2969            assert_eq!(Pos::default(), *an.pos());
2970
2971            assert_eq!(Token::Err, an.next());
2972            assert_eq!(Pos::default(), *an.pos());
2973
2974            let err = an.err();
2975            assert_eq!(
2976                ErrorKind::UnexpectedEof(expect),
2977                err.kind(),
2978                "input = {input:?}, expect = {expect:?}"
2979            );
2980            assert_eq!(
2981                Pos {
2982                    offset: input.len(),
2983                    line: 1,
2984                    col: 1 + input.len(),
2985                },
2986                *err.pos(),
2987                "input = {input:?}, expect = {expect:?}"
2988            );
2989
2990            assert_eq!(Token::Err, an.next());
2991            assert_eq!(Pos::default(), *an.pos());
2992        }
2993
2994        // Without error fetch.
2995        {
2996            let mut an = FixedAnalyzer::new(input.as_bytes());
2997            assert_eq!(Pos::default(), *an.pos());
2998
2999            assert_eq!(Token::Err, an.next());
3000            assert_eq!(Pos::default(), *an.pos());
3001
3002            assert_eq!(Token::Err, an.next());
3003            assert_eq!(Pos::default(), *an.pos());
3004        }
3005    }
3006
3007    #[rstest]
3008    #[case(0x00)]
3009    #[case(0x01)]
3010    #[case(0x02)]
3011    #[case(0x03)]
3012    #[case(0x04)]
3013    #[case(0x05)]
3014    #[case(0x06)]
3015    #[case(0x07)]
3016    #[case(0x08)]
3017    #[case(0x0b)]
3018    #[case(0x0c)]
3019    #[case(0x0e)]
3020    #[case(0x0f)]
3021    #[case(0x10)]
3022    #[case(0x11)]
3023    #[case(0x12)]
3024    #[case(0x13)]
3025    #[case(0x14)]
3026    #[case(0x15)]
3027    #[case(0x16)]
3028    #[case(0x17)]
3029    #[case(0x18)]
3030    #[case(0x19)]
3031    #[case(0x1a)]
3032    #[case(0x1b)]
3033    #[case(0x1c)]
3034    #[case(0x1d)]
3035    #[case(0x1e)]
3036    #[case(0x1f)]
3037    #[case(b'\'')]
3038    #[case(b'+')]
3039    #[case(b'.')]
3040    #[case(b'E')]
3041    #[case(b'\\')]
3042    #[case(b'e')]
3043    #[case(0x7f)]
3044    #[case(0x80)]
3045    #[case(0xbf)]
3046    #[case(0xc0)]
3047    #[case(0xc7)]
3048    #[case(0xcf)]
3049    #[case(0xd0)]
3050    #[case(0xd7)]
3051    #[case(0xdf)]
3052    #[case(0xe0)]
3053    #[case(0xe7)]
3054    #[case(0xef)]
3055    #[case(0xf0)]
3056    #[case(0xf7)]
3057    #[case(0xff)]
3058    fn test_analyzer_error_non_token_start(#[case] bad: u8) {
3059        // Bad character occurs at the very start of the text.
3060        {
3061            let mut an = FixedAnalyzer::new(vec![bad]);
3062            assert_eq!(Pos::default(), *an.pos());
3063
3064            assert_eq!(Token::Err, an.next());
3065            assert_eq!(Pos::default(), *an.pos());
3066
3067            let err = an.err();
3068            assert_eq!(
3069                ErrorKind::UnexpectedByte {
3070                    token: None,
3071                    expect: Expect::TokenStartChar,
3072                    actual: bad
3073                },
3074                err.kind(),
3075                "bad = {bad:02x}"
3076            );
3077            assert_eq!(Pos::default(), *err.pos(), "bad = {bad:02x}");
3078
3079            assert_eq!(Token::Err, an.next());
3080            assert_eq!(Pos::default(), *an.pos());
3081        }
3082
3083        // Bad character occurs after a valid token.
3084        {
3085            let valid_list = [
3086                "[",
3087                "]",
3088                "false ",
3089                "null ",
3090                "1 ",
3091                "{",
3092                "}",
3093                r#""a""#,
3094                r#""\u0000 foo \\//""#,
3095                "true\t",
3096            ];
3097
3098            for (i, valid) in valid_list.into_iter().enumerate() {
3099                let mut buf: Vec<u8> = Vec::with_capacity(valid.len() + 1);
3100                buf.extend_from_slice(valid.as_bytes());
3101                buf.push(bad);
3102
3103                let mut an = FixedAnalyzer::new(buf);
3104
3105                let token = an.next();
3106                assert!(
3107                    !token.is_terminal(),
3108                    "valid = {valid:?}, i = {i}, bad = {bad:02x}"
3109                );
3110                if token.is_literal() || token == Token::Num {
3111                    assert_eq!(
3112                        Token::White,
3113                        an.next(),
3114                        "valid = {valid:?}, i = {i}, bad = {bad:02x}"
3115                    );
3116                }
3117
3118                assert_eq!(Token::Err, an.next());
3119                let err = an.err();
3120                assert_eq!(
3121                    ErrorKind::UnexpectedByte {
3122                        token: None,
3123                        expect: Expect::TokenStartChar,
3124                        actual: bad
3125                    },
3126                    err.kind(),
3127                    "valid = {valid:?}, i = {i}, bad = {bad:02x}"
3128                );
3129                assert_eq!(
3130                    Pos {
3131                        offset: valid.len(),
3132                        line: 1,
3133                        col: 1 + valid.len(),
3134                    },
3135                    *err.pos(),
3136                    "valid = {valid:?}, i = {i}, bad = {bad:02x}"
3137                );
3138            }
3139        }
3140    }
3141
3142    #[rstest]
3143    #[case(br#"123.456789:a"#)]
3144    #[case(br#"<"#)]
3145    #[case(br#""foo" "bar" "baz"#)]
3146    #[should_panic(
3147        expected = "no content: last `next()` returned `Token::Err` (use `err()` instead)"
3148    )]
3149    fn test_analyzer_panic_no_content(#[case] input: &[u8]) {
3150        let mut an = FixedAnalyzer::new(input);
3151
3152        loop {
3153            if an.next() == Token::Err {
3154                break;
3155            }
3156        }
3157
3158        let _ = an.content();
3159    }
3160
3161    #[test]
3162    fn test_analyzer_smoke() {
3163        const JSON_TEXT: &str = r#"{
3164  "foo":["bar",1,5e-7, false, null  ,true, {"baz":"\\\"aââbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb©¢çc\"\\","qux":[{},{},null]}],
3165  "Lorem ipsum dolor sit amet, consectetur adipiscing elit." : "Cras sed ipsum at arcu porta blandit. Nunc eu mauris lacus. Vivamus dignissim tincidunt gravida. Fusce quis neque enim. Sed ac leo neque. Praesent feugiat efficitur eros, quis venenatis urna porttitor condimentum. Mauris finibus dui non vulputate mattis. Nullam scelerisque nibh vel dui egestas luctus. Vestibulum commodo mi ex. In laoreet hendrerit fringilla.\n\nPraesent vel ex sed dolor fermentum lobortis.",
3166  "👋":   ["🌎","🌏", "🌏", "こんにちは、世界"],
3167  "abc\u0020123": {{{"inner":[[[-1,-2.0,-3.00e+0,-4E-0,3.141592653589793238462643383279,null]]]}}}
3168}"#;
3169        const EXPECT: &[(Token, Pos, &str, Option<&str>)] = &[
3170            // Line 1
3171            (
3172                Token::ObjBegin,
3173                Pos {
3174                    offset: 0,
3175                    line: 1,
3176                    col: 1,
3177                },
3178                "{",
3179                None,
3180            ),
3181            (
3182                Token::White,
3183                Pos {
3184                    offset: 1,
3185                    line: 1,
3186                    col: 2,
3187                },
3188                "\n  ",
3189                None,
3190            ),
3191            // Line 2
3192            (
3193                Token::Str,
3194                Pos {
3195                    offset: 4,
3196                    line: 2,
3197                    col: 3,
3198                },
3199                r#""foo""#,
3200                None,
3201            ),
3202            (
3203                Token::NameSep,
3204                Pos {
3205                    offset: 9,
3206                    line: 2,
3207                    col: 8,
3208                },
3209                ":",
3210                None,
3211            ),
3212            (
3213                Token::ArrBegin,
3214                Pos {
3215                    offset: 10,
3216                    line: 2,
3217                    col: 9,
3218                },
3219                "[",
3220                None,
3221            ),
3222            (
3223                Token::Str,
3224                Pos {
3225                    offset: 11,
3226                    line: 2,
3227                    col: 10,
3228                },
3229                r#""bar""#,
3230                None,
3231            ),
3232            (
3233                Token::ValueSep,
3234                Pos {
3235                    offset: 16,
3236                    line: 2,
3237                    col: 15,
3238                },
3239                ",",
3240                None,
3241            ),
3242            (
3243                Token::Num,
3244                Pos {
3245                    offset: 17,
3246                    line: 2,
3247                    col: 16,
3248                },
3249                "1",
3250                None,
3251            ),
3252            (
3253                Token::ValueSep,
3254                Pos {
3255                    offset: 18,
3256                    line: 2,
3257                    col: 17,
3258                },
3259                ",",
3260                None,
3261            ),
3262            (
3263                Token::Num,
3264                Pos {
3265                    offset: 19,
3266                    line: 2,
3267                    col: 18,
3268                },
3269                "5e-7",
3270                None,
3271            ),
3272            (
3273                Token::ValueSep,
3274                Pos {
3275                    offset: 23,
3276                    line: 2,
3277                    col: 22,
3278                },
3279                ",",
3280                None,
3281            ),
3282            (
3283                Token::White,
3284                Pos {
3285                    offset: 24,
3286                    line: 2,
3287                    col: 23,
3288                },
3289                " ",
3290                None,
3291            ),
3292            (
3293                Token::LitFalse,
3294                Pos {
3295                    offset: 25,
3296                    line: 2,
3297                    col: 24,
3298                },
3299                "false",
3300                None,
3301            ),
3302            (
3303                Token::ValueSep,
3304                Pos {
3305                    offset: 30,
3306                    line: 2,
3307                    col: 29,
3308                },
3309                ",",
3310                None,
3311            ),
3312            (
3313                Token::White,
3314                Pos {
3315                    offset: 31,
3316                    line: 2,
3317                    col: 30,
3318                },
3319                " ",
3320                None,
3321            ),
3322            (
3323                Token::LitNull,
3324                Pos {
3325                    offset: 32,
3326                    line: 2,
3327                    col: 31,
3328                },
3329                "null",
3330                None,
3331            ),
3332            (
3333                Token::White,
3334                Pos {
3335                    offset: 36,
3336                    line: 2,
3337                    col: 35,
3338                },
3339                "  ",
3340                None,
3341            ),
3342            (
3343                Token::ValueSep,
3344                Pos {
3345                    offset: 38,
3346                    line: 2,
3347                    col: 37,
3348                },
3349                ",",
3350                None,
3351            ),
3352            (
3353                Token::LitTrue,
3354                Pos {
3355                    offset: 39,
3356                    line: 2,
3357                    col: 38,
3358                },
3359                "true",
3360                None,
3361            ),
3362            (
3363                Token::ValueSep,
3364                Pos {
3365                    offset: 43,
3366                    line: 2,
3367                    col: 42,
3368                },
3369                ",",
3370                None,
3371            ),
3372            (
3373                Token::White,
3374                Pos {
3375                    offset: 44,
3376                    line: 2,
3377                    col: 43,
3378                },
3379                " ",
3380                None,
3381            ),
3382            (
3383                Token::ObjBegin,
3384                Pos {
3385                    offset: 45,
3386                    line: 2,
3387                    col: 44,
3388                },
3389                "{",
3390                None,
3391            ),
3392            (
3393                Token::Str,
3394                Pos {
3395                    offset: 46,
3396                    line: 2,
3397                    col: 45,
3398                },
3399                r#""baz""#,
3400                None,
3401            ),
3402            (
3403                Token::NameSep,
3404                Pos {
3405                    offset: 51,
3406                    line: 2,
3407                    col: 50,
3408                },
3409                ":",
3410                None,
3411            ),
3412            (
3413                Token::Str,
3414                Pos {
3415                    offset: 52,
3416                    line: 2,
3417                    col: 51,
3418                },
3419                r#""\\\"aââbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb©¢çc\"\\""#,
3420                Some(
3421                    r#""\"aââbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb©¢çc"\""#,
3422                ),
3423            ),
3424            (
3425                Token::ValueSep,
3426                Pos {
3427                    offset: 149,
3428                    line: 2,
3429                    col: 143,
3430                },
3431                ",",
3432                None,
3433            ),
3434            (
3435                Token::Str,
3436                Pos {
3437                    offset: 150,
3438                    line: 2,
3439                    col: 144,
3440                },
3441                r#""qux""#,
3442                None,
3443            ),
3444            (
3445                Token::NameSep,
3446                Pos {
3447                    offset: 155,
3448                    line: 2,
3449                    col: 149,
3450                },
3451                ":",
3452                None,
3453            ),
3454            (
3455                Token::ArrBegin,
3456                Pos {
3457                    offset: 156,
3458                    line: 2,
3459                    col: 150,
3460                },
3461                "[",
3462                None,
3463            ),
3464            (
3465                Token::ObjBegin,
3466                Pos {
3467                    offset: 157,
3468                    line: 2,
3469                    col: 151,
3470                },
3471                "{",
3472                None,
3473            ),
3474            (
3475                Token::ObjEnd,
3476                Pos {
3477                    offset: 158,
3478                    line: 2,
3479                    col: 152,
3480                },
3481                "}",
3482                None,
3483            ),
3484            (
3485                Token::ValueSep,
3486                Pos {
3487                    offset: 159,
3488                    line: 2,
3489                    col: 153,
3490                },
3491                ",",
3492                None,
3493            ),
3494            (
3495                Token::ObjBegin,
3496                Pos {
3497                    offset: 160,
3498                    line: 2,
3499                    col: 154,
3500                },
3501                "{",
3502                None,
3503            ),
3504            (
3505                Token::ObjEnd,
3506                Pos {
3507                    offset: 161,
3508                    line: 2,
3509                    col: 155,
3510                },
3511                "}",
3512                None,
3513            ),
3514            (
3515                Token::ValueSep,
3516                Pos {
3517                    offset: 162,
3518                    line: 2,
3519                    col: 156,
3520                },
3521                ",",
3522                None,
3523            ),
3524            (
3525                Token::LitNull,
3526                Pos {
3527                    offset: 163,
3528                    line: 2,
3529                    col: 157,
3530                },
3531                "null",
3532                None,
3533            ),
3534            (
3535                Token::ArrEnd,
3536                Pos {
3537                    offset: 167,
3538                    line: 2,
3539                    col: 161,
3540                },
3541                "]",
3542                None,
3543            ),
3544            (
3545                Token::ObjEnd,
3546                Pos {
3547                    offset: 168,
3548                    line: 2,
3549                    col: 162,
3550                },
3551                "}",
3552                None,
3553            ),
3554            (
3555                Token::ArrEnd,
3556                Pos {
3557                    offset: 169,
3558                    line: 2,
3559                    col: 163,
3560                },
3561                "]",
3562                None,
3563            ),
3564            (
3565                Token::ValueSep,
3566                Pos {
3567                    offset: 170,
3568                    line: 2,
3569                    col: 164,
3570                },
3571                ",",
3572                None,
3573            ),
3574            (
3575                Token::White,
3576                Pos {
3577                    offset: 171,
3578                    line: 2,
3579                    col: 165,
3580                },
3581                "\n  ",
3582                None,
3583            ),
3584            // Line 3
3585            (
3586                Token::Str,
3587                Pos {
3588                    offset: 174,
3589                    line: 3,
3590                    col: 3,
3591                },
3592                r#""Lorem ipsum dolor sit amet, consectetur adipiscing elit.""#,
3593                None,
3594            ),
3595            (
3596                Token::White,
3597                Pos {
3598                    offset: 232,
3599                    line: 3,
3600                    col: 61,
3601                },
3602                " ",
3603                None,
3604            ),
3605            (
3606                Token::NameSep,
3607                Pos {
3608                    offset: 233,
3609                    line: 3,
3610                    col: 62,
3611                },
3612                ":",
3613                None,
3614            ),
3615            (
3616                Token::White,
3617                Pos {
3618                    offset: 234,
3619                    line: 3,
3620                    col: 63,
3621                },
3622                " ",
3623                None,
3624            ),
3625            (
3626                Token::Str,
3627                Pos {
3628                    offset: 235,
3629                    line: 3,
3630                    col: 64,
3631                },
3632                r#""Cras sed ipsum at arcu porta blandit. Nunc eu mauris lacus. Vivamus dignissim tincidunt gravida. Fusce quis neque enim. Sed ac leo neque. Praesent feugiat efficitur eros, quis venenatis urna porttitor condimentum. Mauris finibus dui non vulputate mattis. Nullam scelerisque nibh vel dui egestas luctus. Vestibulum commodo mi ex. In laoreet hendrerit fringilla.\n\nPraesent vel ex sed dolor fermentum lobortis.""#,
3633                Some(
3634                    r#""Cras sed ipsum at arcu porta blandit. Nunc eu mauris lacus. Vivamus dignissim tincidunt gravida. Fusce quis neque enim. Sed ac leo neque. Praesent feugiat efficitur eros, quis venenatis urna porttitor condimentum. Mauris finibus dui non vulputate mattis. Nullam scelerisque nibh vel dui egestas luctus. Vestibulum commodo mi ex. In laoreet hendrerit fringilla.
3635
3636Praesent vel ex sed dolor fermentum lobortis.""#,
3637                ),
3638            ),
3639            (
3640                Token::ValueSep,
3641                Pos {
3642                    offset: 646,
3643                    line: 3,
3644                    col: 475,
3645                },
3646                ",",
3647                None,
3648            ),
3649            (
3650                Token::White,
3651                Pos {
3652                    offset: 647,
3653                    line: 3,
3654                    col: 476,
3655                },
3656                "\n  ",
3657                None,
3658            ),
3659            // Line 4
3660            (
3661                Token::Str,
3662                Pos {
3663                    offset: 650,
3664                    line: 4,
3665                    col: 3,
3666                },
3667                r#""👋""#,
3668                None,
3669            ),
3670            (
3671                Token::NameSep,
3672                Pos {
3673                    offset: 656,
3674                    line: 4,
3675                    col: 6,
3676                },
3677                ":",
3678                None,
3679            ),
3680            (
3681                Token::White,
3682                Pos {
3683                    offset: 657,
3684                    line: 4,
3685                    col: 7,
3686                },
3687                "   ",
3688                None,
3689            ),
3690            (
3691                Token::ArrBegin,
3692                Pos {
3693                    offset: 660,
3694                    line: 4,
3695                    col: 10,
3696                },
3697                "[",
3698                None,
3699            ),
3700            (
3701                Token::Str,
3702                Pos {
3703                    offset: 661,
3704                    line: 4,
3705                    col: 11,
3706                },
3707                r#""🌎""#,
3708                None,
3709            ),
3710            (
3711                Token::ValueSep,
3712                Pos {
3713                    offset: 667,
3714                    line: 4,
3715                    col: 14,
3716                },
3717                ",",
3718                None,
3719            ),
3720            (
3721                Token::Str,
3722                Pos {
3723                    offset: 668,
3724                    line: 4,
3725                    col: 15,
3726                },
3727                r#""🌏""#,
3728                None,
3729            ),
3730            (
3731                Token::ValueSep,
3732                Pos {
3733                    offset: 674,
3734                    line: 4,
3735                    col: 18,
3736                },
3737                ",",
3738                None,
3739            ),
3740            (
3741                Token::White,
3742                Pos {
3743                    offset: 675,
3744                    line: 4,
3745                    col: 19,
3746                },
3747                " ",
3748                None,
3749            ),
3750            (
3751                Token::Str,
3752                Pos {
3753                    offset: 676,
3754                    line: 4,
3755                    col: 20,
3756                },
3757                r#""🌏""#,
3758                None,
3759            ),
3760            (
3761                Token::ValueSep,
3762                Pos {
3763                    offset: 682,
3764                    line: 4,
3765                    col: 23,
3766                },
3767                ",",
3768                None,
3769            ),
3770            (
3771                Token::White,
3772                Pos {
3773                    offset: 683,
3774                    line: 4,
3775                    col: 24,
3776                },
3777                " ",
3778                None,
3779            ),
3780            (
3781                Token::Str,
3782                Pos {
3783                    offset: 684,
3784                    line: 4,
3785                    col: 25,
3786                },
3787                r#""こんにちは、世界""#,
3788                None,
3789            ),
3790            (
3791                Token::ArrEnd,
3792                Pos {
3793                    offset: 710,
3794                    line: 4,
3795                    col: 35,
3796                },
3797                "]",
3798                None,
3799            ),
3800            (
3801                Token::ValueSep,
3802                Pos {
3803                    offset: 711,
3804                    line: 4,
3805                    col: 36,
3806                },
3807                ",",
3808                None,
3809            ),
3810            (
3811                Token::White,
3812                Pos {
3813                    offset: 712,
3814                    line: 4,
3815                    col: 37,
3816                },
3817                "\n  ",
3818                None,
3819            ),
3820            // Line 5
3821            (
3822                Token::Str,
3823                Pos {
3824                    offset: 715,
3825                    line: 5,
3826                    col: 3,
3827                },
3828                r#""abc\u0020123""#,
3829                Some(r#""abc 123""#),
3830            ),
3831            (
3832                Token::NameSep,
3833                Pos {
3834                    offset: 729,
3835                    line: 5,
3836                    col: 17,
3837                },
3838                ":",
3839                None,
3840            ),
3841            (
3842                Token::White,
3843                Pos {
3844                    offset: 730,
3845                    line: 5,
3846                    col: 18,
3847                },
3848                " ",
3849                None,
3850            ),
3851            (
3852                Token::ObjBegin,
3853                Pos {
3854                    offset: 731,
3855                    line: 5,
3856                    col: 19,
3857                },
3858                "{",
3859                None,
3860            ),
3861            (
3862                Token::ObjBegin,
3863                Pos {
3864                    offset: 732,
3865                    line: 5,
3866                    col: 20,
3867                },
3868                "{",
3869                None,
3870            ),
3871            (
3872                Token::ObjBegin,
3873                Pos {
3874                    offset: 733,
3875                    line: 5,
3876                    col: 21,
3877                },
3878                "{",
3879                None,
3880            ),
3881            (
3882                Token::Str,
3883                Pos {
3884                    offset: 734,
3885                    line: 5,
3886                    col: 22,
3887                },
3888                r#""inner""#,
3889                None,
3890            ),
3891            (
3892                Token::NameSep,
3893                Pos {
3894                    offset: 741,
3895                    line: 5,
3896                    col: 29,
3897                },
3898                ":",
3899                None,
3900            ),
3901            (
3902                Token::ArrBegin,
3903                Pos {
3904                    offset: 742,
3905                    line: 5,
3906                    col: 30,
3907                },
3908                "[",
3909                None,
3910            ),
3911            (
3912                Token::ArrBegin,
3913                Pos {
3914                    offset: 743,
3915                    line: 5,
3916                    col: 31,
3917                },
3918                "[",
3919                None,
3920            ),
3921            (
3922                Token::ArrBegin,
3923                Pos {
3924                    offset: 744,
3925                    line: 5,
3926                    col: 32,
3927                },
3928                "[",
3929                None,
3930            ),
3931            (
3932                Token::Num,
3933                Pos {
3934                    offset: 745,
3935                    line: 5,
3936                    col: 33,
3937                },
3938                "-1",
3939                None,
3940            ),
3941            (
3942                Token::ValueSep,
3943                Pos {
3944                    offset: 747,
3945                    line: 5,
3946                    col: 35,
3947                },
3948                ",",
3949                None,
3950            ),
3951            (
3952                Token::Num,
3953                Pos {
3954                    offset: 748,
3955                    line: 5,
3956                    col: 36,
3957                },
3958                "-2.0",
3959                None,
3960            ),
3961            (
3962                Token::ValueSep,
3963                Pos {
3964                    offset: 752,
3965                    line: 5,
3966                    col: 40,
3967                },
3968                ",",
3969                None,
3970            ),
3971            (
3972                Token::Num,
3973                Pos {
3974                    offset: 753,
3975                    line: 5,
3976                    col: 41,
3977                },
3978                "-3.00e+0",
3979                None,
3980            ),
3981            (
3982                Token::ValueSep,
3983                Pos {
3984                    offset: 761,
3985                    line: 5,
3986                    col: 49,
3987                },
3988                ",",
3989                None,
3990            ),
3991            (
3992                Token::Num,
3993                Pos {
3994                    offset: 762,
3995                    line: 5,
3996                    col: 50,
3997                },
3998                "-4E-0",
3999                None,
4000            ),
4001            (
4002                Token::ValueSep,
4003                Pos {
4004                    offset: 767,
4005                    line: 5,
4006                    col: 55,
4007                },
4008                ",",
4009                None,
4010            ),
4011            (
4012                Token::Num,
4013                Pos {
4014                    offset: 768,
4015                    line: 5,
4016                    col: 56,
4017                },
4018                "3.141592653589793238462643383279",
4019                None,
4020            ),
4021            (
4022                Token::ValueSep,
4023                Pos {
4024                    offset: 800,
4025                    line: 5,
4026                    col: 88,
4027                },
4028                ",",
4029                None,
4030            ),
4031            (
4032                Token::LitNull,
4033                Pos {
4034                    offset: 801,
4035                    line: 5,
4036                    col: 89,
4037                },
4038                "null",
4039                None,
4040            ),
4041            (
4042                Token::ArrEnd,
4043                Pos {
4044                    offset: 805,
4045                    line: 5,
4046                    col: 93,
4047                },
4048                "]",
4049                None,
4050            ),
4051            (
4052                Token::ArrEnd,
4053                Pos {
4054                    offset: 806,
4055                    line: 5,
4056                    col: 94,
4057                },
4058                "]",
4059                None,
4060            ),
4061            (
4062                Token::ArrEnd,
4063                Pos {
4064                    offset: 807,
4065                    line: 5,
4066                    col: 95,
4067                },
4068                "]",
4069                None,
4070            ),
4071            (
4072                Token::ObjEnd,
4073                Pos {
4074                    offset: 808,
4075                    line: 5,
4076                    col: 96,
4077                },
4078                "}",
4079                None,
4080            ),
4081            (
4082                Token::ObjEnd,
4083                Pos {
4084                    offset: 809,
4085                    line: 5,
4086                    col: 97,
4087                },
4088                "}",
4089                None,
4090            ),
4091            (
4092                Token::ObjEnd,
4093                Pos {
4094                    offset: 810,
4095                    line: 5,
4096                    col: 98,
4097                },
4098                "}",
4099                None,
4100            ),
4101            (
4102                Token::White,
4103                Pos {
4104                    offset: 811,
4105                    line: 5,
4106                    col: 99,
4107                },
4108                "\n",
4109                None,
4110            ),
4111            // Line 6
4112            (
4113                Token::ObjEnd,
4114                Pos {
4115                    offset: 812,
4116                    line: 6,
4117                    col: 1,
4118                },
4119                "}",
4120                None,
4121            ),
4122            (
4123                Token::Eof,
4124                Pos {
4125                    offset: 813,
4126                    line: 6,
4127                    col: 2,
4128                },
4129                "",
4130                None,
4131            ),
4132            (
4133                Token::Eof,
4134                Pos {
4135                    offset: 813,
4136                    line: 6,
4137                    col: 2,
4138                },
4139                "",
4140                None,
4141            ),
4142            (
4143                Token::Eof,
4144                Pos {
4145                    offset: 813,
4146                    line: 6,
4147                    col: 2,
4148                },
4149                "",
4150                None,
4151            ),
4152        ];
4153
4154        let mut an = FixedAnalyzer::new(JSON_TEXT.as_bytes());
4155
4156        for (i, (expect_token, expect_pos, expect_literal, expect_unescaped)) in
4157            EXPECT.iter().enumerate()
4158        {
4159            let actual_token = an.next();
4160            let actual_pos = *an.pos();
4161            let content = an.content();
4162
4163            assert_eq!(
4164                *expect_token, actual_token,
4165                "i = {i}, actual_pos = {actual_pos}, expect_pos = {expect_pos}"
4166            );
4167            assert_eq!(
4168                *expect_pos, actual_pos,
4169                "i = {i}, token = {actual_token}, content = {content}"
4170            );
4171            assert_eq!(
4172                *expect_literal,
4173                content.literal(),
4174                "i = {i}, token = {actual_token}"
4175            );
4176            if let Some(u) = expect_unescaped {
4177                assert!(
4178                    content.is_escaped(),
4179                    "i = {i}, token = {actual_token}, literal = {expect_literal:?}"
4180                );
4181                assert_eq!(*u, content.unescaped());
4182            } else {
4183                assert!(
4184                    !content.is_escaped(),
4185                    "i = {i}, token = {actual_token}, literal = {expect_literal:?}"
4186                );
4187                assert_eq!(*expect_literal, content.unescaped());
4188            }
4189        }
4190    }
4191
4192    fn inline_buf<const N: usize>(src: &[u8; N]) -> (u8, InlineBuf) {
4193        assert!(N <= INLINE_LEN);
4194        let mut dst = [0; INLINE_LEN];
4195        dst[0..N].copy_from_slice(src);
4196
4197        (u8::try_from(N).unwrap(), dst)
4198    }
4199
4200    impl From<(u8, InlineBuf)> for InnerContent<Vec<u8>> {
4201        fn from(value: (u8, InlineBuf)) -> Self {
4202            InnerContent::Inline(value.0, value.1)
4203        }
4204    }
4205}