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