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