From f69a9a097bd77f413029bab7ea6a6aa6890dbc4f Mon Sep 17 00:00:00 2001 From: Sumera Priyadarsini Date: Thu, 3 Jul 2025 19:48:12 +0530 Subject: [PATCH 1/5] examples/perf: Add an arch flag to run only on x86_64 Allow lints for "unnecessary transmutes" for now. --- Cargo.toml | 2 ++ examples/perf.rs | 10 +++++++--- src/lib.rs | 3 ++- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7e0cb098..b85bd114 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,8 @@ alloc_counter = { version = "0.0.4", optional = true } colored = { version = "3.0", optional = true } getopts = { version = "0.2", optional = true } jemallocator = { version = "0.5", optional = true } + +[target.'cfg(target_arch = "x86_64")'.dependencies] perfcnt = { version = "0.8", optional = true } ref-cast = "1.0" diff --git a/examples/perf.rs b/examples/perf.rs index b5786c6a..778811c5 100644 --- a/examples/perf.rs +++ b/examples/perf.rs @@ -1,6 +1,6 @@ use std::env; -#[cfg(feature = "perf")] +#[cfg(all(feature = "perf", target_arch = "x86_64", target_os = "linux"))] mod int { const ROUNDS: usize = 2000; const WARMUP: usize = 200; @@ -216,10 +216,14 @@ mod int { } } -#[cfg(not(feature = "perf"))] +#[cfg(not(all(feature = "perf", target_arch = "x86_64", target_os = "linux")))] mod int { pub fn bench(_name: &str, _baseline: bool) { - println!("Perf requires linux to run and the perf feature to be enabled") + if std::env::consts::ARCH != "x86_64" { + println!("This Perf example only supports x86_64 for now."); + } else if std::env::consts::OS != "linux" { + println!("Perf requires linux to run and the perf feature to be enabled"); + } } } diff --git a/src/lib.rs b/src/lib.rs index c2830ea7..b9f377f7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,7 +11,8 @@ )] #![allow( clippy::module_name_repetitions, - unused_unsafe // for nightly + unused_unsafe, // for nightly + unnecessary_transmutes )] #![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/README.md"))] From 7c9391d0ec1bc534503fc0ae865d6d5b8e224e66 Mon Sep 17 00:00:00 2001 From: Sumera Priyadarsini Date: Thu, 3 Jul 2025 19:48:12 +0530 Subject: [PATCH 2/5] chore: Release simd-json version 0.16.0 Resolve lints for "unnecessary transmutes". Signed-off-by: Sumera Priyadarsini --- .github/workflows/quality.yaml | 2 +- .github/workflows/tests.yml | 4 ++-- Cargo.toml | 4 ++-- src/lib.rs | 1 - src/macros.rs | 6 +++--- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/.github/workflows/quality.yaml b/.github/workflows/quality.yaml index 2e01b0d7..e7068bc5 100644 --- a/.github/workflows/quality.yaml +++ b/.github/workflows/quality.yaml @@ -18,7 +18,7 @@ jobs: steps: - uses: actions/checkout@v3 - - uses: dtolnay/rust-toolchain@1.85 # do clippy chekcs with the minimum supported version + - uses: dtolnay/rust-toolchain@1.88 # do clippy chekcs with the minimum supported version with: components: rustfmt, clippy diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index b40c3176..11c013b0 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -24,7 +24,7 @@ jobs: steps: - uses: actions/checkout@v3 - - uses: dtolnay/rust-toolchain@1.85 + - uses: dtolnay/rust-toolchain@1.88 with: components: llvm-tools-preview @@ -120,7 +120,7 @@ jobs: steps: - uses: actions/checkout@v3 - - uses: dtolnay/rust-toolchain@1.85 + - uses: dtolnay/rust-toolchain@1.88 with: targets: wasm32-wasip1 diff --git a/Cargo.toml b/Cargo.toml index b85bd114..82ecfd88 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "simd-json" -version = "0.15.1" +version = "0.16.0" authors = ["Heinz N. Gies ", "Sunny Gleason"] edition = "2024" exclude = ["data/*", "fuzz/*"] @@ -9,7 +9,7 @@ description = "High performance JSON parser based on a port of simdjson" repository = "https://github.com/simd-lite/simd-json" readme = "README.md" documentation = "https://docs.rs/simd-json" -rust-version = "1.85" +rust-version = "1.88" [target.'cfg(target_family = "wasm")'.dependencies] getrandom = { version = "0.3", features = ["wasm_js"] } diff --git a/src/lib.rs b/src/lib.rs index b9f377f7..2967df3b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,7 +12,6 @@ #![allow( clippy::module_name_repetitions, unused_unsafe, // for nightly - unnecessary_transmutes )] #![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/README.md"))] diff --git a/src/macros.rs b/src/macros.rs index 0624ca74..2e61ca68 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -1223,7 +1223,7 @@ pub(crate) use unlikely; #[allow(unused_macros)] macro_rules! static_cast_i32 { ($v:expr_2021) => { - ::std::mem::transmute::($v) + u32::cast_signed($v) }; } #[allow(unused_imports)] @@ -1243,7 +1243,7 @@ pub(crate) use static_cast_u32; /// static cast to an i64 macro_rules! static_cast_i64 { ($v:expr_2021) => { - ::std::mem::transmute::($v) + u64::cast_signed($v) }; } pub(crate) use static_cast_i64; @@ -1261,7 +1261,7 @@ pub(crate) use static_cast_i128; /// static cast to an u64 macro_rules! static_cast_u64 { ($v:expr_2021) => { - ::std::mem::transmute::($v) + i64::cast_unsigned($v) }; } pub(crate) use static_cast_u64; From adb9f979622f30efbb574f593b3049acc5ba9e02 Mon Sep 17 00:00:00 2001 From: Sumera Priyadarsini Date: Sat, 26 Jul 2025 15:35:31 +0530 Subject: [PATCH 3/5] macros: fix "unnecessary transmute" for x86" Signed-off-by: Sumera Priyadarsini --- src/macros.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/macros.rs b/src/macros.rs index 2e61ca68..d1691902 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -1234,7 +1234,7 @@ pub(crate) use static_cast_i32; macro_rules! static_cast_u32 { ($v:expr_2021) => { // #[allow(clippy::missing_transmute_annotations)] - ::std::mem::transmute::($v) + i32::cast_unsigned($v) }; } #[allow(unused_imports)] From cfa89391f2add5c35629d604e4ff4523ee7ec7ec Mon Sep 17 00:00:00 2001 From: Sumera Priyadarsini Date: Thu, 31 Jul 2025 19:41:47 +0530 Subject: [PATCH 4/5] Make clippy happy Signed-off-by: Sumera Priyadarsini --- src/error.rs | 20 ++++++++++---------- src/impls/avx2/deser.rs | 2 +- src/impls/sse42/deser.rs | 2 +- src/lib.rs | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/error.rs b/src/error.rs index 8b3dc826..8fe45614 100644 --- a/src/error.rs +++ b/src/error.rs @@ -158,15 +158,15 @@ pub struct Error { /// Current character character: Option, /// Type of error - error: ErrorType, + err_type: ErrorType, } impl Error { - pub(crate) fn new(index: usize, character: Option, error: ErrorType) -> Self { + pub(crate) fn new(index: usize, character: Option, err_type: ErrorType) -> Self { Self { index, character, - error, + err_type, } } pub(crate) fn new_c(index: usize, character: char, error: ErrorType) -> Self { @@ -179,7 +179,7 @@ impl Error { Self { index: 0, character: None, - error: t, + err_type: t, } } @@ -198,7 +198,7 @@ impl Error { /// Returns the type of error that occurred. #[must_use] pub fn error(&self) -> &ErrorType { - &self.error + &self.err_type } // These make it a bit easier to fit into a serde_json context @@ -209,7 +209,7 @@ impl Error { #[must_use] pub fn is_io(&self) -> bool { // We have to include InternalError _somewhere_ - match &self.error { + match &self.err_type { ErrorType::Io(_) | ErrorType::InputTooLarge => true, ErrorType::InternalError(e) if !matches!(e, crate::InternalError::TapeError) => true, _ => false, @@ -219,7 +219,7 @@ impl Error { /// Indicates if the error that occurred was an early EOF #[must_use] pub fn is_eof(&self) -> bool { - matches!(self.error, ErrorType::Eof) + matches!(self.err_type, ErrorType::Eof) } /// Indicates if the error that occurred was due to a data shape error @@ -234,7 +234,7 @@ impl Error { pub fn is_syntax(&self) -> bool { // Lazy? maybe but if it aint something else... matches!( - self.error, + self.err_type, ErrorType::InternalError(crate::InternalError::TapeError) | //This seems to get thrown on some syntax errors ErrorType::BadKeyType | ErrorType::ExpectedArrayComma | @@ -268,9 +268,9 @@ impl std::error::Error for Error {} impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if let Some(c) = self.character { - write!(f, "{:?} at character {} ('{c}')", self.error, self.index) + write!(f, "{:?} at character {} ('{c}')", self.err_type, self.index) } else { - write!(f, "{:?} at character {}", self.error, self.index) + write!(f, "{:?} at character {}", self.err_type, self.index) } } } diff --git a/src/impls/avx2/deser.rs b/src/impls/avx2/deser.rs index 5821097b..cf978d0f 100644 --- a/src/impls/avx2/deser.rs +++ b/src/impls/avx2/deser.rs @@ -157,7 +157,7 @@ pub(crate) unsafe fn parse_str<'invoke, 'de>( if o == 0 { return Err(Deserializer::error_c(src_i, 'u', InvalidUnicodeCodepoint)); - }; + } // We moved o steps forward at the destination and 6 on the source src_i += s; dst_i += o; diff --git a/src/impls/sse42/deser.rs b/src/impls/sse42/deser.rs index 1d5e47b4..c169c5a2 100644 --- a/src/impls/sse42/deser.rs +++ b/src/impls/sse42/deser.rs @@ -148,7 +148,7 @@ pub(crate) unsafe fn parse_str<'invoke, 'de>( }; if o == 0 { return Err(Deserializer::error_c(src_i, 'u', InvalidUnicodeCodepoint)); - }; + } // We moved o steps forward at the destination and 6 on the source src_i += s; dst_i += o; diff --git a/src/lib.rs b/src/lib.rs index 2967df3b..2e1584f5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -916,7 +916,7 @@ impl<'de> Deserializer<'de> { // expensive carryless multiply in the previous step with this work let mut structurals: u64 = 0; - let lenminus64: usize = if len < 64 { 0 } else { len - 64 }; + let lenminus64: usize = len.saturating_sub(64); let mut idx: usize = 0; let mut error_mask: u64 = 0; // for unescaped characters within strings (ASCII code points < 0x20) From b84646579c6a30e7bef238516092f0acea766070 Mon Sep 17 00:00:00 2001 From: Sumera Priyadarsini Date: Thu, 31 Jul 2025 22:39:53 +0530 Subject: [PATCH 5/5] src: Make nightly and clippy happy --- src/impls/native/stage1.rs | 2 +- src/lib.rs | 2 +- src/numberparse/approx.rs | 2 +- src/serde.rs | 4 ++-- src/value/borrowed.rs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/impls/native/stage1.rs b/src/impls/native/stage1.rs index 0c0a4002..e2af9a35 100644 --- a/src/impls/native/stage1.rs +++ b/src/impls/native/stage1.rs @@ -445,7 +445,7 @@ impl Stage1Parse for SimdInput { base.reserve(64); let final_len = l + cnt; - let is_unaligned = l % 4 != 0; + let is_unaligned = !l.is_multiple_of(4); let write_fn = if is_unaligned { std::ptr::write_unaligned } else { diff --git a/src/lib.rs b/src/lib.rs index 2e1584f5..5a3051ac 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -123,7 +123,7 @@ impl Buffers { /// /// Will return `Err` if `s` is invalid JSON. #[cfg_attr(not(feature = "no-inline"), inline)] -pub fn to_tape(s: &mut [u8]) -> Result { +pub fn to_tape(s: &mut [u8]) -> Result> { Deserializer::from_slice(s).map(Deserializer::into_tape) } diff --git a/src/numberparse/approx.rs b/src/numberparse/approx.rs index 66324342..61113ecb 100644 --- a/src/numberparse/approx.rs +++ b/src/numberparse/approx.rs @@ -532,7 +532,7 @@ impl Deserializer<'_> { let mut d1: f64 = i as f64; d1 *= unsafe { POWER_OF_TEN.get_kinda_unchecked((323 + exponent) as usize) }; - StaticNode::from(if negative { d1 * -1.0 } else { d1 }) + StaticNode::from(if negative { -d1 } else { d1 }) } } else { if unlikely!(byte_count >= 18) { diff --git a/src/serde.rs b/src/serde.rs index 76f1346f..1ea81df5 100644 --- a/src/serde.rs +++ b/src/serde.rs @@ -136,7 +136,7 @@ where /// parses a Reader using a serde deserializer. /// /// # Warning -/// +/// /// Since simd-json does not support streaming and requires mutability of the data, this function /// will read the entire reader into memory before parsing it. /// @@ -208,7 +208,7 @@ impl<'de> Deserializer<'de> { } #[cfg_attr(not(feature = "no-inline"), inline)] - fn peek(&self) -> Result { + fn peek(&self) -> Result> { self.tape .get(self.idx) .copied() diff --git a/src/value/borrowed.rs b/src/value/borrowed.rs index ebc93469..b3f938fc 100644 --- a/src/value/borrowed.rs +++ b/src/value/borrowed.rs @@ -46,7 +46,7 @@ pub type Array<'value> = Vec>; /// # Errors /// /// Will return `Err` if `s` is invalid JSON. -pub fn to_value(s: &mut [u8]) -> Result { +pub fn to_value(s: &mut [u8]) -> Result> { match Deserializer::from_slice(s) { Ok(de) => Ok(BorrowDeserializer::from_deserializer(de).parse()), Err(e) => Err(e),