From 816cc2fdf8f742c40f201c9c95b9be6619fa2a92 Mon Sep 17 00:00:00 2001 From: Yuansheng Wang Date: Tue, 2 Jun 2026 09:33:15 +0800 Subject: [PATCH] test: add big-endian architecture Miri validation Add powerpc64-unknown-linux-gnu (big-endian) target to the Miri test matrix, aligning with serde_json's QA practices. Changes: - CI: add powerpc64 Miri FFI tests (ffi_smoke, ffi_cursor, ffi_strings, ffi_ops_interleave) using scalar scanner only - Tests: fix c_char signedness for cross-platform compatibility (char is unsigned on PowerPC, signed on x86) - Docs: add ENDIAN NOTE to src/scan/avx2.rs documenting that the AVX2 scanner is x86_64-only and relies on ISA-fixed bit semantics The c_char fix demonstrates the value of big-endian testing: it caught a latent ABI mismatch that would have broken FFI calls on platforms where char defaults to unsigned. Closes #148 --- .github/workflows/ci.yml | 9 ++++++- src/scan/avx2.rs | 6 +++++ tests/ffi_cursor.rs | 44 +++++++++++++++++------------------ tests/ffi_numbers.rs | 42 ++++++++++++++++----------------- tests/ffi_strings.rs | 7 +++--- tests/ffi_typeof.rs | 36 ++++++++++++++-------------- tests/ffi_wide_object.rs | 7 +++--- tests/third_party_fixtures.rs | 30 ++++++++++++------------ 8 files changed, 98 insertions(+), 83 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 74ddb29..ea621e8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -321,7 +321,7 @@ jobs: - name: Install Rust (nightly) run: | rustup toolchain install nightly --profile minimal --no-self-update - rustup +nightly target add x86_64-unknown-linux-gnu i686-unknown-linux-gnu + rustup +nightly target add x86_64-unknown-linux-gnu i686-unknown-linux-gnu powerpc64-unknown-linux-gnu rustup +nightly component add miri - name: Cache cargo registry & target @@ -349,6 +349,13 @@ jobs: cargo +nightly miri test --target i686-unknown-linux-gnu --no-default-features --test ffi_strings cargo +nightly miri test --target i686-unknown-linux-gnu --no-default-features --test ffi_ops_interleave + - name: Miri FFI tests powerpc64 (big-endian validation) + run: | + cargo +nightly miri test --target powerpc64-unknown-linux-gnu --no-default-features --test ffi_smoke + cargo +nightly miri test --target powerpc64-unknown-linux-gnu --no-default-features --test ffi_cursor + cargo +nightly miri test --target powerpc64-unknown-linux-gnu --no-default-features --test ffi_strings + cargo +nightly miri test --target powerpc64-unknown-linux-gnu --no-default-features --test ffi_ops_interleave + - name: ASan FFI smoke tests continue-on-error: true env: diff --git a/src/scan/avx2.rs b/src/scan/avx2.rs index 2f0f414..bd3c871 100644 --- a/src/scan/avx2.rs +++ b/src/scan/avx2.rs @@ -1,4 +1,10 @@ #![cfg(target_arch = "x86_64")] +// ENDIAN NOTE: This module is x86_64-only (always little-endian). The +// _mm256_movemask_epi8 intrinsic produces a 32-bit mask where bit i corresponds +// to the sign bit of lane i; combined masks are composed as (lo | (hi << 32)). +// This bit-index-to-lane mapping is fixed by the x86 ISA, not memory byte order, +// so the code is correct on x86_64 without explicit endian handling. PowerPC +// (big-endian) CI coverage runs the scalar scanner only. use core::arch::x86_64::*; use super::Scanner; diff --git a/tests/ffi_cursor.rs b/tests/ffi_cursor.rs index 4791b62..954f730 100644 --- a/tests/ffi_cursor.rs +++ b/tests/ffi_cursor.rs @@ -1,4 +1,4 @@ -use std::os::raw::c_int; +use std::os::raw::{c_char, c_int}; use qjson::ffi::*; fn parse(s: &[u8]) -> *mut qjson_doc { @@ -13,21 +13,21 @@ fn open_object_then_get_field() { let d = parse(b"{\"body\":{\"model\":\"gpt\",\"temperature\":0.5}}"); let mut c = std::mem::MaybeUninit::::uninit(); let p = b"body"; - let rc = unsafe { qjson_open(d, p.as_ptr() as *const i8, p.len(), c.as_mut_ptr()) }; + let rc = unsafe { qjson_open(d, p.as_ptr() as *const c_char, p.len(), c.as_mut_ptr()) }; assert_eq!(rc, 0); let c = unsafe { c.assume_init() }; let mut pp: *const u8 = std::ptr::null(); let mut nn: usize = 0; let k = b"model"; - let rc = unsafe { qjson_cursor_get_str(&c, k.as_ptr() as *const i8, k.len(), &mut pp, &mut nn) }; + let rc = unsafe { qjson_cursor_get_str(&c, k.as_ptr() as *const c_char, k.len(), &mut pp, &mut nn) }; assert_eq!(rc, 0); let s = unsafe { std::slice::from_raw_parts(pp, nn) }; assert_eq!(s, b"gpt"); let mut f: f64 = 0.0; let k = b"temperature"; - let rc = unsafe { qjson_cursor_get_f64(&c, k.as_ptr() as *const i8, k.len(), &mut f) }; + let rc = unsafe { qjson_cursor_get_f64(&c, k.as_ptr() as *const c_char, k.len(), &mut f) }; assert_eq!(rc, 0); assert!((f - 0.5).abs() < 1e-12); @@ -39,7 +39,7 @@ fn cursor_index_array() { let d = parse(b"[\"a\",\"b\",\"c\"]"); let mut c = std::mem::MaybeUninit::::uninit(); let p = b""; - let rc = unsafe { qjson_open(d, p.as_ptr() as *const i8, 0, c.as_mut_ptr()) }; + let rc = unsafe { qjson_open(d, p.as_ptr() as *const c_char, 0, c.as_mut_ptr()) }; assert_eq!(rc, 0); let c = unsafe { c.assume_init() }; @@ -51,7 +51,7 @@ fn cursor_index_array() { let mut pp: *const u8 = std::ptr::null(); let mut nn: usize = 0; let empty = b""; - let rc = unsafe { qjson_cursor_get_str(&sub, empty.as_ptr() as *const i8, 0, &mut pp, &mut nn) }; + let rc = unsafe { qjson_cursor_get_str(&sub, empty.as_ptr() as *const c_char, 0, &mut pp, &mut nn) }; assert_eq!(rc, 0); assert_eq!(unsafe { std::slice::from_raw_parts(pp, nn) }, b"b"); @@ -63,19 +63,19 @@ fn cursor_field_with_dotted_key() { let d = parse(b"{\"a.b\":42}"); let mut c = std::mem::MaybeUninit::::uninit(); let p = b""; - let rc = unsafe { qjson_open(d, p.as_ptr() as *const i8, 0, c.as_mut_ptr()) }; + let rc = unsafe { qjson_open(d, p.as_ptr() as *const c_char, 0, c.as_mut_ptr()) }; assert_eq!(rc, 0); let c = unsafe { c.assume_init() }; let mut sub = std::mem::MaybeUninit::::uninit(); let key = b"a.b"; - let rc = unsafe { qjson_cursor_field(&c, key.as_ptr() as *const i8, key.len(), sub.as_mut_ptr()) }; + let rc = unsafe { qjson_cursor_field(&c, key.as_ptr() as *const c_char, key.len(), sub.as_mut_ptr()) }; assert_eq!(rc, 0); let sub = unsafe { sub.assume_init() }; let mut v: i64 = 0; let empty = b""; - let rc = unsafe { qjson_cursor_get_i64(&sub, empty.as_ptr() as *const i8, 0, &mut v) }; + let rc = unsafe { qjson_cursor_get_i64(&sub, empty.as_ptr() as *const c_char, 0, &mut v) }; assert_eq!(rc, 0); assert_eq!(v, 42); @@ -91,7 +91,7 @@ fn walk_children_trailing_scalar_integer() { let d = parse(b"[10,20,30]"); let mut c = std::mem::MaybeUninit::::uninit(); let empty = b""; - let rc = unsafe { qjson_open(d, empty.as_ptr() as *const i8, 0, c.as_mut_ptr()) }; + let rc = unsafe { qjson_open(d, empty.as_ptr() as *const c_char, 0, c.as_mut_ptr()) }; assert_eq!(rc, 0); let c = unsafe { c.assume_init() }; @@ -102,7 +102,7 @@ fn walk_children_trailing_scalar_integer() { let sub = unsafe { sub.assume_init() }; let mut v: i64 = 0; - let rc = unsafe { qjson_cursor_get_i64(&sub, empty.as_ptr() as *const i8, 0, &mut v) }; + let rc = unsafe { qjson_cursor_get_i64(&sub, empty.as_ptr() as *const c_char, 0, &mut v) }; assert_eq!(rc, 0, "qjson_cursor_get_i64 on trailing element must succeed"); assert_eq!(v, 30); @@ -116,7 +116,7 @@ fn walk_children_trailing_scalar_bool() { let d = parse(b"[1,\"x\",true]"); let mut c = std::mem::MaybeUninit::::uninit(); let empty = b""; - let rc = unsafe { qjson_open(d, empty.as_ptr() as *const i8, 0, c.as_mut_ptr()) }; + let rc = unsafe { qjson_open(d, empty.as_ptr() as *const c_char, 0, c.as_mut_ptr()) }; assert_eq!(rc, 0); let c = unsafe { c.assume_init() }; @@ -127,7 +127,7 @@ fn walk_children_trailing_scalar_bool() { let sub = unsafe { sub.assume_init() }; let mut b: c_int = -1; - let rc = unsafe { qjson_cursor_get_bool(&sub, empty.as_ptr() as *const i8, 0, &mut b) }; + let rc = unsafe { qjson_cursor_get_bool(&sub, empty.as_ptr() as *const c_char, 0, &mut b) }; assert_eq!(rc, 0, "qjson_cursor_get_bool on trailing `true` must succeed"); assert_eq!(b, 1); @@ -139,17 +139,17 @@ fn open_root_number_cursor_gets_f64() { let d = parse(b"42"); let mut c = std::mem::MaybeUninit::::uninit(); let empty = b""; - let rc = unsafe { qjson_open(d, empty.as_ptr() as *const i8, 0, c.as_mut_ptr()) }; + let rc = unsafe { qjson_open(d, empty.as_ptr() as *const c_char, 0, c.as_mut_ptr()) }; assert_eq!(rc, 0); let c = unsafe { c.assume_init() }; let mut t: c_int = -1; - let rc = unsafe { qjson_cursor_typeof(&c, empty.as_ptr() as *const i8, 0, &mut t) }; + let rc = unsafe { qjson_cursor_typeof(&c, empty.as_ptr() as *const c_char, 0, &mut t) }; assert_eq!(rc, 0); assert_eq!(t, 2); let mut v: f64 = 0.0; - let rc = unsafe { qjson_cursor_get_f64(&c, empty.as_ptr() as *const i8, 0, &mut v) }; + let rc = unsafe { qjson_cursor_get_f64(&c, empty.as_ptr() as *const c_char, 0, &mut v) }; assert_eq!(rc, 0); assert_eq!(v, 42.0); @@ -162,24 +162,24 @@ fn open_root_bool_and_null_cursors() { let d = parse(b"true"); let mut c = std::mem::MaybeUninit::::uninit(); - let rc = unsafe { qjson_open(d, empty.as_ptr() as *const i8, 0, c.as_mut_ptr()) }; + let rc = unsafe { qjson_open(d, empty.as_ptr() as *const c_char, 0, c.as_mut_ptr()) }; assert_eq!(rc, 0); let c = unsafe { c.assume_init() }; let mut b: c_int = -1; - let rc = unsafe { qjson_cursor_get_bool(&c, empty.as_ptr() as *const i8, 0, &mut b) }; + let rc = unsafe { qjson_cursor_get_bool(&c, empty.as_ptr() as *const c_char, 0, &mut b) }; assert_eq!(rc, 0); assert_eq!(b, 1); unsafe { qjson_free(d) }; let d = parse(b"null"); let mut c = std::mem::MaybeUninit::::uninit(); - let rc = unsafe { qjson_open(d, empty.as_ptr() as *const i8, 0, c.as_mut_ptr()) }; + let rc = unsafe { qjson_open(d, empty.as_ptr() as *const c_char, 0, c.as_mut_ptr()) }; assert_eq!(rc, 0); let c = unsafe { c.assume_init() }; let mut t: c_int = -1; - let rc = unsafe { qjson_cursor_typeof(&c, empty.as_ptr() as *const i8, 0, &mut t) }; + let rc = unsafe { qjson_cursor_typeof(&c, empty.as_ptr() as *const c_char, 0, &mut t) }; assert_eq!(rc, 0); assert_eq!(t, 0); @@ -191,12 +191,12 @@ fn root_scalar_cursor_container_ops_return_type_mismatch() { let d = parse(b"42"); let mut c = std::mem::MaybeUninit::::uninit(); let empty = b""; - let rc = unsafe { qjson_open(d, empty.as_ptr() as *const i8, 0, c.as_mut_ptr()) }; + let rc = unsafe { qjson_open(d, empty.as_ptr() as *const c_char, 0, c.as_mut_ptr()) }; assert_eq!(rc, 0); let c = unsafe { c.assume_init() }; let mut len = 0usize; - let rc = unsafe { qjson_cursor_len(&c, empty.as_ptr() as *const i8, 0, &mut len) }; + let rc = unsafe { qjson_cursor_len(&c, empty.as_ptr() as *const c_char, 0, &mut len) }; assert_eq!(rc, 3); let mut key_ptr: *const u8 = std::ptr::null(); diff --git a/tests/ffi_numbers.rs b/tests/ffi_numbers.rs index b194b3c..6378469 100644 --- a/tests/ffi_numbers.rs +++ b/tests/ffi_numbers.rs @@ -1,4 +1,4 @@ -use std::os::raw::c_int; +use std::os::raw::{c_char, c_int}; use qjson::ffi::*; fn parse(s: &[u8]) -> *mut qjson_doc { @@ -13,7 +13,7 @@ fn get_i64_basic() { let d = parse(b"{\"a\":42}"); let mut v: i64 = 0; let p = b"a"; - let rc = unsafe { qjson_get_i64(d, p.as_ptr() as *const i8, p.len(), &mut v) }; + let rc = unsafe { qjson_get_i64(d, p.as_ptr() as *const c_char, p.len(), &mut v) }; assert_eq!(rc, 0); assert_eq!(v, 42); unsafe { qjson_free(d) }; @@ -24,7 +24,7 @@ fn get_i64_negative() { let d = parse(b"{\"a\":-7}"); let mut v: i64 = 0; let p = b"a"; - let rc = unsafe { qjson_get_i64(d, p.as_ptr() as *const i8, p.len(), &mut v) }; + let rc = unsafe { qjson_get_i64(d, p.as_ptr() as *const c_char, p.len(), &mut v) }; assert_eq!(rc, 0); assert_eq!(v, -7); unsafe { qjson_free(d) }; @@ -35,7 +35,7 @@ fn get_i64_overflow() { let d = parse(b"{\"a\":99999999999999999999}"); let mut v: i64 = 0; let p = b"a"; - let rc = unsafe { qjson_get_i64(d, p.as_ptr() as *const i8, p.len(), &mut v) }; + let rc = unsafe { qjson_get_i64(d, p.as_ptr() as *const c_char, p.len(), &mut v) }; assert_eq!(rc, 4); // OUT_OF_RANGE unsafe { qjson_free(d) }; } @@ -45,7 +45,7 @@ fn get_f64_basic() { let d = parse(b"{\"a\":1.7}"); let mut v: f64 = 0.0; let p = b"a"; - let rc = unsafe { qjson_get_f64(d, p.as_ptr() as *const i8, p.len(), &mut v) }; + let rc = unsafe { qjson_get_f64(d, p.as_ptr() as *const c_char, p.len(), &mut v) }; assert_eq!(rc, 0); assert!((v - 1.7).abs() < 1e-12); unsafe { qjson_free(d) }; @@ -56,11 +56,11 @@ fn get_bool() { let d = parse(b"{\"a\":true,\"b\":false}"); let mut v: c_int = -1; let p = b"a"; - let rc = unsafe { qjson_get_bool(d, p.as_ptr() as *const i8, p.len(), &mut v) }; + let rc = unsafe { qjson_get_bool(d, p.as_ptr() as *const c_char, p.len(), &mut v) }; assert_eq!(rc, 0); assert_ne!(v, 0); let p = b"b"; - let rc = unsafe { qjson_get_bool(d, p.as_ptr() as *const i8, p.len(), &mut v) }; + let rc = unsafe { qjson_get_bool(d, p.as_ptr() as *const c_char, p.len(), &mut v) }; assert_eq!(rc, 0); assert_eq!(v, 0); unsafe { qjson_free(d) }; @@ -72,11 +72,11 @@ fn get_i64_max_and_min() { let d = parse(json.as_bytes()); let mut v: i64 = 0; let p = b"hi"; - let rc = unsafe { qjson_get_i64(d, p.as_ptr() as *const i8, p.len(), &mut v) }; + let rc = unsafe { qjson_get_i64(d, p.as_ptr() as *const c_char, p.len(), &mut v) }; assert_eq!(rc, 0); assert_eq!(v, i64::MAX); let p = b"lo"; - let rc = unsafe { qjson_get_i64(d, p.as_ptr() as *const i8, p.len(), &mut v) }; + let rc = unsafe { qjson_get_i64(d, p.as_ptr() as *const c_char, p.len(), &mut v) }; assert_eq!(rc, 0); assert_eq!(v, i64::MIN); unsafe { qjson_free(d) }; @@ -88,7 +88,7 @@ fn get_i64_just_over_max_overflows() { let d = parse(b"{\"a\":9223372036854775808}"); let mut v: i64 = 0; let p = b"a"; - let rc = unsafe { qjson_get_i64(d, p.as_ptr() as *const i8, p.len(), &mut v) }; + let rc = unsafe { qjson_get_i64(d, p.as_ptr() as *const c_char, p.len(), &mut v) }; assert_eq!(rc, 4); // OUT_OF_RANGE unsafe { qjson_free(d) }; } @@ -98,7 +98,7 @@ fn get_i64_returns_type_mismatch_for_non_numbers() { let d = parse(b"{\"b\":true,\"s\":\"1\",\"n\":null}"); let mut v: i64 = 0; for p in [b"b".as_slice(), b"s".as_slice(), b"n".as_slice()] { - let rc = unsafe { qjson_get_i64(d, p.as_ptr() as *const i8, p.len(), &mut v) }; + let rc = unsafe { qjson_get_i64(d, p.as_ptr() as *const c_char, p.len(), &mut v) }; assert_eq!(rc, 3); // TYPE_MISMATCH } unsafe { qjson_free(d) }; @@ -110,7 +110,7 @@ fn get_u64_max() { let d = parse(json.as_bytes()); let mut v: u64 = 0; let p = b"a"; - let rc = unsafe { qjson_get_u64(d, p.as_ptr() as *const i8, p.len(), &mut v) }; + let rc = unsafe { qjson_get_u64(d, p.as_ptr() as *const c_char, p.len(), &mut v) }; assert_eq!(rc, 0); assert_eq!(v, u64::MAX); unsafe { qjson_free(d) }; @@ -121,10 +121,10 @@ fn get_u64_rejects_negative_and_overflow() { let d = parse(b"{\"neg\":-1,\"too_big\":18446744073709551616}"); let mut v: u64 = 0; let p = b"neg"; - let rc = unsafe { qjson_get_u64(d, p.as_ptr() as *const i8, p.len(), &mut v) }; + let rc = unsafe { qjson_get_u64(d, p.as_ptr() as *const c_char, p.len(), &mut v) }; assert_eq!(rc, 4); // OUT_OF_RANGE let p = b"too_big"; - let rc = unsafe { qjson_get_u64(d, p.as_ptr() as *const i8, p.len(), &mut v) }; + let rc = unsafe { qjson_get_u64(d, p.as_ptr() as *const c_char, p.len(), &mut v) }; assert_eq!(rc, 4); // OUT_OF_RANGE unsafe { qjson_free(d) }; } @@ -134,7 +134,7 @@ fn get_u64_rejects_float_and_non_numbers() { let d = parse(b"{\"f\":1.5,\"b\":true,\"s\":\"1\",\"n\":null}"); let mut v: u64 = 0; for p in [b"f".as_slice(), b"b".as_slice(), b"s".as_slice(), b"n".as_slice()] { - let rc = unsafe { qjson_get_u64(d, p.as_ptr() as *const i8, p.len(), &mut v) }; + let rc = unsafe { qjson_get_u64(d, p.as_ptr() as *const c_char, p.len(), &mut v) }; assert_eq!(rc, 3); // TYPE_MISMATCH } unsafe { qjson_free(d) }; @@ -152,11 +152,11 @@ fn cursor_get_u64_max() { _reserved1: 0, }; let p = b"root"; - let rc = unsafe { qjson_open(d, p.as_ptr() as *const i8, p.len(), &mut cur) }; + let rc = unsafe { qjson_open(d, p.as_ptr() as *const c_char, p.len(), &mut cur) }; assert_eq!(rc, 0); let mut v: u64 = 0; let p = b"a"; - let rc = unsafe { qjson_cursor_get_u64(&cur, p.as_ptr() as *const i8, p.len(), &mut v) }; + let rc = unsafe { qjson_cursor_get_u64(&cur, p.as_ptr() as *const c_char, p.len(), &mut v) }; assert_eq!(rc, 0); assert_eq!(v, u64::MAX); unsafe { qjson_free(d) }; @@ -167,7 +167,7 @@ fn get_f64_large_magnitude() { let d = parse(b"{\"a\":1.7e308}"); let mut v: f64 = 0.0; let p = b"a"; - let rc = unsafe { qjson_get_f64(d, p.as_ptr() as *const i8, p.len(), &mut v) }; + let rc = unsafe { qjson_get_f64(d, p.as_ptr() as *const c_char, p.len(), &mut v) }; assert_eq!(rc, 0); assert!(v > 1.0e308 && v < f64::INFINITY); unsafe { qjson_free(d) }; @@ -178,11 +178,11 @@ fn get_f64_negative_zero_and_exponent() { let d = parse(b"{\"a\":-0.0,\"b\":1e-300}"); let mut v: f64 = 1.0; let p = b"a"; - let rc = unsafe { qjson_get_f64(d, p.as_ptr() as *const i8, p.len(), &mut v) }; + let rc = unsafe { qjson_get_f64(d, p.as_ptr() as *const c_char, p.len(), &mut v) }; assert_eq!(rc, 0); assert_eq!(v, 0.0); let p = b"b"; - let rc = unsafe { qjson_get_f64(d, p.as_ptr() as *const i8, p.len(), &mut v) }; + let rc = unsafe { qjson_get_f64(d, p.as_ptr() as *const c_char, p.len(), &mut v) }; assert_eq!(rc, 0); assert!(v > 0.0 && v < 1e-200); unsafe { qjson_free(d) }; @@ -193,7 +193,7 @@ fn get_i64_rejects_float_form() { let d = parse(b"{\"a\":1.5}"); let mut v: i64 = 0; let p = b"a"; - let rc = unsafe { qjson_get_i64(d, p.as_ptr() as *const i8, p.len(), &mut v) }; + let rc = unsafe { qjson_get_i64(d, p.as_ptr() as *const c_char, p.len(), &mut v) }; assert_ne!(rc, 0); // any error code is acceptable; not a valid i64 unsafe { qjson_free(d) }; } diff --git a/tests/ffi_strings.rs b/tests/ffi_strings.rs index 6e333c7..3bb940e 100644 --- a/tests/ffi_strings.rs +++ b/tests/ffi_strings.rs @@ -1,3 +1,4 @@ +use std::os::raw::c_char; use qjson::ffi::*; fn parse(s: &[u8]) -> *mut qjson_doc { @@ -13,7 +14,7 @@ fn get_str_simple() { let mut p: *const u8 = std::ptr::null(); let mut n: usize = 0; let path = b"a"; - let rc = unsafe { qjson_get_str(d, path.as_ptr() as *const i8, path.len(), &mut p, &mut n) }; + let rc = unsafe { qjson_get_str(d, path.as_ptr() as *const c_char, path.len(), &mut p, &mut n) }; assert_eq!(rc, 0); let s = unsafe { std::slice::from_raw_parts(p, n) }; assert_eq!(s, b"hello"); @@ -26,7 +27,7 @@ fn get_str_with_escape() { let mut p: *const u8 = std::ptr::null(); let mut n: usize = 0; let path = b"a"; - let rc = unsafe { qjson_get_str(d, path.as_ptr() as *const i8, path.len(), &mut p, &mut n) }; + let rc = unsafe { qjson_get_str(d, path.as_ptr() as *const c_char, path.len(), &mut p, &mut n) }; assert_eq!(rc, 0); let s = unsafe { std::slice::from_raw_parts(p, n) }; assert_eq!(s, b"he\nlo"); @@ -39,7 +40,7 @@ fn get_str_type_mismatch() { let mut p: *const u8 = std::ptr::null(); let mut n: usize = 0; let path = b"a"; - let rc = unsafe { qjson_get_str(d, path.as_ptr() as *const i8, path.len(), &mut p, &mut n) }; + let rc = unsafe { qjson_get_str(d, path.as_ptr() as *const c_char, path.len(), &mut p, &mut n) }; assert_eq!(rc, 3); // TYPE_MISMATCH unsafe { qjson_free(d) }; } diff --git a/tests/ffi_typeof.rs b/tests/ffi_typeof.rs index ff62783..7d5b0c2 100644 --- a/tests/ffi_typeof.rs +++ b/tests/ffi_typeof.rs @@ -1,4 +1,4 @@ -use std::os::raw::c_int; +use std::os::raw::{c_char, c_int}; use qjson::ffi::*; fn parse(s: &[u8]) -> *mut qjson_doc { @@ -13,7 +13,7 @@ fn typeof_string() { let d = parse(b"{\"a\":\"hi\"}"); let mut t: c_int = -1; let p = b"a"; - let rc = unsafe { qjson_typeof(d, p.as_ptr() as *const i8, p.len(), &mut t) }; + let rc = unsafe { qjson_typeof(d, p.as_ptr() as *const c_char, p.len(), &mut t) }; assert_eq!(rc, 0); assert_eq!(t, 3); // QJSON_T_STR unsafe { qjson_free(d) }; @@ -24,7 +24,7 @@ fn typeof_number() { let d = parse(b"{\"a\":42}"); let mut t: c_int = -1; let p = b"a"; - let rc = unsafe { qjson_typeof(d, p.as_ptr() as *const i8, p.len(), &mut t) }; + let rc = unsafe { qjson_typeof(d, p.as_ptr() as *const c_char, p.len(), &mut t) }; assert_eq!(rc, 0); assert_eq!(t, 2); // QJSON_T_NUM unsafe { qjson_free(d) }; @@ -35,7 +35,7 @@ fn typeof_bool() { let d = parse(b"{\"a\":true}"); let mut t: c_int = -1; let p = b"a"; - let rc = unsafe { qjson_typeof(d, p.as_ptr() as *const i8, p.len(), &mut t) }; + let rc = unsafe { qjson_typeof(d, p.as_ptr() as *const c_char, p.len(), &mut t) }; assert_eq!(rc, 0); assert_eq!(t, 1); unsafe { qjson_free(d) }; @@ -46,7 +46,7 @@ fn typeof_null() { let d = parse(b"{\"a\":null}"); let mut t: c_int = -1; let p = b"a"; - let rc = unsafe { qjson_typeof(d, p.as_ptr() as *const i8, p.len(), &mut t) }; + let rc = unsafe { qjson_typeof(d, p.as_ptr() as *const c_char, p.len(), &mut t) }; assert_eq!(rc, 0); assert_eq!(t, 0); unsafe { qjson_free(d) }; @@ -57,7 +57,7 @@ fn is_null_true() { let d = parse(b"{\"a\":null}"); let mut b: c_int = -1; let p = b"a"; - let rc = unsafe { qjson_is_null(d, p.as_ptr() as *const i8, p.len(), &mut b) }; + let rc = unsafe { qjson_is_null(d, p.as_ptr() as *const c_char, p.len(), &mut b) }; assert_eq!(rc, 0); assert_ne!(b, 0); unsafe { qjson_free(d) }; @@ -68,7 +68,7 @@ fn len_object() { let d = parse(b"{\"a\":1,\"b\":2,\"c\":3}"); let mut n: usize = 0; let p = b""; - let rc = unsafe { qjson_len(d, p.as_ptr() as *const i8, p.len(), &mut n) }; + let rc = unsafe { qjson_len(d, p.as_ptr() as *const c_char, p.len(), &mut n) }; assert_eq!(rc, 0); assert_eq!(n, 3); unsafe { qjson_free(d) }; @@ -79,7 +79,7 @@ fn len_array() { let d = parse(b"[10,20,30,40]"); let mut n: usize = 0; let p = b""; - let rc = unsafe { qjson_len(d, p.as_ptr() as *const i8, p.len(), &mut n) }; + let rc = unsafe { qjson_len(d, p.as_ptr() as *const c_char, p.len(), &mut n) }; assert_eq!(rc, 0); assert_eq!(n, 4); unsafe { qjson_free(d) }; @@ -90,7 +90,7 @@ fn typeof_not_found() { let d = parse(b"{\"a\":1}"); let mut t: c_int = -1; let p = b"b"; - let rc = unsafe { qjson_typeof(d, p.as_ptr() as *const i8, p.len(), &mut t) }; + let rc = unsafe { qjson_typeof(d, p.as_ptr() as *const c_char, p.len(), &mut t) }; assert_eq!(rc, 2); // NOT_FOUND unsafe { qjson_free(d) }; } @@ -100,7 +100,7 @@ fn len_empty_object() { let d = parse(b"{}"); let mut n: usize = 0; let p = b""; - let rc = unsafe { qjson_len(d, p.as_ptr() as *const i8, p.len(), &mut n) }; + let rc = unsafe { qjson_len(d, p.as_ptr() as *const c_char, p.len(), &mut n) }; assert_eq!(rc, 0); assert_eq!(n, 0); unsafe { qjson_free(d) }; @@ -111,7 +111,7 @@ fn len_empty_array() { let d = parse(b"[]"); let mut n: usize = 0; let p = b""; - let rc = unsafe { qjson_len(d, p.as_ptr() as *const i8, p.len(), &mut n) }; + let rc = unsafe { qjson_len(d, p.as_ptr() as *const c_char, p.len(), &mut n) }; assert_eq!(rc, 0); assert_eq!(n, 0); unsafe { qjson_free(d) }; @@ -122,7 +122,7 @@ fn len_single_scalar_array() { let d = parse(b"[5]"); let mut n: usize = 0; let p = b""; - let rc = unsafe { qjson_len(d, p.as_ptr() as *const i8, p.len(), &mut n) }; + let rc = unsafe { qjson_len(d, p.as_ptr() as *const c_char, p.len(), &mut n) }; assert_eq!(rc, 0); assert_eq!(n, 1); unsafe { qjson_free(d) }; @@ -133,7 +133,7 @@ fn len_single_scalar_object() { let d = parse(b"{\"a\":1}"); let mut n: usize = 0; let p = b""; - let rc = unsafe { qjson_len(d, p.as_ptr() as *const i8, p.len(), &mut n) }; + let rc = unsafe { qjson_len(d, p.as_ptr() as *const c_char, p.len(), &mut n) }; assert_eq!(rc, 0); assert_eq!(n, 1); unsafe { qjson_free(d) }; @@ -145,25 +145,25 @@ fn root_scalar_typeof_and_getters_work_with_empty_path() { let d = parse(b"42"); let mut t: c_int = -1; - let rc = unsafe { qjson_typeof(d, empty.as_ptr() as *const i8, 0, &mut t) }; + let rc = unsafe { qjson_typeof(d, empty.as_ptr() as *const c_char, 0, &mut t) }; assert_eq!(rc, 0); assert_eq!(t, 2); let mut v: f64 = 0.0; - let rc = unsafe { qjson_get_f64(d, empty.as_ptr() as *const i8, 0, &mut v) }; + let rc = unsafe { qjson_get_f64(d, empty.as_ptr() as *const c_char, 0, &mut v) }; assert_eq!(rc, 0); assert_eq!(v, 42.0); unsafe { qjson_free(d) }; let d = parse(b"false"); let mut b: c_int = -1; - let rc = unsafe { qjson_get_bool(d, empty.as_ptr() as *const i8, 0, &mut b) }; + let rc = unsafe { qjson_get_bool(d, empty.as_ptr() as *const c_char, 0, &mut b) }; assert_eq!(rc, 0); assert_eq!(b, 0); unsafe { qjson_free(d) }; let d = parse(b"null"); let mut is_null: c_int = 0; - let rc = unsafe { qjson_is_null(d, empty.as_ptr() as *const i8, 0, &mut is_null) }; + let rc = unsafe { qjson_is_null(d, empty.as_ptr() as *const c_char, 0, &mut is_null) }; assert_eq!(rc, 0); assert_eq!(is_null, 1); unsafe { qjson_free(d) }; @@ -174,7 +174,7 @@ fn root_scalar_len_returns_type_mismatch() { let d = parse(b"42"); let empty = b""; let mut len = 0usize; - let rc = unsafe { qjson_len(d, empty.as_ptr() as *const i8, 0, &mut len) }; + let rc = unsafe { qjson_len(d, empty.as_ptr() as *const c_char, 0, &mut len) }; assert_eq!(rc, 3); unsafe { qjson_free(d) }; } diff --git a/tests/ffi_wide_object.rs b/tests/ffi_wide_object.rs index d82d897..87ef0e8 100644 --- a/tests/ffi_wide_object.rs +++ b/tests/ffi_wide_object.rs @@ -1,6 +1,7 @@ //! Wide-object skip-cache test (spec ยง9.2): 5K keys, repeatedly access random //! keys via the same cursor and confirm correctness. +use std::os::raw::c_char; use qjson::ffi::*; fn build_wide(n: usize) -> (String, Vec) { @@ -31,14 +32,14 @@ fn wide_object_5k_keys_all_resolvable() { for &i in &samples { let mut v: i64 = -1; let k = keys[i].as_bytes(); - let rc = unsafe { qjson_get_i64(d, k.as_ptr() as *const i8, k.len(), &mut v) }; + let rc = unsafe { qjson_get_i64(d, k.as_ptr() as *const c_char, k.len(), &mut v) }; assert_eq!(rc, 0, "miss on first pass for key {}", keys[i]); assert_eq!(v as usize, i * 2); } for &i in samples.iter().rev() { let mut v: i64 = -1; let k = keys[i].as_bytes(); - let rc = unsafe { qjson_get_i64(d, k.as_ptr() as *const i8, k.len(), &mut v) }; + let rc = unsafe { qjson_get_i64(d, k.as_ptr() as *const c_char, k.len(), &mut v) }; assert_eq!(rc, 0, "miss on cache-hit pass for key {}", keys[i]); assert_eq!(v as usize, i * 2); } @@ -46,7 +47,7 @@ fn wide_object_5k_keys_all_resolvable() { // Unknown key still returns NOT_FOUND after the cache is populated. let bogus = b"definitely_not_a_key"; let mut v: i64 = 0; - let rc = unsafe { qjson_get_i64(d, bogus.as_ptr() as *const i8, bogus.len(), &mut v) }; + let rc = unsafe { qjson_get_i64(d, bogus.as_ptr() as *const c_char, bogus.len(), &mut v) }; assert_eq!(rc, 2); // QJSON_NOT_FOUND unsafe { qjson_free(d) }; diff --git a/tests/third_party_fixtures.rs b/tests/third_party_fixtures.rs index e185550..9ad51d1 100644 --- a/tests/third_party_fixtures.rs +++ b/tests/third_party_fixtures.rs @@ -1,5 +1,5 @@ use std::fs; -use std::os::raw::c_int; +use std::os::raw::{c_char, c_int}; use std::path::{Path, PathBuf}; use std::ptr; @@ -98,35 +98,35 @@ fn simdjson_ndjson_cases() -> Vec { fn get_str(doc: *mut qjson_doc, path: &[u8]) -> String { let mut p: *const u8 = ptr::null(); let mut n: usize = 0; - let rc = unsafe { qjson_get_str(doc, path.as_ptr() as *const i8, path.len(), &mut p, &mut n) }; + let rc = unsafe { qjson_get_str(doc, path.as_ptr() as *const c_char, path.len(), &mut p, &mut n) }; assert_eq!(rc, qjson_err::QJSON_OK as c_int); String::from_utf8(unsafe { std::slice::from_raw_parts(p, n) }.to_vec()).unwrap() } fn get_i64(doc: *mut qjson_doc, path: &[u8]) -> i64 { let mut v: i64 = 0; - let rc = unsafe { qjson_get_i64(doc, path.as_ptr() as *const i8, path.len(), &mut v) }; + let rc = unsafe { qjson_get_i64(doc, path.as_ptr() as *const c_char, path.len(), &mut v) }; assert_eq!(rc, qjson_err::QJSON_OK as c_int); v } fn get_bool(doc: *mut qjson_doc, path: &[u8]) -> bool { let mut v: c_int = -1; - let rc = unsafe { qjson_get_bool(doc, path.as_ptr() as *const i8, path.len(), &mut v) }; + let rc = unsafe { qjson_get_bool(doc, path.as_ptr() as *const c_char, path.len(), &mut v) }; assert_eq!(rc, qjson_err::QJSON_OK as c_int); v != 0 } fn is_null(doc: *mut qjson_doc, path: &[u8]) -> bool { let mut v: c_int = -1; - let rc = unsafe { qjson_is_null(doc, path.as_ptr() as *const i8, path.len(), &mut v) }; + let rc = unsafe { qjson_is_null(doc, path.as_ptr() as *const c_char, path.len(), &mut v) }; assert_eq!(rc, qjson_err::QJSON_OK as c_int); v != 0 } fn len(doc: *mut qjson_doc, path: &[u8]) -> usize { let mut n: usize = 0; - let rc = unsafe { qjson_len(doc, path.as_ptr() as *const i8, path.len(), &mut n) }; + let rc = unsafe { qjson_len(doc, path.as_ptr() as *const c_char, path.len(), &mut n) }; assert_eq!(rc, qjson_err::QJSON_OK as c_int); n } @@ -136,7 +136,7 @@ fn open(doc: *mut qjson_doc, path: &[u8]) -> qjson_cursor { let rc = unsafe { qjson_open( doc, - path.as_ptr() as *const i8, + path.as_ptr() as *const c_char, path.len(), cur.as_mut_ptr(), ) @@ -156,7 +156,7 @@ fn cursor_get_str(cur: &qjson_cursor) -> String { let empty = b""; let mut p: *const u8 = ptr::null(); let mut n: usize = 0; - let rc = unsafe { qjson_cursor_get_str(cur, empty.as_ptr() as *const i8, 0, &mut p, &mut n) }; + let rc = unsafe { qjson_cursor_get_str(cur, empty.as_ptr() as *const c_char, 0, &mut p, &mut n) }; assert_eq!(rc, qjson_err::QJSON_OK as c_int); String::from_utf8(unsafe { std::slice::from_raw_parts(p, n) }.to_vec()).unwrap() } @@ -304,7 +304,7 @@ fn cjson_menu_and_matrix_fixtures_keep_array_shape() { let rc = unsafe { qjson_cursor_field( &second, - b"onclick".as_ptr() as *const i8, + b"onclick".as_ptr() as *const c_char, b"onclick".len(), onclick.as_mut_ptr(), ) @@ -324,7 +324,7 @@ fn cjson_menu_and_matrix_fixtures_keep_array_shape() { let first = cursor_index(&middle_row, 0); let mut v: i64 = 0; let empty = b""; - let rc = unsafe { qjson_cursor_get_i64(&first, empty.as_ptr() as *const i8, 0, &mut v) }; + let rc = unsafe { qjson_cursor_get_i64(&first, empty.as_ptr() as *const c_char, 0, &mut v) }; assert_eq!(rc, qjson_err::QJSON_OK as c_int); assert_eq!(v, 1); unsafe { qjson_free(matrix_doc) }; @@ -444,7 +444,7 @@ fn cjson_fixture_invalid_paths_and_type_mismatches_fail() { let rc = unsafe { qjson_get_str( doc, - b"format.width".as_ptr() as *const i8, + b"format.width".as_ptr() as *const c_char, b"format.width".len(), &mut wrong_type_p, &mut wrong_type_n, @@ -457,7 +457,7 @@ fn cjson_fixture_invalid_paths_and_type_mismatches_fail() { let rc = unsafe { qjson_get_str( doc, - b"format.missing".as_ptr() as *const i8, + b"format.missing".as_ptr() as *const c_char, b"format.missing".len(), &mut p, &mut n, @@ -470,7 +470,7 @@ fn cjson_fixture_invalid_paths_and_type_mismatches_fail() { let rc = unsafe { qjson_cursor_field( &format_type, - b"child".as_ptr() as *const i8, + b"child".as_ptr() as *const c_char, b"child".len(), nested.as_mut_ptr(), ) @@ -559,7 +559,7 @@ fn simdjson_big_integer_literals_parse_but_do_not_fit_i64() { for data in &cases[..2] { let doc = parse(data); let mut v: i64 = 0; - let rc = unsafe { qjson_get_i64(doc, b"val".as_ptr() as *const i8, b"val".len(), &mut v) }; + let rc = unsafe { qjson_get_i64(doc, b"val".as_ptr() as *const c_char, b"val".len(), &mut v) }; assert_eq!(rc, qjson_err::QJSON_OUT_OF_RANGE as c_int); unsafe { qjson_free(doc) }; } @@ -569,7 +569,7 @@ fn simdjson_big_integer_literals_parse_but_do_not_fit_i64() { let big_integer = cursor_index(&root, 1); let empty = b""; let mut v: i64 = 0; - let rc = unsafe { qjson_cursor_get_i64(&big_integer, empty.as_ptr() as *const i8, 0, &mut v) }; + let rc = unsafe { qjson_cursor_get_i64(&big_integer, empty.as_ptr() as *const c_char, 0, &mut v) }; assert_eq!(rc, qjson_err::QJSON_OUT_OF_RANGE as c_int); unsafe { qjson_free(doc) }; }