Skip to main content

simd_json/
lib.rs

1#![deny(warnings)]
2#![cfg_attr(feature = "hints", feature(core_intrinsics))]
3#![cfg_attr(feature = "portable", feature(portable_simd))]
4#![warn(unused_extern_crates)]
5#![deny(
6    clippy::all,
7    clippy::unwrap_used,
8    clippy::unnecessary_unwrap,
9    clippy::pedantic,
10    missing_docs
11)]
12#![allow(
13    clippy::module_name_repetitions,
14    unused_unsafe, // for nightly
15)]
16#![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/README.md"))]
17
18#[cfg(feature = "serde_impl")]
19extern crate serde as serde_ext;
20
21#[cfg(feature = "serde_impl")]
22/// serde related helper functions
23pub mod serde;
24
25#[cfg(test)]
26/// serde related helper functions
27pub mod tests;
28
29#[cfg(feature = "serde_impl")]
30pub use crate::serde::{
31    from_reader, from_slice, from_str, to_string, to_string_pretty, to_vec, to_vec_pretty,
32    to_writer, to_writer_pretty,
33};
34
35/// Default trait imports;
36pub mod prelude;
37
38mod charutils;
39#[macro_use]
40mod macros;
41mod error;
42mod numberparse;
43mod safer_unchecked;
44mod stringparse;
45
46#[allow(unused_imports)]
47use macros::static_cast_u64;
48use safer_unchecked::GetSaferUnchecked;
49use stage2::StackState;
50use tape::Value;
51
52mod impls;
53
54/// Re-export of Cow
55pub mod cow;
56
57/// The maximum padding size required by any SIMD implementation
58pub(crate) const SIMDJSON_PADDING: usize = 32; // take upper limit mem::size_of::<__m256i>()
59/// It's 64 for all (Is this correct?)
60pub(crate) const SIMDINPUT_LENGTH: usize = 64;
61
62/// The default maximum nesting depth of objects and arrays, mirroring
63/// simdjson's `DEFAULT_MAX_DEPTH`.
64pub const DEFAULT_MAX_DEPTH: usize = 1024;
65
66mod stage2;
67/// simd-json JSON-DOM value
68pub mod value;
69
70use std::mem::MaybeUninit;
71use std::{alloc::dealloc, mem};
72pub use value_trait::StaticNode;
73
74pub use crate::error::{Error, ErrorType};
75#[doc(inline)]
76pub use crate::value::*;
77pub use value_trait::ValueType;
78
79/// simd-json Result type
80pub type Result<T> = std::result::Result<T, Error>;
81
82#[cfg(feature = "known-key")]
83mod known_key;
84#[cfg(feature = "known-key")]
85pub use known_key::{Error as KnownKeyError, KnownKey, KnownKeyTarget, KnownKeyTargetMut};
86
87pub use crate::tape::{Node, Tape};
88use std::alloc::{Layout, alloc, handle_alloc_error};
89use std::ops::{Deref, DerefMut};
90use std::ptr::NonNull;
91
92use simdutf8::basic::imp::ChunkedUtf8Validator;
93
94/// A struct to hold the buffers for the parser.
95pub struct Buffers {
96    string_buffer: Vec<u8>,
97    structural_indexes: Vec<u32>,
98    input_buffer: AlignedBuf,
99    stage2_stack: Vec<StackState>,
100    max_depth: usize,
101}
102
103impl Default for Buffers {
104    #[cfg_attr(not(feature = "no-inline"), inline)]
105    fn default() -> Self {
106        Self::new(128)
107    }
108}
109
110impl Buffers {
111    /// Borrow the byte offsets of every JSON structural character produced by
112    /// stage-1 SIMD scanning.  Populated as a side effect of any parse path
113    /// that takes `&mut Buffers` (`to_tape_with_buffers`,
114    /// `Deserializer::from_slice_with_buffers`, etc.).
115    ///
116    /// The returned slice is valid until the next parse call that reuses
117    /// these buffers.  Useful for downstream tooling that wants to align
118    /// its own column indices against simd-json's structural decisions
119    /// without running stage-1 a second time.
120    #[cfg_attr(not(feature = "no-inline"), inline)]
121    #[must_use]
122    pub fn structural_indexes(&self) -> &[u32] {
123        &self.structural_indexes
124    }
125
126    /// Create new buffer for input length.
127    /// If this is too small a new buffer will be allocated, if needed during parsing.
128    #[cfg_attr(not(feature = "no-inline"), inline)]
129    #[must_use]
130    pub fn new(input_len: usize) -> Self {
131        Self::with_max_depth(input_len, DEFAULT_MAX_DEPTH)
132    }
133
134    /// Create new buffer for input length with a custom maximum nesting depth.
135    /// If this is too small a new buffer will be allocated, if needed during parsing.
136    #[cfg_attr(not(feature = "no-inline"), inline)]
137    #[must_use]
138    pub fn with_max_depth(input_len: usize, max_depth: usize) -> Self {
139        // this is a heuristic, it will likely be higher but it will avoid some reallocations hopefully
140        let heuristic_index_cout = input_len / 128;
141        Self {
142            string_buffer: Vec::with_capacity(input_len + SIMDJSON_PADDING),
143            structural_indexes: Vec::with_capacity(heuristic_index_cout),
144            input_buffer: AlignedBuf::with_capacity(input_len + SIMDJSON_PADDING * 2),
145            stage2_stack: Vec::with_capacity(heuristic_index_cout),
146            max_depth,
147        }
148    }
149}
150
151/// Creates a tape from the input for later consumption
152/// # Errors
153///
154/// Will return `Err` if `s` is invalid JSON.
155#[cfg_attr(not(feature = "no-inline"), inline)]
156pub fn to_tape(s: &mut [u8]) -> Result<Tape<'_>> {
157    Deserializer::from_slice(s).map(Deserializer::into_tape)
158}
159
160/// Creates a tape from the input for later consumption
161/// # Errors
162///
163/// Will return `Err` if `s` is invalid JSON.
164#[cfg_attr(not(feature = "no-inline"), inline)]
165pub fn to_tape_with_buffers<'de>(s: &'de mut [u8], buffers: &mut Buffers) -> Result<Tape<'de>> {
166    Deserializer::from_slice_with_buffers(s, buffers).map(Deserializer::into_tape)
167}
168
169/// Fills a already existing tape from the input for later consumption
170/// # Errors
171///
172/// Will return `Err` if `s` is invalid JSON.
173#[cfg_attr(not(feature = "no-inline"), inline)]
174pub fn fill_tape<'de>(s: &'de mut [u8], buffers: &mut Buffers, tape: &mut Tape<'de>) -> Result<()> {
175    tape.0.clear();
176    Deserializer::fill_tape(s, buffers, &mut tape.0)
177}
178
179/// Padding bytes callers must provide beyond the logical input for
180/// [`fill_tape_padded`].
181pub const INPUT_PADDING: usize = SIMDINPUT_LENGTH;
182
183/// Fills an already existing tape from a caller-padded input, skipping the padded copy
184/// of the input that [`fill_tape`] makes into its internal buffer.
185///
186/// `s[..len]` is the JSON document and `s[len..]` is at least [`INPUT_PADDING`] bytes of
187/// padding with any content. Like [`fill_tape`], string unescaping writes in place within
188/// `s[..len]`. The padding is unchanged on return, so it can hold the next document of a
189/// buffer that packs several back to back.
190///
191/// With Serde enabled, the tape can deserialize directly into a typed value, including
192/// strings borrowed from the input. [`Deserializer::from_tape`] lets the caller recover
193/// the tape allocation afterward; `Tape::deserialize` consumes it instead:
194///
195/// ```
196/// # #[cfg(feature = "serde_impl")]
197/// # {
198/// use serde::Deserialize;
199/// use simd_json::{Buffers, Deserializer, INPUT_PADDING, Tape, fill_tape_padded};
200///
201/// #[derive(Deserialize)]
202/// struct Message<'a> {
203///     content: &'a str,
204/// }
205///
206/// let mut input = br#"{"content":"hello\nworld"}"#.to_vec();
207/// let len = input.len();
208/// input.resize(len + INPUT_PADDING, 0);
209/// let mut buffers = Buffers::new(len);
210/// let mut tape = Tape::null();
211/// fill_tape_padded(&mut input, len, &mut buffers, &mut tape).unwrap();
212/// let mut deserializer = Deserializer::from_tape(tape);
213/// let message = Message::deserialize(&mut deserializer).unwrap();
214/// let tape = deserializer.into_tape().reset();
215/// assert_eq!(message.content, "hello\nworld");
216/// assert!(tape.0.is_empty()); // Ready for another input, retaining its allocation.
217/// # }
218/// ```
219///
220/// # Errors
221///
222/// Will return `Err` if `s[..len]` is invalid JSON or `s` is shorter than
223/// `len + INPUT_PADDING`.
224#[cfg_attr(not(feature = "no-inline"), inline)]
225pub fn fill_tape_padded<'de>(
226    s: &'de mut [u8],
227    len: usize,
228    buffers: &mut Buffers,
229    tape: &mut Tape<'de>,
230) -> Result<()> {
231    tape.0.clear();
232    Deserializer::fill_tape_padded(s, len, buffers, &mut tape.0)
233}
234
235pub(crate) trait Stage1Parse {
236    type Utf8Validator: ChunkedUtf8Validator;
237    type SimdRepresentation;
238
239    unsafe fn new(ptr: &[u8]) -> Self;
240
241    unsafe fn compute_quote_mask(quote_bits: u64) -> u64;
242
243    unsafe fn cmp_mask_against_input(&self, m: u8) -> u64;
244
245    unsafe fn unsigned_lteq_against_input(&self, maxval: Self::SimdRepresentation) -> u64;
246
247    unsafe fn find_whitespace_and_structurals(&self, whitespace: &mut u64, structurals: &mut u64);
248
249    unsafe fn flatten_bits(base: &mut Vec<u32>, idx: u32, bits: u64);
250
251    // return both the quote mask (which is a half-open mask that covers the first
252    // quote in an unescaped quote pair and everything in the quote pair) and the
253    // quote bits, which are the simple unescaped quoted bits.
254    //
255    // We also update the prev_iter_inside_quote value to tell the next iteration
256    // whether we finished the final iteration inside a quote pair; if so, this
257    // inverts our behavior of whether we're inside quotes for the next iteration.
258    //
259    // Note that we don't do any error checking to see if we have backslash
260    // sequences outside quotes; these
261    // backslash sequences (of any length) will be detected elsewhere.
262    #[cfg_attr(not(feature = "no-inline"), inline)]
263    fn find_quote_mask_and_bits(
264        &self,
265        odd_ends: u64,
266        prev_iter_inside_quote: &mut u64,
267        quote_bits: &mut u64,
268        error_mask: &mut u64,
269    ) -> u64 {
270        unsafe {
271            *quote_bits = self.cmp_mask_against_input(b'"');
272            *quote_bits &= !odd_ends;
273            // remove from the valid quoted region the unescaped characters.
274            let mut quote_mask: u64 = Self::compute_quote_mask(*quote_bits);
275            quote_mask ^= *prev_iter_inside_quote;
276            // All Unicode characters may be placed within the
277            // quotation marks, except for the characters that MUST be escaped:
278            // quotation mark, reverse solidus, and the control characters (U+0000
279            //through U+001F).
280            // https://tools.ietf.org/html/rfc8259
281            let unescaped: u64 = self.unsigned_lteq_against_input(Self::fill_s8(0x1F));
282            *error_mask |= quote_mask & unescaped;
283            // right shift of a signed value expected to be well-defined and standard
284            // compliant as of C++20,
285            // John Regher from Utah U. says this is fine code
286            *prev_iter_inside_quote = static_cast_u64!(static_cast_i64!(quote_mask) >> 63);
287            quote_mask
288        }
289    }
290
291    // return a bitvector indicating where we have characters that end an odd-length
292    // sequence of backslashes (and thus change the behavior of the next character
293    // to follow). A even-length sequence of backslashes, and, for that matter, the
294    // largest even-length prefix of our odd-length sequence of backslashes, simply
295    // modify the behavior of the backslashes themselves.
296    // We also update the prev_iter_ends_odd_backslash reference parameter to
297    // indicate whether we end an iteration on an odd-length sequence of
298    // backslashes, which modifies our subsequent search for odd-length
299    // sequences of backslashes in an obvious way.
300    #[cfg_attr(not(feature = "no-inline"), inline)]
301    fn find_odd_backslash_sequences(&self, prev_iter_ends_odd_backslash: &mut u64) -> u64 {
302        const EVEN_BITS: u64 = 0x5555_5555_5555_5555;
303        const ODD_BITS: u64 = !EVEN_BITS;
304
305        let bs_bits: u64 = unsafe { self.cmp_mask_against_input(b'\\') };
306        let start_edges: u64 = bs_bits & !(bs_bits << 1);
307        // flip lowest if we have an odd-length run at the end of the prior
308        // iteration
309        let even_start_mask: u64 = EVEN_BITS ^ *prev_iter_ends_odd_backslash;
310        let even_starts: u64 = start_edges & even_start_mask;
311        let odd_starts: u64 = start_edges & !even_start_mask;
312        let even_carries: u64 = bs_bits.wrapping_add(even_starts);
313
314        // must record the carry-out of our odd-carries out of bit 63; this
315        // indicates whether the sense of any edge going to the next iteration
316        // should be flipped
317        let (mut odd_carries, iter_ends_odd_backslash) = bs_bits.overflowing_add(odd_starts);
318
319        odd_carries |= *prev_iter_ends_odd_backslash;
320        // push in bit zero as a potential end
321        // if we had an odd-numbered run at the
322        // end of the previous iteration
323        *prev_iter_ends_odd_backslash = u64::from(iter_ends_odd_backslash);
324        let even_carry_ends: u64 = even_carries & !bs_bits;
325        let odd_carry_ends: u64 = odd_carries & !bs_bits;
326        let even_start_odd_end: u64 = even_carry_ends & ODD_BITS;
327        let odd_start_even_end: u64 = odd_carry_ends & EVEN_BITS;
328        let odd_ends: u64 = even_start_odd_end | odd_start_even_end;
329        odd_ends
330    }
331
332    // return a updated structural bit vector with quoted contents cleared out and
333    // pseudo-structural characters added to the mask
334    // updates prev_iter_ends_pseudo_pred which tells us whether the previous
335    // iteration ended on a whitespace or a structural character (which means that
336    // the next iteration
337    // will have a pseudo-structural character at its start)
338    #[cfg_attr(not(feature = "no-inline"), inline)]
339    fn finalize_structurals(
340        mut structurals: u64,
341        whitespace: u64,
342        quote_mask: u64,
343        quote_bits: u64,
344        prev_iter_ends_pseudo_pred: &mut u64,
345    ) -> u64 {
346        // mask off anything inside quotes
347        structurals &= !quote_mask;
348        // add the real quote bits back into our bitmask as well, so we can
349        // quickly traverse the strings we've spent all this trouble gathering
350        structurals |= quote_bits;
351        // Now, establish "pseudo-structural characters". These are non-whitespace
352        // characters that are (a) outside quotes and (b) have a predecessor that's
353        // either whitespace or a structural character. This means that subsequent
354        // passes will get a chance to encounter the first character of every string
355        // of non-whitespace and, if we're parsing an atom like true/false/null or a
356        // number we can stop at the first whitespace or structural character
357        // following it.
358
359        // a qualified predecessor is something that can happen 1 position before an
360        // pseudo-structural character
361        let pseudo_pred: u64 = structurals | whitespace;
362
363        let shifted_pseudo_pred: u64 = (pseudo_pred << 1) | *prev_iter_ends_pseudo_pred;
364        *prev_iter_ends_pseudo_pred = pseudo_pred >> 63;
365        let pseudo_structurals: u64 = shifted_pseudo_pred & (!whitespace) & (!quote_mask);
366        structurals |= pseudo_structurals;
367
368        // now, we've used our close quotes all we need to. So let's switch them off
369        // they will be off in the quote mask and on in quote bits.
370        structurals &= !(quote_bits & !quote_mask);
371        structurals
372    }
373
374    unsafe fn fill_s8(n: i8) -> Self::SimdRepresentation;
375}
376
377/// Deserializer struct to deserialize a JSON
378#[derive(Debug)]
379pub struct Deserializer<'de> {
380    // Note: we use the 2nd part as both index and length since only one is ever
381    // used (array / object use len) everything else uses idx
382    pub(crate) tape: Vec<Node<'de>>,
383    idx: usize,
384}
385
386// architecture dependant parse_str
387
388#[derive(Debug, Clone, Copy)]
389pub(crate) struct SillyWrapper<'de> {
390    input: *mut u8,
391    _marker: std::marker::PhantomData<&'de ()>,
392}
393
394impl From<*mut u8> for SillyWrapper<'_> {
395    #[cfg_attr(not(feature = "no-inline"), inline)]
396    fn from(input: *mut u8) -> Self {
397        Self {
398            input,
399            _marker: std::marker::PhantomData,
400        }
401    }
402}
403
404/// Read-only stage-2 view of the (padded) input, carried as a raw pointer.
405///
406/// In the padded path ([`fill_tape_padded`]) this aliases the buffer string
407/// unescaping writes through the sibling `input` pointer. A `&[u8]` argument
408/// spanning those bytes would be UB the moment a write lands during its call
409/// (borrow-model protectors on reference arguments; LLVM marks them
410/// `noalias readonly`), so reads go through this view instead, materializing
411/// only transient slices that are dead before any write to their range.
412#[derive(Debug, Clone, Copy)]
413pub(crate) struct InputView {
414    pub(crate) ptr: *const u8,
415    pub(crate) len: usize,
416}
417
418impl InputView {
419    #[cfg_attr(not(feature = "no-inline"), inline)]
420    pub(crate) fn from_slice(s: &[u8]) -> Self {
421        Self {
422            ptr: s.as_ptr(),
423            len: s.len(),
424        }
425    }
426
427    /// Bounds-checked only in debug builds, like [`GetSaferUnchecked::get_kinda_unchecked`].
428    ///
429    /// # Safety
430    ///
431    /// `idx` must be in bounds of the view.
432    #[cfg_attr(not(feature = "no-inline"), inline)]
433    pub(crate) unsafe fn get_kinda_unchecked(self, idx: usize) -> u8 {
434        debug_assert!(idx < self.len);
435        unsafe { self.ptr.add(idx).read() }
436    }
437
438    /// Transient shared slice of `[idx..len)`.
439    ///
440    /// # Safety
441    ///
442    /// `idx <= len`, and the returned slice must be dead before the next write
443    /// through the aliasing `input` pointer touches its range.
444    #[cfg_attr(not(feature = "no-inline"), inline)]
445    pub(crate) unsafe fn tail<'a>(self, idx: usize) -> &'a [u8] {
446        debug_assert!(idx <= self.len);
447        unsafe { core::slice::from_raw_parts(self.ptr.add(idx), self.len - idx) }
448    }
449}
450
451#[cfg(all(
452    feature = "runtime-detection",
453    any(target_arch = "x86_64", target_arch = "x86"),
454))] // The runtime detection code is inspired from simdutf8's implementation
455type FnRaw = *mut ();
456#[cfg(all(
457    feature = "runtime-detection",
458    any(target_arch = "x86_64", target_arch = "x86"),
459))]
460type ParseStrFn = for<'invoke, 'de> unsafe fn(
461    SillyWrapper<'de>,
462    InputView,
463    &'invoke mut [MaybeUninit<u8>],
464    usize,
465) -> std::result::Result<&'de str, error::Error>;
466#[cfg(all(
467    feature = "runtime-detection",
468    any(target_arch = "x86_64", target_arch = "x86"),
469))]
470type FindStructuralBitsFn = unsafe fn(
471    input: &[u8],
472    structural_indexes: &mut Vec<u32>,
473) -> std::result::Result<(), ErrorType>;
474
475#[derive(Clone, Copy, Debug, PartialEq, Eq)]
476/// Supported implementations
477pub enum Implementation {
478    /// Rust native implementation
479    Native,
480    /// Rust native implementation with using [`std::simd`]
481    StdSimd,
482    /// SSE4.2 implementation
483    SSE42,
484    /// AVX2 implementation
485    AVX2,
486    /// ARM NEON implementation
487    NEON,
488    /// WEBASM SIMD128 implementation
489    SIMD128,
490}
491
492impl std::fmt::Display for Implementation {
493    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
494        match self {
495            Implementation::Native => write!(f, "Rust Native"),
496            Implementation::StdSimd => write!(f, "std::simd"),
497            Implementation::SSE42 => write!(f, "SSE42"),
498            Implementation::AVX2 => write!(f, "AVX2"),
499            Implementation::NEON => write!(f, "NEON"),
500            Implementation::SIMD128 => write!(f, "SIMD128"),
501        }
502    }
503}
504
505impl Deserializer<'_> {
506    /// returns the algorithm / architecture used by the deserializer
507    #[cfg(all(
508        feature = "runtime-detection",
509        any(target_arch = "x86_64", target_arch = "x86"),
510    ))]
511    #[must_use]
512    pub fn algorithm() -> Implementation {
513        // Same condition as the stage 1 dispatch in `find_structural_bits`.
514        if std::is_x86_feature_detected!("avx2") && std::is_x86_feature_detected!("pclmulqdq") {
515            Implementation::AVX2
516        } else if std::is_x86_feature_detected!("sse4.2") {
517            Implementation::SSE42
518        } else {
519            #[cfg(feature = "portable")]
520            let r = Implementation::StdSimd;
521            #[cfg(not(feature = "portable"))]
522            let r = Implementation::Native;
523            r
524        }
525    }
526    #[cfg(not(any(
527        all(
528            feature = "runtime-detection",
529            any(target_arch = "x86_64", target_arch = "x86")
530        ),
531        feature = "portable",
532        target_feature = "avx2",
533        target_feature = "sse4.2",
534        target_feature = "simd128",
535        target_arch = "aarch64",
536    )))]
537    /// returns the algorithm / architecture used by the deserializer
538    #[must_use]
539    pub fn algorithm() -> Implementation {
540        Implementation::Native
541    }
542    #[cfg(all(feature = "portable", not(feature = "runtime-detection")))]
543    /// returns the algorithm / architecture used by the deserializer
544    #[must_use]
545    pub fn algorithm() -> Implementation {
546        Implementation::StdSimd
547    }
548
549    #[cfg(all(
550        target_feature = "avx2",
551        not(feature = "portable"),
552        not(feature = "runtime-detection"),
553    ))]
554    /// returns the algorithm / architecture used by the deserializer
555    #[must_use]
556    pub fn algorithm() -> Implementation {
557        Implementation::AVX2
558    }
559
560    #[cfg(all(
561        target_feature = "sse4.2",
562        not(target_feature = "avx2"),
563        not(feature = "runtime-detection"),
564        not(feature = "portable"),
565    ))]
566    /// returns the algorithm / architecture used by the deserializer
567    #[must_use]
568    pub fn algorithm() -> Implementation {
569        Implementation::SSE42
570    }
571
572    #[cfg(all(target_arch = "aarch64", not(feature = "portable")))]
573    /// returns the algorithm / architecture used by the deserializer
574    #[must_use]
575    pub fn algorithm() -> Implementation {
576        Implementation::NEON
577    }
578
579    #[cfg(all(target_feature = "simd128", not(feature = "portable")))]
580    /// returns the algorithm / architecture used by the deserializer
581    #[must_use]
582    pub fn algorithm() -> Implementation {
583        Implementation::SIMD128
584    }
585}
586
587impl<'de> Deserializer<'de> {
588    /// Resolves the fastest available `parse_str` implementation once; callers
589    /// (stage 2) hoist this out of the per-string hot path so each JSON string
590    /// costs a plain indirect call instead of detection + dispatch (T6).
591    #[cfg_attr(not(feature = "no-inline"), inline)]
592    #[cfg(all(
593        feature = "runtime-detection",
594        any(target_arch = "x86_64", target_arch = "x86"),
595    ))]
596    pub(crate) fn parse_str_fn() -> ParseStrFn {
597        if std::is_x86_feature_detected!("avx2") {
598            impls::avx2::parse_str
599        } else if std::is_x86_feature_detected!("sse4.2") {
600            impls::sse42::parse_str
601        } else {
602            #[cfg(feature = "portable")]
603            let r = impls::portable::parse_str;
604            #[cfg(not(feature = "portable"))]
605            let r = impls::native::parse_str;
606            r
607        }
608    }
609
610    #[cfg_attr(not(feature = "no-inline"), inline)]
611    #[cfg(all(
612        feature = "runtime-detection",
613        any(target_arch = "x86_64", target_arch = "x86"),
614    ))]
615    // stage 2 uses `parse_str_fn()` directly (resolved once per document);
616    // this remains for tests and external-ish callers.
617    #[allow(dead_code)]
618    pub(crate) unsafe fn parse_str_<'invoke>(
619        input: *mut u8,
620        data: InputView,
621        buffer: &'invoke mut [MaybeUninit<u8>],
622        idx: usize,
623    ) -> Result<&'de str>
624    where
625        'de: 'invoke,
626    {
627        let input: SillyWrapper<'de> = SillyWrapper::from(input);
628        unsafe { (Self::parse_str_fn())(input, data, buffer, idx) }
629    }
630    #[cfg_attr(not(feature = "no-inline"), inline)]
631    #[cfg(not(any(
632        all(
633            feature = "runtime-detection",
634            any(target_arch = "x86_64", target_arch = "x86")
635        ),
636        feature = "portable",
637        target_feature = "avx2",
638        target_feature = "sse4.2",
639        target_feature = "simd128",
640        target_arch = "aarch64",
641    )))]
642    pub(crate) unsafe fn parse_str_<'invoke>(
643        input: *mut u8,
644        data: InputView,
645        buffer: &'invoke mut [MaybeUninit<u8>],
646        idx: usize,
647    ) -> Result<&'de str>
648    where
649        'de: 'invoke,
650    {
651        let input: SillyWrapper<'de> = SillyWrapper::from(input);
652        unsafe { impls::native::parse_str(input, data, buffer, idx) }
653    }
654    #[cfg_attr(not(feature = "no-inline"), inline)]
655    #[cfg(all(feature = "portable", not(feature = "runtime-detection")))]
656    pub(crate) unsafe fn parse_str_<'invoke>(
657        input: *mut u8,
658        data: InputView,
659        buffer: &'invoke mut [MaybeUninit<u8>],
660        idx: usize,
661    ) -> Result<&'de str>
662    where
663        'de: 'invoke,
664    {
665        let input: SillyWrapper<'de> = SillyWrapper::from(input);
666        impls::portable::parse_str(input, data, buffer, idx)
667    }
668
669    #[cfg_attr(not(feature = "no-inline"), inline)]
670    #[cfg(all(
671        target_feature = "avx2",
672        not(feature = "portable"),
673        not(feature = "runtime-detection"),
674    ))]
675    pub(crate) unsafe fn parse_str_<'invoke>(
676        input: *mut u8,
677        data: InputView,
678        buffer: &'invoke mut [MaybeUninit<u8>],
679        idx: usize,
680    ) -> Result<&'de str> {
681        let input: SillyWrapper<'de> = SillyWrapper::from(input);
682        unsafe { impls::avx2::parse_str(input, data, buffer, idx) }
683    }
684
685    #[cfg_attr(not(feature = "no-inline"), inline)]
686    #[cfg(all(
687        target_feature = "sse4.2",
688        not(target_feature = "avx2"),
689        not(feature = "runtime-detection"),
690        not(feature = "portable"),
691    ))]
692    pub(crate) unsafe fn parse_str_<'invoke>(
693        input: *mut u8,
694        data: InputView,
695        buffer: &'invoke mut [MaybeUninit<u8>],
696        idx: usize,
697    ) -> Result<&'de str> {
698        let input: SillyWrapper<'de> = SillyWrapper::from(input);
699        unsafe { impls::sse42::parse_str(input, data, buffer, idx) }
700    }
701
702    #[cfg_attr(not(feature = "no-inline"), inline)]
703    #[cfg(all(target_arch = "aarch64", not(feature = "portable")))]
704    pub(crate) unsafe fn parse_str_<'invoke>(
705        input: *mut u8,
706        data: InputView,
707        buffer: &'invoke mut [MaybeUninit<u8>],
708        idx: usize,
709    ) -> Result<&'de str> {
710        let input: SillyWrapper = SillyWrapper::from(input);
711        impls::neon::parse_str(input, data, buffer, idx)
712    }
713    #[cfg_attr(not(feature = "no-inline"), inline)]
714    #[cfg(all(target_feature = "simd128", not(feature = "portable")))]
715    pub(crate) unsafe fn parse_str_<'invoke>(
716        input: *mut u8,
717        data: InputView,
718        buffer: &'invoke mut [MaybeUninit<u8>],
719        idx: usize,
720    ) -> Result<&'de str> {
721        let input: SillyWrapper<'de> = SillyWrapper::from(input);
722        impls::simd128::parse_str(input, data, buffer, idx)
723    }
724}
725
726/// architecture dependant `find_structural_bits`
727impl Deserializer<'_> {
728    #[cfg_attr(not(feature = "no-inline"), inline)]
729    /// Native fallback that pre-validates UTF-8 before finding structural bits,
730    /// since the native `ChunkedUtf8ValidatorImp` is a no-op.
731    #[cfg(all(
732        feature = "runtime-detection",
733        any(target_arch = "x86_64", target_arch = "x86"),
734        not(feature = "portable"),
735    ))]
736    pub(crate) unsafe fn find_structural_bits_native(
737        input: &[u8],
738        structural_indexes: &mut Vec<u32>,
739    ) -> std::result::Result<(), ErrorType> {
740        match core::str::from_utf8(input) {
741            Ok(_) => (),
742            Err(_) => return Err(ErrorType::InvalidUtf8),
743        }
744        unsafe {
745            Self::_find_structural_bits::<impls::native::SimdInput>(input, structural_indexes)
746        }
747    }
748
749    #[cfg_attr(not(feature = "no-inline"), inline)]
750    #[cfg(all(
751        feature = "runtime-detection",
752        any(target_arch = "x86_64", target_arch = "x86"),
753    ))]
754    pub(crate) unsafe fn find_structural_bits(
755        input: &[u8],
756        structural_indexes: &mut Vec<u32>,
757    ) -> std::result::Result<(), ErrorType> {
758        unsafe {
759            use std::sync::atomic::{AtomicPtr, Ordering};
760
761            static FN: AtomicPtr<()> = AtomicPtr::new(get_fastest as FnRaw);
762
763            // The wrappers below carry the ISA's `target_feature` so that LLVM can inline
764            // the `#[target_feature]`-annotated SIMD primitives into the stage-1 loop;
765            // without them every primitive stays an outlined call per 64-byte block.
766            #[target_feature(enable = "avx2", enable = "pclmulqdq")]
767            unsafe fn find_structural_bits_avx2(
768                input: &[u8],
769                structural_indexes: &mut Vec<u32>,
770            ) -> core::result::Result<(), error::ErrorType> {
771                unsafe {
772                    Deserializer::_find_structural_bits::<impls::avx2::SimdInput>(
773                        input,
774                        structural_indexes,
775                    )
776                }
777            }
778
779            #[target_feature(enable = "sse4.2")]
780            unsafe fn find_structural_bits_sse42(
781                input: &[u8],
782                structural_indexes: &mut Vec<u32>,
783            ) -> core::result::Result<(), error::ErrorType> {
784                unsafe {
785                    Deserializer::_find_structural_bits::<impls::sse42::SimdInput>(
786                        input,
787                        structural_indexes,
788                    )
789                }
790            }
791
792            #[cfg_attr(not(feature = "no-inline"), inline)]
793            fn get_fastest_available_implementation() -> FindStructuralBitsFn {
794                if std::is_x86_feature_detected!("avx2")
795                    && std::is_x86_feature_detected!("pclmulqdq")
796                {
797                    find_structural_bits_avx2
798                } else if std::is_x86_feature_detected!("sse4.2") {
799                    find_structural_bits_sse42
800                } else {
801                    #[cfg(feature = "portable")]
802                    let r = Deserializer::_find_structural_bits::<impls::portable::SimdInput>;
803                    #[cfg(not(feature = "portable"))]
804                    let r = Deserializer::find_structural_bits_native;
805                    r
806                }
807            }
808
809            #[cfg_attr(not(feature = "no-inline"), inline)]
810            unsafe fn get_fastest(
811                input: &[u8],
812                structural_indexes: &mut Vec<u32>,
813            ) -> core::result::Result<(), error::ErrorType> {
814                unsafe {
815                    let fun = get_fastest_available_implementation();
816                    FN.store(fun as FnRaw, Ordering::Relaxed);
817                    (fun)(input, structural_indexes)
818                }
819            }
820
821            let fun = FN.load(Ordering::Relaxed);
822            mem::transmute::<FnRaw, FindStructuralBitsFn>(fun)(input, structural_indexes)
823        }
824    }
825
826    #[cfg(not(any(
827        all(
828            feature = "runtime-detection",
829            any(target_arch = "x86_64", target_arch = "x86")
830        ),
831        feature = "portable",
832        target_feature = "avx2",
833        target_feature = "sse4.2",
834        target_feature = "simd128",
835        target_arch = "aarch64",
836    )))]
837    #[cfg_attr(not(feature = "no-inline"), inline)]
838    pub(crate) unsafe fn find_structural_bits(
839        input: &[u8],
840        structural_indexes: &mut Vec<u32>,
841    ) -> std::result::Result<(), ErrorType> {
842        // This is a nasty hack, we don't have a chunked implementation for native rust
843        // so we validate UTF8 ahead of time
844        match core::str::from_utf8(input) {
845            Ok(_) => (),
846            Err(_) => return Err(ErrorType::InvalidUtf8),
847        }
848        #[cfg(not(feature = "portable"))]
849        unsafe {
850            Self::_find_structural_bits::<impls::native::SimdInput>(input, structural_indexes)
851        }
852    }
853
854    #[cfg(all(feature = "portable", not(feature = "runtime-detection")))]
855    #[cfg_attr(not(feature = "no-inline"), inline)]
856    pub(crate) unsafe fn find_structural_bits(
857        input: &[u8],
858        structural_indexes: &mut Vec<u32>,
859    ) -> std::result::Result<(), ErrorType> {
860        unsafe {
861            Self::_find_structural_bits::<impls::portable::SimdInput>(input, structural_indexes)
862        }
863    }
864
865    #[cfg(all(
866        target_feature = "avx2",
867        not(feature = "portable"),
868        not(feature = "runtime-detection"),
869    ))]
870    #[cfg_attr(not(feature = "no-inline"), inline)]
871    pub(crate) unsafe fn find_structural_bits(
872        input: &[u8],
873        structural_indexes: &mut Vec<u32>,
874    ) -> std::result::Result<(), ErrorType> {
875        unsafe { Self::_find_structural_bits::<impls::avx2::SimdInput>(input, structural_indexes) }
876    }
877
878    #[cfg(all(
879        target_feature = "sse4.2",
880        not(target_feature = "avx2"),
881        not(feature = "runtime-detection"),
882        not(feature = "portable"),
883    ))]
884    #[cfg_attr(not(feature = "no-inline"), inline)]
885    pub(crate) unsafe fn find_structural_bits(
886        input: &[u8],
887        structural_indexes: &mut Vec<u32>,
888    ) -> std::result::Result<(), ErrorType> {
889        unsafe { Self::_find_structural_bits::<impls::sse42::SimdInput>(input, structural_indexes) }
890    }
891
892    #[cfg(all(target_arch = "aarch64", not(feature = "portable")))]
893    #[cfg_attr(not(feature = "no-inline"), inline)]
894    pub(crate) unsafe fn find_structural_bits(
895        input: &[u8],
896        structural_indexes: &mut Vec<u32>,
897    ) -> std::result::Result<(), ErrorType> {
898        unsafe { Self::_find_structural_bits::<impls::neon::SimdInput>(input, structural_indexes) }
899    }
900
901    #[cfg(all(target_feature = "simd128", not(feature = "portable")))]
902    #[cfg_attr(not(feature = "no-inline"), inline)]
903    pub(crate) unsafe fn find_structural_bits(
904        input: &[u8],
905        structural_indexes: &mut Vec<u32>,
906    ) -> std::result::Result<(), ErrorType> {
907        unsafe {
908            Self::_find_structural_bits::<impls::simd128::SimdInput>(input, structural_indexes)
909        }
910    }
911}
912
913impl<'de> Deserializer<'de> {
914    /// Creates a deserializer from an existing tape without copying or reparsing it.
915    /// The allocation can be recovered with [`Self::into_tape`] after deserialization.
916    #[must_use]
917    pub fn from_tape(tape: Tape<'de>) -> Self {
918        Self {
919            tape: tape.0,
920            idx: 0,
921        }
922    }
923
924    /// Extracts the tape from the Deserializer
925    #[must_use]
926    pub fn into_tape(self) -> Tape<'de> {
927        Tape(self.tape)
928    }
929
930    /// Gives a `Value` view of the tape in the Deserializer
931    #[must_use]
932    pub fn as_value(&self) -> Value<'_, 'de> {
933        // Skip initial zero
934        Value(&self.tape)
935    }
936
937    /// Resets the Deserializer tape index to 0
938    pub fn restart(&mut self) {
939        // Skip initial zero
940        self.idx = 0;
941    }
942
943    #[cold]
944    #[inline(never)]
945    fn error(error: ErrorType) -> Error {
946        Error::new(0, None, error)
947    }
948
949    #[cold]
950    #[inline(never)]
951    fn error_c(idx: usize, c: char, error: ErrorType) -> Error {
952        Error::new(idx, Some(c), error)
953    }
954
955    /// Creates a serializer from a mutable slice of bytes
956    ///
957    /// # Errors
958    ///
959    /// Will return `Err` if `s` is invalid JSON.
960    pub fn from_slice(input: &'de mut [u8]) -> Result<Self> {
961        let len = input.len();
962
963        let mut buffer = Buffers::new(len);
964
965        Self::from_slice_with_buffers(input, &mut buffer)
966    }
967
968    /// Fills the tape without creating a serializer, this function poses
969    /// lifetime chalanges and can be frustrating, howver when it is
970    /// usable it allows a allocation free (armotized) parsing of JSON
971    ///
972    /// # Errors
973    ///
974    /// Will return `Err` if `input` is invalid JSON.
975    #[allow(clippy::uninit_vec)]
976    #[cfg_attr(not(feature = "no-inline"), inline)]
977    fn fill_tape(
978        input: &'de mut [u8],
979        buffer: &mut Buffers,
980        tape: &mut Vec<Node<'de>>,
981    ) -> Result<()> {
982        const LOTS_OF_SPACES: [u8; SIMDINPUT_LENGTH] = [b' '; SIMDINPUT_LENGTH];
983        let len = input.len();
984        let simd_safe_len = len + SIMDINPUT_LENGTH;
985
986        if len > u32::MAX as usize {
987            return Err(Self::error(ErrorType::InputTooLarge));
988        }
989
990        buffer.string_buffer.clear();
991        buffer.string_buffer.reserve(len + SIMDJSON_PADDING);
992
993        let input_buffer = &mut buffer.input_buffer;
994        if input_buffer.capacity() < simd_safe_len {
995            *input_buffer = AlignedBuf::with_capacity(simd_safe_len);
996        }
997
998        unsafe {
999            input_buffer
1000                .as_mut_ptr()
1001                .copy_from_nonoverlapping(input.as_ptr(), len);
1002
1003            // initialize all remaining bytes
1004            // this also ensures we have whitespace to terminate the buffer
1005            input_buffer
1006                .as_mut_ptr()
1007                .add(len)
1008                .copy_from_nonoverlapping(LOTS_OF_SPACES.as_ptr(), SIMDINPUT_LENGTH);
1009
1010            // safety: all bytes are initialized
1011            input_buffer.set_len(simd_safe_len);
1012
1013            Self::find_structural_bits(input, &mut buffer.structural_indexes)
1014                .map_err(Error::generic)?;
1015        };
1016
1017        // SAFETY: the pointer spans the caller's exclusive borrow of `input`, which is
1018        // not used again; reads go through `input_buffer`, a disjoint padded copy.
1019        unsafe {
1020            Self::build_tape(
1021                input.as_mut_ptr(),
1022                InputView::from_slice(input_buffer),
1023                buffer.string_buffer.spare_capacity_mut(),
1024                &buffer.structural_indexes,
1025                &mut buffer.stage2_stack,
1026                buffer.max_depth,
1027                tape,
1028            )
1029        }
1030    }
1031
1032    #[cfg_attr(not(feature = "no-inline"), inline)]
1033    fn fill_tape_padded(
1034        input: &'de mut [u8],
1035        len: usize,
1036        buffer: &mut Buffers,
1037        tape: &mut Vec<Node<'de>>,
1038    ) -> Result<()> {
1039        if input.len().saturating_sub(len) < SIMDINPUT_LENGTH {
1040            return Err(Self::error(ErrorType::InsufficientPadding));
1041        }
1042        if len > u32::MAX as usize {
1043            return Err(Self::error(ErrorType::InputTooLarge));
1044        }
1045
1046        buffer.string_buffer.clear();
1047        buffer.string_buffer.reserve(len + SIMDJSON_PADDING);
1048
1049        // A root-level number or atom is terminated by the byte after it, which fill_tape's
1050        // copy pads with a space. The caller's byte is restored before returning.
1051        let terminator = mem::replace(&mut input[len], b' ');
1052
1053        // The caller-provided padding plays the role fill_tape's internal copy plays: a
1054        // region parse_str can over-read with SIMD loads. Unlike fill_tape, reads and
1055        // writes share this one buffer, so stage 2 reads through a raw-pointer InputView
1056        // (see its doc); no reference into the buffer is live once unescaping writes
1057        // start. The stage-1 slice below is dead before the first write.
1058        let ptr = input.as_mut_ptr();
1059        let input2 = InputView {
1060            ptr,
1061            len: input.len(),
1062        };
1063
1064        let stage1 = unsafe {
1065            let head: &[u8] = core::slice::from_raw_parts(ptr, len);
1066            Self::find_structural_bits(head, &mut buffer.structural_indexes)
1067        };
1068        let res = stage1.map_err(Error::generic).and_then(|()| unsafe {
1069            Self::build_tape(
1070                ptr,
1071                input2,
1072                buffer.string_buffer.spare_capacity_mut(),
1073                &buffer.structural_indexes,
1074                &mut buffer.stage2_stack,
1075                buffer.max_depth,
1076                tape,
1077            )
1078        });
1079        // SAFETY: `len < input.len()`, and the tape borrows only bytes before `len`.
1080        unsafe { ptr.add(len).write(terminator) };
1081        res
1082    }
1083
1084    /// Creates a serializer from a mutable slice of bytes using a temporary
1085    /// buffer for strings for them to be copied in and out if needed
1086    ///
1087    /// # Errors
1088    ///
1089    /// Will return `Err` if `s` is invalid JSON.
1090    pub fn from_slice_with_buffers(input: &'de mut [u8], buffer: &mut Buffers) -> Result<Self> {
1091        let mut tape: Vec<Node<'de>> = Vec::with_capacity(buffer.structural_indexes.len());
1092
1093        Self::fill_tape(input, buffer, &mut tape)?;
1094
1095        Ok(Self { tape, idx: 0 })
1096    }
1097
1098    #[cfg(feature = "serde_impl")]
1099    #[cfg_attr(not(feature = "no-inline"), inline)]
1100    fn skip(&mut self) {
1101        self.idx += 1;
1102    }
1103
1104    /// Same as `next()` but we pull out the check so we don't need to
1105    /// stry every time. Use this only if you know the next element exists!
1106    ///
1107    /// # Safety
1108    ///
1109    /// This function is not safe to use, it is meant for internal use
1110    /// where it's know the tape isn't finished.
1111    #[cfg_attr(not(feature = "no-inline"), inline)]
1112    pub unsafe fn next_(&mut self) -> Node<'de> {
1113        let r = *unsafe { self.tape.get_kinda_unchecked(self.idx) };
1114        self.idx += 1;
1115        r
1116    }
1117
1118    #[cfg_attr(not(feature = "no-inline"), inline)]
1119    #[allow(clippy::cast_possible_truncation)]
1120    pub(crate) unsafe fn _find_structural_bits<S: Stage1Parse>(
1121        input: &[u8],
1122        structural_indexes: &mut Vec<u32>,
1123    ) -> std::result::Result<(), ErrorType> {
1124        let len = input.len();
1125        // 8 is a heuristic number to estimate it turns out a rate of 1/8 structural characters
1126        // leads almost never to relocations.
1127        structural_indexes.clear();
1128        structural_indexes.reserve(len / 8);
1129
1130        let mut utf8_validator = unsafe { S::Utf8Validator::new() };
1131
1132        // we have padded the input out to 64 byte multiple with the remainder being
1133        // spaces
1134
1135        // persistent state across loop
1136        // does the last iteration end with an odd-length sequence of backslashes?
1137        // either 0 or 1, but a 64-bit value
1138        let mut prev_iter_ends_odd_backslash: u64 = 0;
1139        // does the previous iteration end inside a double-quote pair?
1140        let mut prev_iter_inside_quote: u64 = 0;
1141        // either all zeros or all ones
1142        // does the previous iteration end on something that is a predecessor of a
1143        // pseudo-structural character - i.e. whitespace or a structural character
1144        // effectively the very first char is considered to follow "whitespace" for
1145        // the
1146        // purposes of pseudo-structural character detection so we initialize to 1
1147        let mut prev_iter_ends_pseudo_pred: u64 = 1;
1148
1149        // structurals are persistent state across loop as we flatten them on the
1150        // subsequent iteration into our array pointed to be base_ptr.
1151        // This is harmless on the first iteration as structurals==0
1152        // and is done for performance reasons; we can hide some of the latency of the
1153        // expensive carryless multiply in the previous step with this work
1154        let mut structurals: u64 = 0;
1155
1156        let lenminus64: usize = len.saturating_sub(64);
1157        let mut idx: usize = 0;
1158        let mut error_mask: u64 = 0; // for unescaped characters within strings (ASCII code points < 0x20)
1159
1160        while idx < lenminus64 {
1161            /*
1162            #ifndef _MSC_VER
1163              __builtin_prefetch(buf + idx + 128);
1164            #endif
1165             */
1166            let chunk = unsafe { input.get_kinda_unchecked(idx..idx + 64) };
1167            unsafe { utf8_validator.update_from_chunks(chunk) };
1168
1169            let input = unsafe { S::new(chunk) };
1170            // detect odd sequences of backslashes
1171            let odd_ends: u64 =
1172                input.find_odd_backslash_sequences(&mut prev_iter_ends_odd_backslash);
1173
1174            // detect insides of quote pairs ("quote_mask") and also our quote_bits
1175            // themselves
1176            let mut quote_bits: u64 = 0;
1177            let quote_mask: u64 = input.find_quote_mask_and_bits(
1178                odd_ends,
1179                &mut prev_iter_inside_quote,
1180                &mut quote_bits,
1181                &mut error_mask,
1182            );
1183
1184            // take the previous iterations structural bits, not our current iteration,
1185            // and flatten
1186            unsafe { S::flatten_bits(structural_indexes, idx as u32, structurals) };
1187
1188            let mut whitespace: u64 = 0;
1189            unsafe { input.find_whitespace_and_structurals(&mut whitespace, &mut structurals) };
1190
1191            // fixup structurals to reflect quotes and add pseudo-structural characters
1192            structurals = S::finalize_structurals(
1193                structurals,
1194                whitespace,
1195                quote_mask,
1196                quote_bits,
1197                &mut prev_iter_ends_pseudo_pred,
1198            );
1199            idx += SIMDINPUT_LENGTH;
1200        }
1201
1202        // we use a giant copy-paste which is ugly.
1203        // but otherwise the string needs to be properly padded or else we
1204        // risk invalidating the UTF-8 checks.
1205        if idx < len {
1206            let mut tmpbuf: [u8; SIMDINPUT_LENGTH] = [0x20; SIMDINPUT_LENGTH];
1207            unsafe {
1208                tmpbuf
1209                    .as_mut_ptr()
1210                    .copy_from(input.as_ptr().add(idx), len - idx);
1211            };
1212            unsafe { utf8_validator.update_from_chunks(&tmpbuf) };
1213
1214            let input = unsafe { S::new(&tmpbuf) };
1215
1216            // detect odd sequences of backslashes
1217            let odd_ends: u64 =
1218                input.find_odd_backslash_sequences(&mut prev_iter_ends_odd_backslash);
1219
1220            // detect insides of quote pairs ("quote_mask") and also our quote_bits
1221            // themselves
1222            let mut quote_bits: u64 = 0;
1223            let quote_mask: u64 = input.find_quote_mask_and_bits(
1224                odd_ends,
1225                &mut prev_iter_inside_quote,
1226                &mut quote_bits,
1227                &mut error_mask,
1228            );
1229
1230            // take the previous iterations structural bits, not our current iteration,
1231            // and flatten
1232            unsafe { S::flatten_bits(structural_indexes, idx as u32, structurals) };
1233
1234            let mut whitespace: u64 = 0;
1235            unsafe { input.find_whitespace_and_structurals(&mut whitespace, &mut structurals) };
1236
1237            // fixup structurals to reflect quotes and add pseudo-structural characters
1238            structurals = S::finalize_structurals(
1239                structurals,
1240                whitespace,
1241                quote_mask,
1242                quote_bits,
1243                &mut prev_iter_ends_pseudo_pred,
1244            );
1245            idx += SIMDINPUT_LENGTH;
1246        }
1247        // This test isn't in upstream, for some reason the error mask is et for then.
1248        if prev_iter_inside_quote != 0 {
1249            return Err(ErrorType::Syntax);
1250        }
1251        // finally, flatten out the remaining structurals from the last iteration
1252        unsafe { S::flatten_bits(structural_indexes, idx as u32, structurals) };
1253
1254        // a valid JSON file cannot have zero structural indexes - we should have
1255        // found something (note that we compare to 1 as we always add the root!)
1256        if structural_indexes.is_empty() {
1257            return Err(ErrorType::Eof);
1258        }
1259
1260        if error_mask != 0 {
1261            return Err(ErrorType::Syntax);
1262        }
1263
1264        if unsafe { utf8_validator.finalize(None).is_err() } {
1265            Err(ErrorType::InvalidUtf8)
1266        } else {
1267            Ok(())
1268        }
1269    }
1270}
1271
1272/// SIMD aligned buffer
1273struct AlignedBuf {
1274    layout: Layout,
1275    capacity: usize,
1276    len: usize,
1277    inner: NonNull<u8>,
1278}
1279// We use allow Sync + Send here since we know u8 is sync and send
1280// we never reallocate or grow this buffer only allocate it in
1281// create then deallocate it in drop.
1282//
1283// An example of this can be found [in the official rust docs](https://doc.rust-lang.org/nomicon/vec/vec-raw.html).
1284
1285unsafe impl Send for AlignedBuf {}
1286unsafe impl Sync for AlignedBuf {}
1287impl AlignedBuf {
1288    /// Creates a new buffer that is  aligned with the simd register size
1289    #[must_use]
1290    pub fn with_capacity(capacity: usize) -> Self {
1291        if capacity == 0 {
1292            let layout = Layout::from_size_align(0, SIMDJSON_PADDING)
1293                .expect("Layout for size 0 should always be valid");
1294            return Self {
1295                layout,
1296                capacity: 0,
1297                len: 0,
1298                inner: NonNull::dangling(),
1299            };
1300        }
1301        let Ok(layout) = Layout::from_size_align(capacity, SIMDJSON_PADDING) else {
1302            Self::capacity_overflow()
1303        };
1304        if mem::size_of::<usize>() < 8 && capacity > isize::MAX as usize {
1305            Self::capacity_overflow()
1306        }
1307        unsafe {
1308            let Some(inner) = NonNull::new(alloc(layout)) else {
1309                handle_alloc_error(layout)
1310            };
1311            Self {
1312                layout,
1313                capacity,
1314                len: 0,
1315                inner,
1316            }
1317        }
1318    }
1319
1320    fn as_mut_ptr(&mut self) -> *mut u8 {
1321        self.inner.as_ptr()
1322    }
1323
1324    fn capacity_overflow() -> ! {
1325        panic!("capacity overflow");
1326    }
1327    fn capacity(&self) -> usize {
1328        self.capacity
1329    }
1330    unsafe fn set_len(&mut self, n: usize) {
1331        assert!(
1332            n <= self.capacity,
1333            "New size ({}) can not be larger then capacity ({}).",
1334            n,
1335            self.capacity
1336        );
1337        self.len = n;
1338    }
1339}
1340impl Drop for AlignedBuf {
1341    fn drop(&mut self) {
1342        if self.capacity > 0 {
1343            unsafe {
1344                dealloc(self.inner.as_ptr(), self.layout);
1345            }
1346        }
1347    }
1348}
1349
1350impl Deref for AlignedBuf {
1351    type Target = [u8];
1352
1353    fn deref(&self) -> &Self::Target {
1354        unsafe { std::slice::from_raw_parts(self.inner.as_ptr(), self.len) }
1355    }
1356}
1357
1358impl DerefMut for AlignedBuf {
1359    fn deref_mut(&mut self) -> &mut Self::Target {
1360        unsafe { std::slice::from_raw_parts_mut(self.inner.as_ptr(), self.len) }
1361    }
1362}