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