feat(rust): add common primitive compatibility layer

Introduce the Rust static library and move the shared byte, bitstream, CPU,
error, xxHash, debug, and public-common implementations into it. Thin C shims
preserve the existing header-driven C build while original tests link the Rust
archive.

This establishes the ABI-safe foundation for later codec and CLI ports;
entropy coding, runtime support, codecs, dictionaries, and the CLI remain C.
The top-down migration map documents that boundary and its validation path.

Test Plan:
- cargo fmt --check
- cargo test --all-targets
- cargo clippy --all-targets -- -D warnings
- cargo build --release

Refs: rust/README.md
This commit is contained in:
2026-07-10 20:02:17 +02:00
parent f8745da6ff
commit 089f8e5b4d
18 changed files with 2270 additions and 136 deletions
+121
View File
@@ -0,0 +1,121 @@
#![allow(non_snake_case)]
use crate::mem::*;
#[inline]
pub fn ZSTD_isPower2(u: usize) -> bool {
(u & (u.wrapping_sub(1))) == 0
}
#[inline]
pub fn ZSTD_countTrailingZeros32(val: U32) -> u32 {
assert!(val != 0);
val.trailing_zeros()
}
#[inline]
pub fn ZSTD_countLeadingZeros32(val: U32) -> u32 {
assert!(val != 0);
val.leading_zeros()
}
#[inline]
pub fn ZSTD_countTrailingZeros64(val: U64) -> u32 {
assert!(val != 0);
val.trailing_zeros()
}
#[inline]
pub fn ZSTD_countLeadingZeros64(val: U64) -> u32 {
assert!(val != 0);
val.leading_zeros()
}
#[inline]
pub fn ZSTD_NbCommonBytes(val: usize) -> u32 {
if MEM_isLittleEndian() {
if MEM_64bits() {
ZSTD_countTrailingZeros64(val as U64) >> 3
} else {
ZSTD_countTrailingZeros32(val as U32) >> 3
}
} else {
if MEM_64bits() {
ZSTD_countLeadingZeros64(val as U64) >> 3
} else {
ZSTD_countLeadingZeros32(val as U32) >> 3
}
}
}
#[inline]
pub fn ZSTD_highbit32(val: U32) -> u32 {
assert!(val != 0);
31 - ZSTD_countLeadingZeros32(val)
}
#[inline]
pub fn ZSTD_rotateRight_U64(value: U64, count: U32) -> U64 {
assert!(count < 64);
value.rotate_right(count)
}
#[inline]
pub fn ZSTD_rotateRight_U32(value: U32, count: U32) -> U32 {
assert!(count < 32);
value.rotate_right(count)
}
#[inline]
pub fn ZSTD_rotateRight_U16(value: U16, count: U32) -> U16 {
assert!(count < 16);
value.rotate_right(count)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn power_of_two_matches_the_c_helper() {
assert!(ZSTD_isPower2(0));
assert!(ZSTD_isPower2(1));
assert!(ZSTD_isPower2(1 << 20));
assert!(!ZSTD_isPower2(3));
assert!(!ZSTD_isPower2((1 << 20) + 1));
}
#[test]
fn bit_counts_cover_both_ends() {
assert_eq!(ZSTD_countTrailingZeros32(1), 0);
assert_eq!(ZSTD_countTrailingZeros32(1 << 31), 31);
assert_eq!(ZSTD_countLeadingZeros32(1), 31);
assert_eq!(ZSTD_countLeadingZeros32(1 << 31), 0);
assert_eq!(ZSTD_countTrailingZeros64(1), 0);
assert_eq!(ZSTD_countTrailingZeros64(1 << 63), 63);
assert_eq!(ZSTD_countLeadingZeros64(1), 63);
assert_eq!(ZSTD_countLeadingZeros64(1 << 63), 0);
assert_eq!(ZSTD_highbit32(1), 0);
assert_eq!(ZSTD_highbit32(1 << 31), 31);
}
#[test]
fn common_bytes_are_counted_in_memory_order() {
if MEM_isLittleEndian() {
assert_eq!(ZSTD_NbCommonBytes(0x0000_0000_0001_0000), 2);
} else if MEM_64bits() {
assert_eq!(ZSTD_NbCommonBytes(0x0001_0000_0000_0000), 2);
} else {
assert_eq!(ZSTD_NbCommonBytes(0x0001_0000), 2);
}
}
#[test]
fn rotations_match_expected_wraparound() {
assert_eq!(ZSTD_rotateRight_U16(0x1234, 4), 0x4123);
assert_eq!(ZSTD_rotateRight_U32(0x1234_5678, 8), 0x7812_3456);
assert_eq!(
ZSTD_rotateRight_U64(0x0123_4567_89ab_cdef, 16),
0xcdef_0123_4567_89ab
);
}
}