#![deny(warnings)]
#![cfg_attr(feature = "hints", feature(core_intrinsics))]
#![cfg_attr(feature = "portable", feature(portable_simd))]
#![warn(unused_extern_crates)]
#![deny(
clippy::all,
clippy::unwrap_used,
clippy::unnecessary_unwrap,
clippy::pedantic,
missing_docs
)]
#![allow(clippy::module_name_repetitions, renamed_and_removed_lints)]
#![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/README.md"))]
#[cfg(feature = "serde_impl")]
extern crate serde as serde_ext;
#[cfg(feature = "serde_impl")]
pub mod serde;
use crate::error::InternalError;
#[cfg(feature = "serde_impl")]
pub use crate::serde::{
from_reader, from_slice, from_str, to_string, to_string_pretty, to_vec, to_vec_pretty,
to_writer, to_writer_pretty,
};
pub mod prelude;
mod charutils;
#[macro_use]
mod macros;
mod error;
mod numberparse;
mod safer_unchecked;
mod stringparse;
use safer_unchecked::GetSaferUnchecked;
use stage2::StackState;
use tape::Value;
mod impls;
pub mod cow;
pub const SIMDJSON_PADDING: usize = 32; pub const SIMDINPUT_LENGTH: usize = 64;
mod stage2;
pub mod value;
use std::{alloc::dealloc, mem};
pub use value_trait::StaticNode;
pub use crate::error::{Error, ErrorType};
#[doc(inline)]
pub use crate::value::*;
pub use value_trait::ValueType;
pub type Result<T> = std::result::Result<T, Error>;
#[cfg(feature = "known-key")]
mod known_key;
#[cfg(feature = "known-key")]
pub use known_key::{Error as KnownKeyError, KnownKey};
pub use crate::tape::{Node, Tape};
use std::alloc::{alloc, handle_alloc_error, Layout};
use std::ops::{Deref, DerefMut};
use std::ptr::NonNull;
use simdutf8::basic::imp::ChunkedUtf8Validator;
pub struct Buffers {
string_buffer: Vec<u8>,
structural_indexes: Vec<u32>,
input_buffer: AlignedBuf,
stage2_stack: Vec<StackState>,
}
impl Default for Buffers {
#[cfg_attr(not(feature = "no-inline"), inline)]
fn default() -> Self {
Self::new(128)
}
}
impl Buffers {
#[cfg_attr(not(feature = "no-inline"), inline)]
#[must_use]
pub fn new(input_len: usize) -> Self {
let heuristic_index_cout = input_len / 128;
Self {
string_buffer: Vec::with_capacity(input_len + SIMDJSON_PADDING),
structural_indexes: Vec::with_capacity(heuristic_index_cout),
input_buffer: AlignedBuf::with_capacity(input_len + SIMDJSON_PADDING * 2),
stage2_stack: Vec::with_capacity(heuristic_index_cout),
}
}
}
#[cfg_attr(not(feature = "no-inline"), inline)]
pub fn to_tape(s: &mut [u8]) -> Result<Tape> {
Deserializer::from_slice(s).map(Deserializer::into_tape)
}
#[cfg_attr(not(feature = "no-inline"), inline)]
pub fn to_tape_with_buffers<'de>(s: &'de mut [u8], buffers: &mut Buffers) -> Result<Tape<'de>> {
Deserializer::from_slice_with_buffers(s, buffers).map(Deserializer::into_tape)
}
#[cfg_attr(not(feature = "no-inline"), inline)]
pub fn fill_tape<'de>(s: &'de mut [u8], buffers: &mut Buffers, tape: &mut Tape<'de>) -> Result<()> {
tape.0.clear();
Deserializer::fill_tape(s, buffers, &mut tape.0)
}
pub(crate) trait Stage1Parse {
type Utf8Validator: ChunkedUtf8Validator;
type SimdRepresentation;
unsafe fn new(ptr: &[u8]) -> Self;
unsafe fn compute_quote_mask(quote_bits: u64) -> u64;
unsafe fn cmp_mask_against_input(&self, m: u8) -> u64;
unsafe fn unsigned_lteq_against_input(&self, maxval: Self::SimdRepresentation) -> u64;
unsafe fn find_whitespace_and_structurals(&self, whitespace: &mut u64, structurals: &mut u64);
unsafe fn flatten_bits(base: &mut Vec<u32>, idx: u32, bits: u64);
#[cfg_attr(not(feature = "no-inline"), inline)]
fn find_quote_mask_and_bits(
&self,
odd_ends: u64,
prev_iter_inside_quote: &mut u64,
quote_bits: &mut u64,
error_mask: &mut u64,
) -> u64 {
unsafe {
*quote_bits = self.cmp_mask_against_input(b'"');
*quote_bits &= !odd_ends;
let mut quote_mask: u64 = Self::compute_quote_mask(*quote_bits);
quote_mask ^= *prev_iter_inside_quote;
let unescaped: u64 = self.unsigned_lteq_against_input(Self::fill_s8(0x1F));
*error_mask |= quote_mask & unescaped;
*prev_iter_inside_quote = static_cast_u64!(static_cast_i64!(quote_mask) >> 63);
quote_mask
}
}
#[cfg_attr(not(feature = "no-inline"), inline)]
fn find_odd_backslash_sequences(&self, prev_iter_ends_odd_backslash: &mut u64) -> u64 {
const EVEN_BITS: u64 = 0x5555_5555_5555_5555;
const ODD_BITS: u64 = !EVEN_BITS;
let bs_bits: u64 = unsafe { self.cmp_mask_against_input(b'\\') };
let start_edges: u64 = bs_bits & !(bs_bits << 1);
let even_start_mask: u64 = EVEN_BITS ^ *prev_iter_ends_odd_backslash;
let even_starts: u64 = start_edges & even_start_mask;
let odd_starts: u64 = start_edges & !even_start_mask;
let even_carries: u64 = bs_bits.wrapping_add(even_starts);
let (mut odd_carries, iter_ends_odd_backslash) = bs_bits.overflowing_add(odd_starts);
odd_carries |= *prev_iter_ends_odd_backslash;
*prev_iter_ends_odd_backslash = u64::from(iter_ends_odd_backslash);
let even_carry_ends: u64 = even_carries & !bs_bits;
let odd_carry_ends: u64 = odd_carries & !bs_bits;
let even_start_odd_end: u64 = even_carry_ends & ODD_BITS;
let odd_start_even_end: u64 = odd_carry_ends & EVEN_BITS;
let odd_ends: u64 = even_start_odd_end | odd_start_even_end;
odd_ends
}
#[cfg_attr(not(feature = "no-inline"), inline)]
fn finalize_structurals(
mut structurals: u64,
whitespace: u64,
quote_mask: u64,
quote_bits: u64,
prev_iter_ends_pseudo_pred: &mut u64,
) -> u64 {
structurals &= !quote_mask;
structurals |= quote_bits;
let pseudo_pred: u64 = structurals | whitespace;
let shifted_pseudo_pred: u64 = (pseudo_pred << 1) | *prev_iter_ends_pseudo_pred;
*prev_iter_ends_pseudo_pred = pseudo_pred >> 63;
let pseudo_structurals: u64 = shifted_pseudo_pred & (!whitespace) & (!quote_mask);
structurals |= pseudo_structurals;
structurals &= !(quote_bits & !quote_mask);
structurals
}
unsafe fn fill_s8(n: i8) -> Self::SimdRepresentation;
}
#[derive(Debug)]
pub struct Deserializer<'de> {
pub(crate) tape: Vec<Node<'de>>,
idx: usize,
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct SillyWrapper<'de> {
input: *mut u8,
_marker: std::marker::PhantomData<&'de ()>,
}
impl<'de> From<*mut u8> for SillyWrapper<'de> {
#[cfg_attr(not(feature = "no-inline"), inline)]
fn from(input: *mut u8) -> Self {
Self {
input,
_marker: std::marker::PhantomData,
}
}
}
#[cfg(all(
feature = "runtime-detection",
any(target_arch = "x86_64", target_arch = "x86"),
))] type FnRaw = *mut ();
#[cfg(all(
feature = "runtime-detection",
any(target_arch = "x86_64", target_arch = "x86"),
))]
type ParseStrFn = for<'invoke, 'de> unsafe fn(
SillyWrapper<'de>,
&'invoke [u8],
&'invoke mut [u8],
usize,
) -> std::result::Result<&'de str, error::Error>;
#[cfg(all(
feature = "runtime-detection",
any(target_arch = "x86_64", target_arch = "x86"),
))]
type FindStructuralBitsFn = unsafe fn(
input: &[u8],
structural_indexes: &mut Vec<u32>,
) -> std::result::Result<(), ErrorType>;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Implementation {
Native,
StdSimd,
SSE42,
AVX2,
NEON,
SIMD128,
}
impl std::fmt::Display for Implementation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Implementation::Native => write!(f, "Rust Native"),
Implementation::StdSimd => write!(f, "std::simd"),
Implementation::SSE42 => write!(f, "SSE42"),
Implementation::AVX2 => write!(f, "AVX2"),
Implementation::NEON => write!(f, "NEON"),
Implementation::SIMD128 => write!(f, "SIMD128"),
}
}
}
impl<'de> Deserializer<'de> {
#[cfg(all(
feature = "runtime-detection",
any(target_arch = "x86_64", target_arch = "x86"),
))]
#[must_use]
pub fn algorithm() -> Implementation {
if std::is_x86_feature_detected!("avx2") {
Implementation::AVX2
} else if std::is_x86_feature_detected!("sse4.2") {
Implementation::SSE42
} else {
#[cfg(feature = "portable")]
let r = Implementation::StdSimd;
#[cfg(not(feature = "portable"))]
let r = Implementation::Native;
r
}
}
#[cfg(not(any(
all(
feature = "runtime-detection",
any(target_arch = "x86_64", target_arch = "x86")
),
feature = "portable",
target_feature = "avx2",
target_feature = "sse4.2",
target_feature = "simd128",
target_arch = "aarch64",
)))]
#[must_use]
pub fn algorithm() -> Implementation {
Implementation::Native
}
#[cfg(all(feature = "portable", not(feature = "runtime-detection")))]
#[must_use]
pub fn algorithm() -> Implementation {
Implementation::StdSimd
}
#[cfg(all(
target_feature = "avx2",
not(feature = "portable"),
not(feature = "runtime-detection"),
))]
#[must_use]
pub fn algorithm() -> Implementation {
Implementation::AVX2
}
#[cfg(all(
target_feature = "sse4.2",
not(target_feature = "avx2"),
not(feature = "runtime-detection"),
not(feature = "portable"),
))]
#[must_use]
pub fn algorithm() -> Implementation {
Implementation::SSE42
}
#[cfg(all(target_arch = "aarch64", not(feature = "portable")))]
#[must_use]
pub fn algorithm() -> Implementation {
Implementation::NEON
}
#[cfg(all(target_feature = "simd128", not(feature = "portable")))]
#[must_use]
pub fn algorithm() -> Implementation {
Implementation::SIMD128
}
}
impl<'de> Deserializer<'de> {
#[cfg_attr(not(feature = "no-inline"), inline)]
#[cfg(all(
feature = "runtime-detection",
any(target_arch = "x86_64", target_arch = "x86"),
))]
pub(crate) unsafe fn parse_str_<'invoke>(
input: *mut u8,
data: &'invoke [u8],
buffer: &'invoke mut [u8],
idx: usize,
) -> Result<&'de str>
where
'de: 'invoke,
{
use std::sync::atomic::{AtomicPtr, Ordering};
static FN: AtomicPtr<()> = AtomicPtr::new(get_fastest as FnRaw);
#[cfg_attr(not(feature = "no-inline"), inline)]
fn get_fastest_available_implementation() -> ParseStrFn {
if std::is_x86_feature_detected!("avx2") {
impls::avx2::parse_str
} else if std::is_x86_feature_detected!("sse4.2") {
impls::sse42::parse_str
} else {
#[cfg(feature = "portable")]
let r = impls::portable::parse_str;
#[cfg(not(feature = "portable"))]
let r = impls::native::parse_str;
r
}
}
#[cfg_attr(not(feature = "no-inline"), inline)]
unsafe fn get_fastest<'invoke, 'de>(
input: SillyWrapper<'de>,
data: &'invoke [u8],
buffer: &'invoke mut [u8],
idx: usize,
) -> core::result::Result<&'de str, error::Error>
where
'de: 'invoke,
{
let fun = get_fastest_available_implementation();
FN.store(fun as FnRaw, Ordering::Relaxed);
(fun)(input, data, buffer, idx)
}
let input: SillyWrapper<'de> = SillyWrapper::from(input);
let fun = FN.load(Ordering::Relaxed);
mem::transmute::<FnRaw, ParseStrFn>(fun)(input, data, buffer, idx)
}
#[cfg_attr(not(feature = "no-inline"), inline)]
#[cfg(not(any(
all(
feature = "runtime-detection",
any(target_arch = "x86_64", target_arch = "x86")
),
feature = "portable",
target_feature = "avx2",
target_feature = "sse4.2",
target_feature = "simd128",
target_arch = "aarch64",
)))]
pub(crate) unsafe fn parse_str_<'invoke>(
input: *mut u8,
data: &'invoke [u8],
buffer: &'invoke mut [u8],
idx: usize,
) -> Result<&'de str>
where
'de: 'invoke,
{
let input: SillyWrapper<'de> = SillyWrapper::from(input);
impls::native::parse_str(input, data, buffer, idx)
}
#[cfg_attr(not(feature = "no-inline"), inline)]
#[cfg(all(feature = "portable", not(feature = "runtime-detection")))]
pub(crate) unsafe fn parse_str_<'invoke>(
input: *mut u8,
data: &'invoke [u8],
buffer: &'invoke mut [u8],
idx: usize,
) -> Result<&'de str>
where
'de: 'invoke,
{
let input: SillyWrapper<'de> = SillyWrapper::from(input);
impls::portable::parse_str(input, data, buffer, idx)
}
#[cfg_attr(not(feature = "no-inline"), inline)]
#[cfg(all(
target_feature = "avx2",
not(feature = "portable"),
not(feature = "runtime-detection"),
))]
pub(crate) unsafe fn parse_str_<'invoke>(
input: *mut u8,
data: &'invoke [u8],
buffer: &'invoke mut [u8],
idx: usize,
) -> Result<&'de str> {
let input: SillyWrapper<'de> = SillyWrapper::from(input);
impls::avx2::parse_str(input, data, buffer, idx)
}
#[cfg_attr(not(feature = "no-inline"), inline)]
#[cfg(all(
target_feature = "sse4.2",
not(target_feature = "avx2"),
not(feature = "runtime-detection"),
not(feature = "portable"),
))]
pub(crate) unsafe fn parse_str_<'invoke>(
input: *mut u8,
data: &'invoke [u8],
buffer: &'invoke mut [u8],
idx: usize,
) -> Result<&'de str> {
let input: SillyWrapper<'de> = SillyWrapper::from(input);
impls::sse42::parse_str(input, data, buffer, idx)
}
#[cfg_attr(not(feature = "no-inline"), inline)]
#[cfg(all(target_arch = "aarch64", not(feature = "portable")))]
pub(crate) unsafe fn parse_str_<'invoke>(
input: *mut u8,
data: &'invoke [u8],
buffer: &'invoke mut [u8],
idx: usize,
) -> Result<&'de str> {
let input: SillyWrapper<'de> = SillyWrapper::from(input);
impls::neon::parse_str(input, data, buffer, idx)
}
#[cfg_attr(not(feature = "no-inline"), inline)]
#[cfg(all(target_feature = "simd128", not(feature = "portable")))]
pub(crate) unsafe fn parse_str_<'invoke>(
input: *mut u8,
data: &'invoke [u8],
buffer: &'invoke mut [u8],
idx: usize,
) -> Result<&'de str> {
let input: SillyWrapper<'de> = SillyWrapper::from(input);
impls::simd128::parse_str(input, data, buffer, idx)
}
}
impl<'de> Deserializer<'de> {
#[cfg_attr(not(feature = "no-inline"), inline)]
#[cfg(all(
feature = "runtime-detection",
any(target_arch = "x86_64", target_arch = "x86"),
))]
pub(crate) unsafe fn find_structural_bits(
input: &[u8],
structural_indexes: &mut Vec<u32>,
) -> std::result::Result<(), ErrorType> {
use std::sync::atomic::{AtomicPtr, Ordering};
static FN: AtomicPtr<()> = AtomicPtr::new(get_fastest as FnRaw);
#[cfg_attr(not(feature = "no-inline"), inline)]
fn get_fastest_available_implementation() -> FindStructuralBitsFn {
if std::is_x86_feature_detected!("avx2") {
Deserializer::_find_structural_bits::<impls::avx2::SimdInput>
} else if std::is_x86_feature_detected!("sse4.2") {
Deserializer::_find_structural_bits::<impls::sse42::SimdInput>
} else {
#[cfg(feature = "portable")]
let r = Deserializer::_find_structural_bits::<impls::portable::SimdInput>;
#[cfg(not(feature = "portable"))]
let r = Deserializer::_find_structural_bits::<impls::native::SimdInput>;
r
}
}
#[cfg_attr(not(feature = "no-inline"), inline)]
unsafe fn get_fastest(
input: &[u8],
structural_indexes: &mut Vec<u32>,
) -> core::result::Result<(), error::ErrorType> {
let fun = get_fastest_available_implementation();
FN.store(fun as FnRaw, Ordering::Relaxed);
(fun)(input, structural_indexes)
}
let fun = FN.load(Ordering::Relaxed);
mem::transmute::<FnRaw, FindStructuralBitsFn>(fun)(input, structural_indexes)
}
#[cfg(not(any(
all(
feature = "runtime-detection",
any(target_arch = "x86_64", target_arch = "x86")
),
feature = "portable",
target_feature = "avx2",
target_feature = "sse4.2",
target_feature = "simd128",
target_arch = "aarch64",
)))]
#[cfg_attr(not(feature = "no-inline"), inline)]
pub(crate) unsafe fn find_structural_bits(
input: &[u8],
structural_indexes: &mut Vec<u32>,
) -> std::result::Result<(), ErrorType> {
match core::str::from_utf8(input) {
Ok(_) => (),
Err(_) => return Err(ErrorType::InvalidUtf8),
};
#[cfg(not(feature = "portable"))]
Self::_find_structural_bits::<impls::native::SimdInput>(input, structural_indexes)
}
#[cfg(all(feature = "portable", not(feature = "runtime-detection")))]
#[cfg_attr(not(feature = "no-inline"), inline)]
pub(crate) unsafe fn find_structural_bits(
input: &[u8],
structural_indexes: &mut Vec<u32>,
) -> std::result::Result<(), ErrorType> {
Self::_find_structural_bits::<impls::portable::SimdInput>(input, structural_indexes)
}
#[cfg(all(
target_feature = "avx2",
not(feature = "portable"),
not(feature = "runtime-detection"),
))]
#[cfg_attr(not(feature = "no-inline"), inline)]
pub(crate) unsafe fn find_structural_bits(
input: &[u8],
structural_indexes: &mut Vec<u32>,
) -> std::result::Result<(), ErrorType> {
Self::_find_structural_bits::<impls::avx2::SimdInput>(input, structural_indexes)
}
#[cfg(all(
target_feature = "sse4.2",
not(target_feature = "avx2"),
not(feature = "runtime-detection"),
not(feature = "portable"),
))]
#[cfg_attr(not(feature = "no-inline"), inline)]
pub(crate) unsafe fn find_structural_bits(
input: &[u8],
structural_indexes: &mut Vec<u32>,
) -> std::result::Result<(), ErrorType> {
Self::_find_structural_bits::<impls::sse42::SimdInput>(input, structural_indexes)
}
#[cfg(all(target_arch = "aarch64", not(feature = "portable")))]
#[cfg_attr(not(feature = "no-inline"), inline)]
pub(crate) unsafe fn find_structural_bits(
input: &[u8],
structural_indexes: &mut Vec<u32>,
) -> std::result::Result<(), ErrorType> {
unsafe { Self::_find_structural_bits::<impls::neon::SimdInput>(input, structural_indexes) }
}
#[cfg(all(target_feature = "simd128", not(feature = "portable")))]
#[cfg_attr(not(feature = "no-inline"), inline)]
pub(crate) unsafe fn find_structural_bits(
input: &[u8],
structural_indexes: &mut Vec<u32>,
) -> std::result::Result<(), ErrorType> {
Self::_find_structural_bits::<impls::simd128::SimdInput>(input, structural_indexes)
}
}
impl<'de> Deserializer<'de> {
#[must_use]
pub fn into_tape(self) -> Tape<'de> {
Tape(self.tape)
}
#[must_use]
pub fn as_value(&self) -> Value<'_, 'de> {
Value(&self.tape)
}
pub fn restart(&mut self) {
self.idx = 0;
}
#[cfg_attr(not(feature = "no-inline"), inline)]
fn error(error: ErrorType) -> Error {
Error::new(0, None, error)
}
#[cfg_attr(not(feature = "no-inline"), inline)]
fn error_c(idx: usize, c: char, error: ErrorType) -> Error {
Error::new(idx, Some(c), error)
}
pub fn from_slice(input: &'de mut [u8]) -> Result<Self> {
let len = input.len();
let mut buffer = Buffers::new(len);
Self::from_slice_with_buffers(input, &mut buffer)
}
#[allow(clippy::uninit_vec)]
#[cfg_attr(not(feature = "no-inline"), inline)]
fn fill_tape(
input: &'de mut [u8],
buffer: &mut Buffers,
tape: &mut Vec<Node<'de>>,
) -> Result<()> {
const LOTS_OF_ZOERS: [u8; SIMDINPUT_LENGTH] = [0; SIMDINPUT_LENGTH];
let len = input.len();
let simd_safe_len = len + SIMDINPUT_LENGTH;
if len > u32::MAX as usize {
return Err(Self::error(ErrorType::InputTooLarge));
}
buffer.string_buffer.clear();
buffer.string_buffer.reserve(len + SIMDJSON_PADDING);
unsafe {
buffer.string_buffer.set_len(len + SIMDJSON_PADDING);
};
let input_buffer = &mut buffer.input_buffer;
if input_buffer.capacity() < simd_safe_len {
*input_buffer = AlignedBuf::with_capacity(simd_safe_len);
}
unsafe {
input_buffer
.as_mut_ptr()
.copy_from_nonoverlapping(input.as_ptr(), len);
input_buffer
.as_mut_ptr()
.add(len)
.copy_from_nonoverlapping(LOTS_OF_ZOERS.as_ptr(), SIMDINPUT_LENGTH);
input_buffer.set_len(simd_safe_len);
Self::find_structural_bits(input, &mut buffer.structural_indexes)
.map_err(Error::generic)?;
};
Self::build_tape(
input,
input_buffer,
&mut buffer.string_buffer,
&buffer.structural_indexes,
&mut buffer.stage2_stack,
tape,
)
}
pub fn from_slice_with_buffers(input: &'de mut [u8], buffer: &mut Buffers) -> Result<Self> {
let mut tape: Vec<Node<'de>> = Vec::with_capacity(buffer.structural_indexes.len());
Self::fill_tape(input, buffer, &mut tape)?;
Ok(Self { tape, idx: 0 })
}
#[cfg(feature = "serde_impl")]
#[cfg_attr(not(feature = "no-inline"), inline)]
fn skip(&mut self) {
self.idx += 1;
}
#[cfg_attr(not(feature = "no-inline"), inline)]
pub unsafe fn next_(&mut self) -> Node<'de> {
let r = *unsafe { self.tape.get_kinda_unchecked(self.idx) };
self.idx += 1;
r
}
#[cfg_attr(not(feature = "no-inline"), inline)]
#[allow(clippy::cast_possible_truncation)]
pub(crate) unsafe fn _find_structural_bits<S: Stage1Parse>(
input: &[u8],
structural_indexes: &mut Vec<u32>,
) -> std::result::Result<(), ErrorType> {
let len = input.len();
structural_indexes.clear();
structural_indexes.reserve(len / 8);
let mut utf8_validator = unsafe { S::Utf8Validator::new() };
let mut prev_iter_ends_odd_backslash: u64 = 0;
let mut prev_iter_inside_quote: u64 = 0;
let mut prev_iter_ends_pseudo_pred: u64 = 1;
let mut structurals: u64 = 0;
let lenminus64: usize = if len < 64 { 0 } else { len - 64 };
let mut idx: usize = 0;
let mut error_mask: u64 = 0; while idx < lenminus64 {
let chunk = unsafe { input.get_kinda_unchecked(idx..idx + 64) };
unsafe { utf8_validator.update_from_chunks(chunk) };
let input = unsafe { S::new(chunk) };
let odd_ends: u64 =
input.find_odd_backslash_sequences(&mut prev_iter_ends_odd_backslash);
let mut quote_bits: u64 = 0;
let quote_mask: u64 = input.find_quote_mask_and_bits(
odd_ends,
&mut prev_iter_inside_quote,
&mut quote_bits,
&mut error_mask,
);
unsafe { S::flatten_bits(structural_indexes, idx as u32, structurals) };
let mut whitespace: u64 = 0;
unsafe { input.find_whitespace_and_structurals(&mut whitespace, &mut structurals) };
structurals = S::finalize_structurals(
structurals,
whitespace,
quote_mask,
quote_bits,
&mut prev_iter_ends_pseudo_pred,
);
idx += SIMDINPUT_LENGTH;
}
if idx < len {
let mut tmpbuf: [u8; SIMDINPUT_LENGTH] = [0x20; SIMDINPUT_LENGTH];
unsafe {
tmpbuf
.as_mut_ptr()
.copy_from(input.as_ptr().add(idx), len - idx);
};
unsafe { utf8_validator.update_from_chunks(&tmpbuf) };
let input = unsafe { S::new(&tmpbuf) };
let odd_ends: u64 =
input.find_odd_backslash_sequences(&mut prev_iter_ends_odd_backslash);
let mut quote_bits: u64 = 0;
let quote_mask: u64 = input.find_quote_mask_and_bits(
odd_ends,
&mut prev_iter_inside_quote,
&mut quote_bits,
&mut error_mask,
);
unsafe { S::flatten_bits(structural_indexes, idx as u32, structurals) };
let mut whitespace: u64 = 0;
unsafe { input.find_whitespace_and_structurals(&mut whitespace, &mut structurals) };
structurals = S::finalize_structurals(
structurals,
whitespace,
quote_mask,
quote_bits,
&mut prev_iter_ends_pseudo_pred,
);
idx += SIMDINPUT_LENGTH;
}
if prev_iter_inside_quote != 0 {
return Err(ErrorType::Syntax);
}
unsafe { S::flatten_bits(structural_indexes, idx as u32, structurals) };
if structural_indexes.is_empty() {
return Err(ErrorType::Eof);
}
if error_mask != 0 {
return Err(ErrorType::Syntax);
}
if unsafe { utf8_validator.finalize(None).is_err() } {
Err(ErrorType::InvalidUtf8)
} else {
Ok(())
}
}
}
struct AlignedBuf {
layout: Layout,
capacity: usize,
len: usize,
inner: NonNull<u8>,
}
unsafe impl Send for AlignedBuf {}
unsafe impl Sync for AlignedBuf {}
impl AlignedBuf {
#[must_use]
pub fn with_capacity(capacity: usize) -> Self {
let layout = match Layout::from_size_align(capacity, SIMDJSON_PADDING) {
Ok(layout) => layout,
Err(_) => Self::capacity_overflow(),
};
if mem::size_of::<usize>() < 8 && capacity > isize::MAX as usize {
Self::capacity_overflow()
}
let inner = match unsafe { NonNull::new(alloc(layout)) } {
Some(ptr) => ptr,
None => handle_alloc_error(layout),
};
Self {
layout,
capacity,
len: 0,
inner,
}
}
fn as_mut_ptr(&mut self) -> *mut u8 {
self.inner.as_ptr()
}
fn capacity_overflow() -> ! {
panic!("capacity overflow");
}
fn capacity(&self) -> usize {
self.capacity
}
unsafe fn set_len(&mut self, n: usize) {
assert!(
n <= self.capacity,
"New size ({}) can not be larger then capacity ({}).",
n,
self.capacity
);
self.len = n;
}
}
impl Drop for AlignedBuf {
fn drop(&mut self) {
unsafe {
dealloc(self.inner.as_ptr(), self.layout);
}
}
}
impl Deref for AlignedBuf {
type Target = [u8];
fn deref(&self) -> &Self::Target {
unsafe { std::slice::from_raw_parts(self.inner.as_ptr(), self.len) }
}
}
impl DerefMut for AlignedBuf {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { std::slice::from_raw_parts_mut(self.inner.as_ptr(), self.len) }
}
}
#[cfg(feature = "serde_impl")] #[cfg(test)]
mod tests {
use crate::Deserializer;
use serde_ext::Deserialize;
static JSON: &str = r#"{
"code": 200,
"success": true,
"payload": {
"features": [
"serde",
"json"
]
}
}"#;
#[derive(Deserialize, PartialEq, Debug)]
struct TestPayload {
features: Vec<String>,
}
#[derive(Deserialize, PartialEq, Debug)]
struct TestEnvelope {
code: usize,
success: bool,
payload: TestPayload,
}
#[test]
fn test_deser_to_value() {
let mut json = JSON.as_bytes().to_vec();
let d = Deserializer::from_slice(&mut json).expect("Invalid JSON");
let original_index = d.idx;
let original_nodes = d.tape.len();
let v = d.as_value();
assert!(v.contains_key("payload"), "Failed to find payload key");
let v = v.get("payload").expect("Can't get payload");
assert!(v.is_object(), "payload not recognized as object: {v:?}");
assert!(v.contains_key("features"), "Failed to find features key");
let v = v.get("features").expect("can't get features");
assert!(v.is_array(), "features not recognized as array: {v:?}");
assert_eq!(
original_index, d.idx,
"Deserializer has been internally modified"
);
assert_eq!(
original_nodes,
d.tape.len(),
"Deserializer has been internally modified"
);
}
#[test]
fn test_deser_restart() {
let mut json = JSON.as_bytes().to_vec();
let mut d = Deserializer::from_slice(&mut json).expect("Invalid JSON");
let original_index = d.idx;
let original_nodes = d.tape.len();
let test1 = TestEnvelope::deserialize(&mut d).expect("Deserialization failed");
assert!(
original_index != d.idx,
"Deserializer has NOT been internally modified"
);
assert_eq!(
original_nodes,
d.tape.len(),
"Deserializer nodes are NOT intact"
);
d.restart();
let test2 = TestEnvelope::deserialize(&mut d).expect("Deserialization failed");
assert_eq!(test2, test1, "Deserializer is not idempotent");
}
}