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