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
29use crate::error::InternalError;
30#[cfg(feature = "serde_impl")]
31pub use crate::serde::{
32    from_reader, from_slice, from_str, to_string, to_string_pretty, to_vec, to_vec_pretty,
33    to_writer, to_writer_pretty,
34};
35
36/// Default trait imports;
37pub mod prelude;
38
39mod charutils;
40#[macro_use]
41mod macros;
42mod error;
43mod numberparse;
44mod safer_unchecked;
45mod stringparse;
46
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
62mod stage2;
63/// simd-json JSON-DOM value
64pub mod value;
65
66use std::{alloc::dealloc, mem};
67pub use value_trait::StaticNode;
68
69pub use crate::error::{Error, ErrorType};
70#[doc(inline)]
71pub use crate::value::*;
72pub use value_trait::ValueType;
73
74/// simd-json Result type
75pub type Result<T> = std::result::Result<T, Error>;
76
77#[cfg(feature = "known-key")]
78mod known_key;
79#[cfg(feature = "known-key")]
80pub use known_key::{Error as KnownKeyError, KnownKey};
81
82pub use crate::tape::{Node, Tape};
83use std::alloc::{Layout, alloc, handle_alloc_error};
84use std::ops::{Deref, DerefMut};
85use std::ptr::NonNull;
86
87use simdutf8::basic::imp::ChunkedUtf8Validator;
88
89/// A struct to hold the buffers for the parser.
90pub struct Buffers {
91    string_buffer: Vec<u8>,
92    structural_indexes: Vec<u32>,
93    input_buffer: AlignedBuf,
94    stage2_stack: Vec<StackState>,
95}
96
97impl Default for Buffers {
98    #[cfg_attr(not(feature = "no-inline"), inline)]
99    fn default() -> Self {
100        Self::new(128)
101    }
102}
103
104impl Buffers {
105    /// Create new buffer for input length.
106    /// If this is too small a new buffer will be allocated, if needed during parsing.
107    #[cfg_attr(not(feature = "no-inline"), inline)]
108    #[must_use]
109    pub fn new(input_len: usize) -> Self {
110        // this is a heuristic, it will likely be higher but it will avoid some reallocations hopefully
111        let heuristic_index_cout = input_len / 128;
112        Self {
113            string_buffer: Vec::with_capacity(input_len + SIMDJSON_PADDING),
114            structural_indexes: Vec::with_capacity(heuristic_index_cout),
115            input_buffer: AlignedBuf::with_capacity(input_len + SIMDJSON_PADDING * 2),
116            stage2_stack: Vec::with_capacity(heuristic_index_cout),
117        }
118    }
119}
120
121/// Creates a tape from the input for later consumption
122/// # Errors
123///
124/// Will return `Err` if `s` is invalid JSON.
125#[cfg_attr(not(feature = "no-inline"), inline)]
126pub fn to_tape(s: &mut [u8]) -> Result<Tape> {
127    Deserializer::from_slice(s).map(Deserializer::into_tape)
128}
129
130/// Creates a tape from the input for later consumption
131/// # Errors
132///
133/// Will return `Err` if `s` is invalid JSON.
134#[cfg_attr(not(feature = "no-inline"), inline)]
135pub fn to_tape_with_buffers<'de>(s: &'de mut [u8], buffers: &mut Buffers) -> Result<Tape<'de>> {
136    Deserializer::from_slice_with_buffers(s, buffers).map(Deserializer::into_tape)
137}
138
139/// Fills a already existing tape from the input for later consumption
140/// # Errors
141///
142/// Will return `Err` if `s` is invalid JSON.
143#[cfg_attr(not(feature = "no-inline"), inline)]
144pub fn fill_tape<'de>(s: &'de mut [u8], buffers: &mut Buffers, tape: &mut Tape<'de>) -> Result<()> {
145    tape.0.clear();
146    Deserializer::fill_tape(s, buffers, &mut tape.0)
147}
148
149pub(crate) trait Stage1Parse {
150    type Utf8Validator: ChunkedUtf8Validator;
151    type SimdRepresentation;
152
153    unsafe fn new(ptr: &[u8]) -> Self;
154
155    unsafe fn compute_quote_mask(quote_bits: u64) -> u64;
156
157    unsafe fn cmp_mask_against_input(&self, m: u8) -> u64;
158
159    unsafe fn unsigned_lteq_against_input(&self, maxval: Self::SimdRepresentation) -> u64;
160
161    unsafe fn find_whitespace_and_structurals(&self, whitespace: &mut u64, structurals: &mut u64);
162
163    unsafe fn flatten_bits(base: &mut Vec<u32>, idx: u32, bits: u64);
164
165    // return both the quote mask (which is a half-open mask that covers the first
166    // quote in an unescaped quote pair and everything in the quote pair) and the
167    // quote bits, which are the simple unescaped quoted bits.
168    //
169    // We also update the prev_iter_inside_quote value to tell the next iteration
170    // whether we finished the final iteration inside a quote pair; if so, this
171    // inverts our behavior of whether we're inside quotes for the next iteration.
172    //
173    // Note that we don't do any error checking to see if we have backslash
174    // sequences outside quotes; these
175    // backslash sequences (of any length) will be detected elsewhere.
176    #[cfg_attr(not(feature = "no-inline"), inline)]
177    fn find_quote_mask_and_bits(
178        &self,
179        odd_ends: u64,
180        prev_iter_inside_quote: &mut u64,
181        quote_bits: &mut u64,
182        error_mask: &mut u64,
183    ) -> u64 {
184        unsafe {
185            *quote_bits = self.cmp_mask_against_input(b'"');
186            *quote_bits &= !odd_ends;
187            // remove from the valid quoted region the unescaped characters.
188            let mut quote_mask: u64 = Self::compute_quote_mask(*quote_bits);
189            quote_mask ^= *prev_iter_inside_quote;
190            // All Unicode characters may be placed within the
191            // quotation marks, except for the characters that MUST be escaped:
192            // quotation mark, reverse solidus, and the control characters (U+0000
193            //through U+001F).
194            // https://tools.ietf.org/html/rfc8259
195            let unescaped: u64 = self.unsigned_lteq_against_input(Self::fill_s8(0x1F));
196            *error_mask |= quote_mask & unescaped;
197            // right shift of a signed value expected to be well-defined and standard
198            // compliant as of C++20,
199            // John Regher from Utah U. says this is fine code
200            *prev_iter_inside_quote = static_cast_u64!(static_cast_i64!(quote_mask) >> 63);
201            quote_mask
202        }
203    }
204
205    // return a bitvector indicating where we have characters that end an odd-length
206    // sequence of backslashes (and thus change the behavior of the next character
207    // to follow). A even-length sequence of backslashes, and, for that matter, the
208    // largest even-length prefix of our odd-length sequence of backslashes, simply
209    // modify the behavior of the backslashes themselves.
210    // We also update the prev_iter_ends_odd_backslash reference parameter to
211    // indicate whether we end an iteration on an odd-length sequence of
212    // backslashes, which modifies our subsequent search for odd-length
213    // sequences of backslashes in an obvious way.
214    #[cfg_attr(not(feature = "no-inline"), inline)]
215    fn find_odd_backslash_sequences(&self, prev_iter_ends_odd_backslash: &mut u64) -> u64 {
216        const EVEN_BITS: u64 = 0x5555_5555_5555_5555;
217        const ODD_BITS: u64 = !EVEN_BITS;
218
219        let bs_bits: u64 = unsafe { self.cmp_mask_against_input(b'\\') };
220        let start_edges: u64 = bs_bits & !(bs_bits << 1);
221        // flip lowest if we have an odd-length run at the end of the prior
222        // iteration
223        let even_start_mask: u64 = EVEN_BITS ^ *prev_iter_ends_odd_backslash;
224        let even_starts: u64 = start_edges & even_start_mask;
225        let odd_starts: u64 = start_edges & !even_start_mask;
226        let even_carries: u64 = bs_bits.wrapping_add(even_starts);
227
228        // must record the carry-out of our odd-carries out of bit 63; this
229        // indicates whether the sense of any edge going to the next iteration
230        // should be flipped
231        let (mut odd_carries, iter_ends_odd_backslash) = bs_bits.overflowing_add(odd_starts);
232
233        odd_carries |= *prev_iter_ends_odd_backslash;
234        // push in bit zero as a potential end
235        // if we had an odd-numbered run at the
236        // end of the previous iteration
237        *prev_iter_ends_odd_backslash = u64::from(iter_ends_odd_backslash);
238        let even_carry_ends: u64 = even_carries & !bs_bits;
239        let odd_carry_ends: u64 = odd_carries & !bs_bits;
240        let even_start_odd_end: u64 = even_carry_ends & ODD_BITS;
241        let odd_start_even_end: u64 = odd_carry_ends & EVEN_BITS;
242        let odd_ends: u64 = even_start_odd_end | odd_start_even_end;
243        odd_ends
244    }
245
246    // return a updated structural bit vector with quoted contents cleared out and
247    // pseudo-structural characters added to the mask
248    // updates prev_iter_ends_pseudo_pred which tells us whether the previous
249    // iteration ended on a whitespace or a structural character (which means that
250    // the next iteration
251    // will have a pseudo-structural character at its start)
252    #[cfg_attr(not(feature = "no-inline"), inline)]
253    fn finalize_structurals(
254        mut structurals: u64,
255        whitespace: u64,
256        quote_mask: u64,
257        quote_bits: u64,
258        prev_iter_ends_pseudo_pred: &mut u64,
259    ) -> u64 {
260        // mask off anything inside quotes
261        structurals &= !quote_mask;
262        // add the real quote bits back into our bitmask as well, so we can
263        // quickly traverse the strings we've spent all this trouble gathering
264        structurals |= quote_bits;
265        // Now, establish "pseudo-structural characters". These are non-whitespace
266        // characters that are (a) outside quotes and (b) have a predecessor that's
267        // either whitespace or a structural character. This means that subsequent
268        // passes will get a chance to encounter the first character of every string
269        // of non-whitespace and, if we're parsing an atom like true/false/null or a
270        // number we can stop at the first whitespace or structural character
271        // following it.
272
273        // a qualified predecessor is something that can happen 1 position before an
274        // pseudo-structural character
275        let pseudo_pred: u64 = structurals | whitespace;
276
277        let shifted_pseudo_pred: u64 = (pseudo_pred << 1) | *prev_iter_ends_pseudo_pred;
278        *prev_iter_ends_pseudo_pred = pseudo_pred >> 63;
279        let pseudo_structurals: u64 = shifted_pseudo_pred & (!whitespace) & (!quote_mask);
280        structurals |= pseudo_structurals;
281
282        // now, we've used our close quotes all we need to. So let's switch them off
283        // they will be off in the quote mask and on in quote bits.
284        structurals &= !(quote_bits & !quote_mask);
285        structurals
286    }
287
288    unsafe fn fill_s8(n: i8) -> Self::SimdRepresentation;
289}
290
291/// Deserializer struct to deserialize a JSON
292#[derive(Debug)]
293pub struct Deserializer<'de> {
294    // Note: we use the 2nd part as both index and length since only one is ever
295    // used (array / object use len) everything else uses idx
296    pub(crate) tape: Vec<Node<'de>>,
297    idx: usize,
298}
299
300// architecture dependant parse_str
301
302#[derive(Debug, Clone, Copy)]
303pub(crate) struct SillyWrapper<'de> {
304    input: *mut u8,
305    _marker: std::marker::PhantomData<&'de ()>,
306}
307
308impl From<*mut u8> for SillyWrapper<'_> {
309    #[cfg_attr(not(feature = "no-inline"), inline)]
310    fn from(input: *mut u8) -> Self {
311        Self {
312            input,
313            _marker: std::marker::PhantomData,
314        }
315    }
316}
317
318#[cfg(all(
319    feature = "runtime-detection",
320    any(target_arch = "x86_64", target_arch = "x86"),
321))] // The runtime detection code is inspired from simdutf8's implementation
322type FnRaw = *mut ();
323#[cfg(all(
324    feature = "runtime-detection",
325    any(target_arch = "x86_64", target_arch = "x86"),
326))]
327type ParseStrFn = for<'invoke, 'de> unsafe fn(
328    SillyWrapper<'de>,
329    &'invoke [u8],
330    &'invoke mut [u8],
331    usize,
332) -> std::result::Result<&'de str, error::Error>;
333#[cfg(all(
334    feature = "runtime-detection",
335    any(target_arch = "x86_64", target_arch = "x86"),
336))]
337type FindStructuralBitsFn = unsafe fn(
338    input: &[u8],
339    structural_indexes: &mut Vec<u32>,
340) -> std::result::Result<(), ErrorType>;
341
342#[derive(Clone, Copy, Debug, PartialEq, Eq)]
343/// Supported implementations
344pub enum Implementation {
345    /// Rust native implementation
346    Native,
347    /// Rust native implementation with using [`std::simd`]
348    StdSimd,
349    /// SSE4.2 implementation
350    SSE42,
351    /// AVX2 implementation
352    AVX2,
353    /// ARM NEON implementation
354    NEON,
355    /// WEBASM SIMD128 implementation
356    SIMD128,
357}
358
359impl std::fmt::Display for Implementation {
360    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
361        match self {
362            Implementation::Native => write!(f, "Rust Native"),
363            Implementation::StdSimd => write!(f, "std::simd"),
364            Implementation::SSE42 => write!(f, "SSE42"),
365            Implementation::AVX2 => write!(f, "AVX2"),
366            Implementation::NEON => write!(f, "NEON"),
367            Implementation::SIMD128 => write!(f, "SIMD128"),
368        }
369    }
370}
371
372impl Deserializer<'_> {
373    /// returns the algorithm / architecture used by the deserializer
374    #[cfg(all(
375        feature = "runtime-detection",
376        any(target_arch = "x86_64", target_arch = "x86"),
377    ))]
378    #[must_use]
379    pub fn algorithm() -> Implementation {
380        if std::is_x86_feature_detected!("avx2") {
381            Implementation::AVX2
382        } else if std::is_x86_feature_detected!("sse4.2") {
383            Implementation::SSE42
384        } else {
385            #[cfg(feature = "portable")]
386            let r = Implementation::StdSimd;
387            #[cfg(not(feature = "portable"))]
388            let r = Implementation::Native;
389            r
390        }
391    }
392    #[cfg(not(any(
393        all(
394            feature = "runtime-detection",
395            any(target_arch = "x86_64", target_arch = "x86")
396        ),
397        feature = "portable",
398        target_feature = "avx2",
399        target_feature = "sse4.2",
400        target_feature = "simd128",
401        target_arch = "aarch64",
402    )))]
403    /// returns the algorithm / architecture used by the deserializer
404    #[must_use]
405    pub fn algorithm() -> Implementation {
406        Implementation::Native
407    }
408    #[cfg(all(feature = "portable", not(feature = "runtime-detection")))]
409    /// returns the algorithm / architecture used by the deserializer
410    #[must_use]
411    pub fn algorithm() -> Implementation {
412        Implementation::StdSimd
413    }
414
415    #[cfg(all(
416        target_feature = "avx2",
417        not(feature = "portable"),
418        not(feature = "runtime-detection"),
419    ))]
420    /// returns the algorithm / architecture used by the deserializer
421    #[must_use]
422    pub fn algorithm() -> Implementation {
423        Implementation::AVX2
424    }
425
426    #[cfg(all(
427        target_feature = "sse4.2",
428        not(target_feature = "avx2"),
429        not(feature = "runtime-detection"),
430        not(feature = "portable"),
431    ))]
432    /// returns the algorithm / architecture used by the deserializer
433    #[must_use]
434    pub fn algorithm() -> Implementation {
435        Implementation::SSE42
436    }
437
438    #[cfg(all(target_arch = "aarch64", not(feature = "portable")))]
439    /// returns the algorithm / architecture used by the deserializer
440    #[must_use]
441    pub fn algorithm() -> Implementation {
442        Implementation::NEON
443    }
444
445    #[cfg(all(target_feature = "simd128", not(feature = "portable")))]
446    /// returns the algorithm / architecture used by the deserializer
447    #[must_use]
448    pub fn algorithm() -> Implementation {
449        Implementation::SIMD128
450    }
451}
452
453impl<'de> Deserializer<'de> {
454    #[cfg_attr(not(feature = "no-inline"), inline)]
455    #[cfg(all(
456        feature = "runtime-detection",
457        any(target_arch = "x86_64", target_arch = "x86"),
458    ))]
459    pub(crate) unsafe fn parse_str_<'invoke>(
460        input: *mut u8,
461        data: &'invoke [u8],
462        buffer: &'invoke mut [u8],
463        idx: usize,
464    ) -> Result<&'de str>
465    where
466        'de: 'invoke,
467    {
468        unsafe {
469            use std::sync::atomic::{AtomicPtr, Ordering};
470
471            static FN: AtomicPtr<()> = AtomicPtr::new(get_fastest as FnRaw);
472
473            #[cfg_attr(not(feature = "no-inline"), inline)]
474            fn get_fastest_available_implementation() -> ParseStrFn {
475                if std::is_x86_feature_detected!("avx2") {
476                    impls::avx2::parse_str
477                } else if std::is_x86_feature_detected!("sse4.2") {
478                    impls::sse42::parse_str
479                } else {
480                    #[cfg(feature = "portable")]
481                    let r = impls::portable::parse_str;
482                    #[cfg(not(feature = "portable"))]
483                    let r = impls::native::parse_str;
484                    r
485                }
486            }
487
488            #[cfg_attr(not(feature = "no-inline"), inline)]
489            unsafe fn get_fastest<'invoke, 'de>(
490                input: SillyWrapper<'de>,
491                data: &'invoke [u8],
492                buffer: &'invoke mut [u8],
493                idx: usize,
494            ) -> core::result::Result<&'de str, error::Error>
495            where
496                'de: 'invoke,
497            {
498                unsafe {
499                    let fun = get_fastest_available_implementation();
500                    FN.store(fun as FnRaw, Ordering::Relaxed);
501                    (fun)(input, data, buffer, idx)
502                }
503            }
504
505            let input: SillyWrapper<'de> = SillyWrapper::from(input);
506            let fun = FN.load(Ordering::Relaxed);
507            mem::transmute::<FnRaw, ParseStrFn>(fun)(input, data, buffer, idx)
508        }
509    }
510    #[cfg_attr(not(feature = "no-inline"), inline)]
511    #[cfg(not(any(
512        all(
513            feature = "runtime-detection",
514            any(target_arch = "x86_64", target_arch = "x86")
515        ),
516        feature = "portable",
517        target_feature = "avx2",
518        target_feature = "sse4.2",
519        target_feature = "simd128",
520        target_arch = "aarch64",
521    )))]
522    pub(crate) unsafe fn parse_str_<'invoke>(
523        input: *mut u8,
524        data: &'invoke [u8],
525        buffer: &'invoke mut [u8],
526        idx: usize,
527    ) -> Result<&'de str>
528    where
529        'de: 'invoke,
530    {
531        let input: SillyWrapper<'de> = SillyWrapper::from(input);
532        unsafe { impls::native::parse_str(input, data, buffer, idx) }
533    }
534    #[cfg_attr(not(feature = "no-inline"), inline)]
535    #[cfg(all(feature = "portable", not(feature = "runtime-detection")))]
536    pub(crate) unsafe fn parse_str_<'invoke>(
537        input: *mut u8,
538        data: &'invoke [u8],
539        buffer: &'invoke mut [u8],
540        idx: usize,
541    ) -> Result<&'de str>
542    where
543        'de: 'invoke,
544    {
545        let input: SillyWrapper<'de> = SillyWrapper::from(input);
546        impls::portable::parse_str(input, data, buffer, idx)
547    }
548
549    #[cfg_attr(not(feature = "no-inline"), inline)]
550    #[cfg(all(
551        target_feature = "avx2",
552        not(feature = "portable"),
553        not(feature = "runtime-detection"),
554    ))]
555    pub(crate) unsafe fn parse_str_<'invoke>(
556        input: *mut u8,
557        data: &'invoke [u8],
558        buffer: &'invoke mut [u8],
559        idx: usize,
560    ) -> Result<&'de str> {
561        let input: SillyWrapper<'de> = SillyWrapper::from(input);
562        unsafe { impls::avx2::parse_str(input, data, buffer, idx) }
563    }
564
565    #[cfg_attr(not(feature = "no-inline"), inline)]
566    #[cfg(all(
567        target_feature = "sse4.2",
568        not(target_feature = "avx2"),
569        not(feature = "runtime-detection"),
570        not(feature = "portable"),
571    ))]
572    pub(crate) unsafe fn parse_str_<'invoke>(
573        input: *mut u8,
574        data: &'invoke [u8],
575        buffer: &'invoke mut [u8],
576        idx: usize,
577    ) -> Result<&'de str> {
578        let input: SillyWrapper<'de> = SillyWrapper::from(input);
579        unsafe { impls::sse42::parse_str(input, data, buffer, idx) }
580    }
581
582    #[cfg_attr(not(feature = "no-inline"), inline)]
583    #[cfg(all(target_arch = "aarch64", not(feature = "portable")))]
584    pub(crate) unsafe fn parse_str_<'invoke>(
585        input: *mut u8,
586        data: &'invoke [u8],
587        buffer: &'invoke mut [u8],
588        idx: usize,
589    ) -> Result<&'de str> {
590        let input: SillyWrapper = SillyWrapper::from(input);
591        impls::neon::parse_str(input, data, buffer, idx)
592    }
593    #[cfg_attr(not(feature = "no-inline"), inline)]
594    #[cfg(all(target_feature = "simd128", not(feature = "portable")))]
595    pub(crate) unsafe fn parse_str_<'invoke>(
596        input: *mut u8,
597        data: &'invoke [u8],
598        buffer: &'invoke mut [u8],
599        idx: usize,
600    ) -> Result<&'de str> {
601        let input: SillyWrapper<'de> = SillyWrapper::from(input);
602        impls::simd128::parse_str(input, data, buffer, idx)
603    }
604}
605
606/// architecture dependant `find_structural_bits`
607impl Deserializer<'_> {
608    #[cfg_attr(not(feature = "no-inline"), inline)]
609    #[cfg(all(
610        feature = "runtime-detection",
611        any(target_arch = "x86_64", target_arch = "x86"),
612    ))]
613    pub(crate) unsafe fn find_structural_bits(
614        input: &[u8],
615        structural_indexes: &mut Vec<u32>,
616    ) -> std::result::Result<(), ErrorType> {
617        unsafe {
618            use std::sync::atomic::{AtomicPtr, Ordering};
619
620            static FN: AtomicPtr<()> = AtomicPtr::new(get_fastest as FnRaw);
621
622            #[cfg_attr(not(feature = "no-inline"), inline)]
623            fn get_fastest_available_implementation() -> FindStructuralBitsFn {
624                if std::is_x86_feature_detected!("avx2") {
625                    Deserializer::_find_structural_bits::<impls::avx2::SimdInput>
626                } else if std::is_x86_feature_detected!("sse4.2") {
627                    Deserializer::_find_structural_bits::<impls::sse42::SimdInput>
628                } else {
629                    #[cfg(feature = "portable")]
630                    let r = Deserializer::_find_structural_bits::<impls::portable::SimdInput>;
631                    #[cfg(not(feature = "portable"))]
632                    let r = Deserializer::_find_structural_bits::<impls::native::SimdInput>;
633                    r
634                }
635            }
636
637            #[cfg_attr(not(feature = "no-inline"), inline)]
638            unsafe fn get_fastest(
639                input: &[u8],
640                structural_indexes: &mut Vec<u32>,
641            ) -> core::result::Result<(), error::ErrorType> {
642                unsafe {
643                    let fun = get_fastest_available_implementation();
644                    FN.store(fun as FnRaw, Ordering::Relaxed);
645                    (fun)(input, structural_indexes)
646                }
647            }
648
649            let fun = FN.load(Ordering::Relaxed);
650            mem::transmute::<FnRaw, FindStructuralBitsFn>(fun)(input, structural_indexes)
651        }
652    }
653
654    #[cfg(not(any(
655        all(
656            feature = "runtime-detection",
657            any(target_arch = "x86_64", target_arch = "x86")
658        ),
659        feature = "portable",
660        target_feature = "avx2",
661        target_feature = "sse4.2",
662        target_feature = "simd128",
663        target_arch = "aarch64",
664    )))]
665    #[cfg_attr(not(feature = "no-inline"), inline)]
666    pub(crate) unsafe fn find_structural_bits(
667        input: &[u8],
668        structural_indexes: &mut Vec<u32>,
669    ) -> std::result::Result<(), ErrorType> {
670        // This is a nasty hack, we don't have a chunked implementation for native rust
671        // so we validate UTF8 ahead of time
672        match core::str::from_utf8(input) {
673            Ok(_) => (),
674            Err(_) => return Err(ErrorType::InvalidUtf8),
675        };
676        #[cfg(not(feature = "portable"))]
677        unsafe {
678            Self::_find_structural_bits::<impls::native::SimdInput>(input, structural_indexes)
679        }
680    }
681
682    #[cfg(all(feature = "portable", not(feature = "runtime-detection")))]
683    #[cfg_attr(not(feature = "no-inline"), inline)]
684    pub(crate) unsafe fn find_structural_bits(
685        input: &[u8],
686        structural_indexes: &mut Vec<u32>,
687    ) -> std::result::Result<(), ErrorType> {
688        unsafe {
689            Self::_find_structural_bits::<impls::portable::SimdInput>(input, structural_indexes)
690        }
691    }
692
693    #[cfg(all(
694        target_feature = "avx2",
695        not(feature = "portable"),
696        not(feature = "runtime-detection"),
697    ))]
698    #[cfg_attr(not(feature = "no-inline"), inline)]
699    pub(crate) unsafe fn find_structural_bits(
700        input: &[u8],
701        structural_indexes: &mut Vec<u32>,
702    ) -> std::result::Result<(), ErrorType> {
703        unsafe { Self::_find_structural_bits::<impls::avx2::SimdInput>(input, structural_indexes) }
704    }
705
706    #[cfg(all(
707        target_feature = "sse4.2",
708        not(target_feature = "avx2"),
709        not(feature = "runtime-detection"),
710        not(feature = "portable"),
711    ))]
712    #[cfg_attr(not(feature = "no-inline"), inline)]
713    pub(crate) unsafe fn find_structural_bits(
714        input: &[u8],
715        structural_indexes: &mut Vec<u32>,
716    ) -> std::result::Result<(), ErrorType> {
717        unsafe { Self::_find_structural_bits::<impls::sse42::SimdInput>(input, structural_indexes) }
718    }
719
720    #[cfg(all(target_arch = "aarch64", not(feature = "portable")))]
721    #[cfg_attr(not(feature = "no-inline"), inline)]
722    pub(crate) unsafe fn find_structural_bits(
723        input: &[u8],
724        structural_indexes: &mut Vec<u32>,
725    ) -> std::result::Result<(), ErrorType> {
726        unsafe { Self::_find_structural_bits::<impls::neon::SimdInput>(input, structural_indexes) }
727    }
728
729    #[cfg(all(target_feature = "simd128", not(feature = "portable")))]
730    #[cfg_attr(not(feature = "no-inline"), inline)]
731    pub(crate) unsafe fn find_structural_bits(
732        input: &[u8],
733        structural_indexes: &mut Vec<u32>,
734    ) -> std::result::Result<(), ErrorType> {
735        unsafe {
736            Self::_find_structural_bits::<impls::simd128::SimdInput>(input, structural_indexes)
737        }
738    }
739}
740
741impl<'de> Deserializer<'de> {
742    /// Extracts the tape from the Deserializer
743    #[must_use]
744    pub fn into_tape(self) -> Tape<'de> {
745        Tape(self.tape)
746    }
747
748    /// Gives a `Value` view of the tape in the Deserializer
749    #[must_use]
750    pub fn as_value(&self) -> Value<'_, 'de> {
751        // Skip initial zero
752        Value(&self.tape)
753    }
754
755    /// Resets the Deserializer tape index to 0
756    pub fn restart(&mut self) {
757        // Skip initial zero
758        self.idx = 0;
759    }
760
761    #[cfg_attr(not(feature = "no-inline"), inline)]
762    fn error(error: ErrorType) -> Error {
763        Error::new(0, None, error)
764    }
765
766    #[cfg_attr(not(feature = "no-inline"), inline)]
767    fn error_c(idx: usize, c: char, error: ErrorType) -> Error {
768        Error::new(idx, Some(c), error)
769    }
770
771    /// Creates a serializer from a mutable slice of bytes
772    ///
773    /// # Errors
774    ///
775    /// Will return `Err` if `s` is invalid JSON.
776    pub fn from_slice(input: &'de mut [u8]) -> Result<Self> {
777        let len = input.len();
778
779        let mut buffer = Buffers::new(len);
780
781        Self::from_slice_with_buffers(input, &mut buffer)
782    }
783
784    /// Fills the tape without creating a serializer, this function poses
785    /// lifetime chalanges and can be frustrating, howver when it is
786    /// usable it allows a allocation free (armotized) parsing of JSON
787    ///
788    /// # Errors
789    ///
790    /// Will return `Err` if `input` is invalid JSON.
791    #[allow(clippy::uninit_vec)]
792    #[cfg_attr(not(feature = "no-inline"), inline)]
793    fn fill_tape(
794        input: &'de mut [u8],
795        buffer: &mut Buffers,
796        tape: &mut Vec<Node<'de>>,
797    ) -> Result<()> {
798        const LOTS_OF_ZOERS: [u8; SIMDINPUT_LENGTH] = [0; SIMDINPUT_LENGTH];
799        let len = input.len();
800        let simd_safe_len = len + SIMDINPUT_LENGTH;
801
802        if len > u32::MAX as usize {
803            return Err(Self::error(ErrorType::InputTooLarge));
804        }
805
806        buffer.string_buffer.clear();
807        buffer.string_buffer.reserve(len + SIMDJSON_PADDING);
808
809        unsafe {
810            buffer.string_buffer.set_len(len + SIMDJSON_PADDING);
811        };
812
813        let input_buffer = &mut buffer.input_buffer;
814        if input_buffer.capacity() < simd_safe_len {
815            *input_buffer = AlignedBuf::with_capacity(simd_safe_len);
816        }
817
818        unsafe {
819            input_buffer
820                .as_mut_ptr()
821                .copy_from_nonoverlapping(input.as_ptr(), len);
822
823            // initialize all remaining bytes
824            // this also ensures we have a 0 to terminate the buffer
825            input_buffer
826                .as_mut_ptr()
827                .add(len)
828                .copy_from_nonoverlapping(LOTS_OF_ZOERS.as_ptr(), SIMDINPUT_LENGTH);
829
830            // safety: all bytes are initialized
831            input_buffer.set_len(simd_safe_len);
832
833            Self::find_structural_bits(input, &mut buffer.structural_indexes)
834                .map_err(Error::generic)?;
835        };
836
837        Self::build_tape(
838            input,
839            input_buffer,
840            &mut buffer.string_buffer,
841            &buffer.structural_indexes,
842            &mut buffer.stage2_stack,
843            tape,
844        )
845    }
846
847    /// Creates a serializer from a mutable slice of bytes using a temporary
848    /// buffer for strings for them to be copied in and out if needed
849    ///
850    /// # Errors
851    ///
852    /// Will return `Err` if `s` is invalid JSON.
853    pub fn from_slice_with_buffers(input: &'de mut [u8], buffer: &mut Buffers) -> Result<Self> {
854        let mut tape: Vec<Node<'de>> = Vec::with_capacity(buffer.structural_indexes.len());
855
856        Self::fill_tape(input, buffer, &mut tape)?;
857
858        Ok(Self { tape, idx: 0 })
859    }
860
861    #[cfg(feature = "serde_impl")]
862    #[cfg_attr(not(feature = "no-inline"), inline)]
863    fn skip(&mut self) {
864        self.idx += 1;
865    }
866
867    /// Same as `next()` but we pull out the check so we don't need to
868    /// stry every time. Use this only if you know the next element exists!
869    ///
870    /// # Safety
871    ///
872    /// This function is not safe to use, it is meant for internal use
873    /// where it's know the tape isn't finished.
874    #[cfg_attr(not(feature = "no-inline"), inline)]
875    pub unsafe fn next_(&mut self) -> Node<'de> {
876        let r = *unsafe { self.tape.get_kinda_unchecked(self.idx) };
877        self.idx += 1;
878        r
879    }
880
881    #[cfg_attr(not(feature = "no-inline"), inline)]
882    #[allow(clippy::cast_possible_truncation)]
883    pub(crate) unsafe fn _find_structural_bits<S: Stage1Parse>(
884        input: &[u8],
885        structural_indexes: &mut Vec<u32>,
886    ) -> std::result::Result<(), ErrorType> {
887        let len = input.len();
888        // 8 is a heuristic number to estimate it turns out a rate of 1/8 structural characters
889        // leads almost never to relocations.
890        structural_indexes.clear();
891        structural_indexes.reserve(len / 8);
892
893        let mut utf8_validator = unsafe { S::Utf8Validator::new() };
894
895        // we have padded the input out to 64 byte multiple with the remainder being
896        // zeros
897
898        // persistent state across loop
899        // does the last iteration end with an odd-length sequence of backslashes?
900        // either 0 or 1, but a 64-bit value
901        let mut prev_iter_ends_odd_backslash: u64 = 0;
902        // does the previous iteration end inside a double-quote pair?
903        let mut prev_iter_inside_quote: u64 = 0;
904        // either all zeros or all ones
905        // does the previous iteration end on something that is a predecessor of a
906        // pseudo-structural character - i.e. whitespace or a structural character
907        // effectively the very first char is considered to follow "whitespace" for
908        // the
909        // purposes of pseudo-structural character detection so we initialize to 1
910        let mut prev_iter_ends_pseudo_pred: u64 = 1;
911
912        // structurals are persistent state across loop as we flatten them on the
913        // subsequent iteration into our array pointed to be base_ptr.
914        // This is harmless on the first iteration as structurals==0
915        // and is done for performance reasons; we can hide some of the latency of the
916        // expensive carryless multiply in the previous step with this work
917        let mut structurals: u64 = 0;
918
919        let lenminus64: usize = if len < 64 { 0 } else { len - 64 };
920        let mut idx: usize = 0;
921        let mut error_mask: u64 = 0; // for unescaped characters within strings (ASCII code points < 0x20)
922
923        while idx < lenminus64 {
924            /*
925            #ifndef _MSC_VER
926              __builtin_prefetch(buf + idx + 128);
927            #endif
928             */
929            let chunk = unsafe { input.get_kinda_unchecked(idx..idx + 64) };
930            unsafe { utf8_validator.update_from_chunks(chunk) };
931
932            let input = unsafe { S::new(chunk) };
933            // detect odd sequences of backslashes
934            let odd_ends: u64 =
935                input.find_odd_backslash_sequences(&mut prev_iter_ends_odd_backslash);
936
937            // detect insides of quote pairs ("quote_mask") and also our quote_bits
938            // themselves
939            let mut quote_bits: u64 = 0;
940            let quote_mask: u64 = input.find_quote_mask_and_bits(
941                odd_ends,
942                &mut prev_iter_inside_quote,
943                &mut quote_bits,
944                &mut error_mask,
945            );
946
947            // take the previous iterations structural bits, not our current iteration,
948            // and flatten
949            unsafe { S::flatten_bits(structural_indexes, idx as u32, structurals) };
950
951            let mut whitespace: u64 = 0;
952            unsafe { input.find_whitespace_and_structurals(&mut whitespace, &mut structurals) };
953
954            // fixup structurals to reflect quotes and add pseudo-structural characters
955            structurals = S::finalize_structurals(
956                structurals,
957                whitespace,
958                quote_mask,
959                quote_bits,
960                &mut prev_iter_ends_pseudo_pred,
961            );
962            idx += SIMDINPUT_LENGTH;
963        }
964
965        // we use a giant copy-paste which is ugly.
966        // but otherwise the string needs to be properly padded or else we
967        // risk invalidating the UTF-8 checks.
968        if idx < len {
969            let mut tmpbuf: [u8; SIMDINPUT_LENGTH] = [0x20; SIMDINPUT_LENGTH];
970            unsafe {
971                tmpbuf
972                    .as_mut_ptr()
973                    .copy_from(input.as_ptr().add(idx), len - idx);
974            };
975            unsafe { utf8_validator.update_from_chunks(&tmpbuf) };
976
977            let input = unsafe { S::new(&tmpbuf) };
978
979            // detect odd sequences of backslashes
980            let odd_ends: u64 =
981                input.find_odd_backslash_sequences(&mut prev_iter_ends_odd_backslash);
982
983            // detect insides of quote pairs ("quote_mask") and also our quote_bits
984            // themselves
985            let mut quote_bits: u64 = 0;
986            let quote_mask: u64 = input.find_quote_mask_and_bits(
987                odd_ends,
988                &mut prev_iter_inside_quote,
989                &mut quote_bits,
990                &mut error_mask,
991            );
992
993            // take the previous iterations structural bits, not our current iteration,
994            // and flatten
995            unsafe { S::flatten_bits(structural_indexes, idx as u32, structurals) };
996
997            let mut whitespace: u64 = 0;
998            unsafe { input.find_whitespace_and_structurals(&mut whitespace, &mut structurals) };
999
1000            // fixup structurals to reflect quotes and add pseudo-structural characters
1001            structurals = S::finalize_structurals(
1002                structurals,
1003                whitespace,
1004                quote_mask,
1005                quote_bits,
1006                &mut prev_iter_ends_pseudo_pred,
1007            );
1008            idx += SIMDINPUT_LENGTH;
1009        }
1010        // This test isn't in upstream, for some reason the error mask is et for then.
1011        if prev_iter_inside_quote != 0 {
1012            return Err(ErrorType::Syntax);
1013        }
1014        // finally, flatten out the remaining structurals from the last iteration
1015        unsafe { S::flatten_bits(structural_indexes, idx as u32, structurals) };
1016
1017        // a valid JSON file cannot have zero structural indexes - we should have
1018        // found something (note that we compare to 1 as we always add the root!)
1019        if structural_indexes.is_empty() {
1020            return Err(ErrorType::Eof);
1021        }
1022
1023        if error_mask != 0 {
1024            return Err(ErrorType::Syntax);
1025        }
1026
1027        if unsafe { utf8_validator.finalize(None).is_err() } {
1028            Err(ErrorType::InvalidUtf8)
1029        } else {
1030            Ok(())
1031        }
1032    }
1033}
1034
1035/// SIMD aligned buffer
1036struct AlignedBuf {
1037    layout: Layout,
1038    capacity: usize,
1039    len: usize,
1040    inner: NonNull<u8>,
1041}
1042// We use allow Sync + Send here since we know u8 is sync and send
1043// we never reallocate or grow this buffer only allocate it in
1044// create then deallocate it in drop.
1045//
1046// An example of this can be found [in the official rust docs](https://doc.rust-lang.org/nomicon/vec/vec-raw.html).
1047
1048unsafe impl Send for AlignedBuf {}
1049unsafe impl Sync for AlignedBuf {}
1050impl AlignedBuf {
1051    /// Creates a new buffer that is  aligned with the simd register size
1052    #[must_use]
1053    pub fn with_capacity(capacity: usize) -> Self {
1054        let Ok(layout) = Layout::from_size_align(capacity, SIMDJSON_PADDING) else {
1055            Self::capacity_overflow()
1056        };
1057        if mem::size_of::<usize>() < 8 && capacity > isize::MAX as usize {
1058            Self::capacity_overflow()
1059        }
1060        unsafe {
1061            let Some(inner) = NonNull::new(alloc(layout)) else {
1062                handle_alloc_error(layout)
1063            };
1064            Self {
1065                layout,
1066                capacity,
1067                len: 0,
1068                inner,
1069            }
1070        }
1071    }
1072
1073    fn as_mut_ptr(&mut self) -> *mut u8 {
1074        self.inner.as_ptr()
1075    }
1076
1077    fn capacity_overflow() -> ! {
1078        panic!("capacity overflow");
1079    }
1080    fn capacity(&self) -> usize {
1081        self.capacity
1082    }
1083    unsafe fn set_len(&mut self, n: usize) {
1084        assert!(
1085            n <= self.capacity,
1086            "New size ({}) can not be larger then capacity ({}).",
1087            n,
1088            self.capacity
1089        );
1090        self.len = n;
1091    }
1092}
1093impl Drop for AlignedBuf {
1094    fn drop(&mut self) {
1095        unsafe {
1096            dealloc(self.inner.as_ptr(), self.layout);
1097        }
1098    }
1099}
1100
1101impl Deref for AlignedBuf {
1102    type Target = [u8];
1103
1104    fn deref(&self) -> &Self::Target {
1105        unsafe { std::slice::from_raw_parts(self.inner.as_ptr(), self.len) }
1106    }
1107}
1108
1109impl DerefMut for AlignedBuf {
1110    fn deref_mut(&mut self) -> &mut Self::Target {
1111        unsafe { std::slice::from_raw_parts_mut(self.inner.as_ptr(), self.len) }
1112    }
1113}