feat(fileio): move buffer helpers to Rust

Route file-I/O input/output buffer construction and the LZ4 block-size mapping through Rust ABI leaves while preserving the existing C helper names and public buffer layouts. Add layout, field, and formula coverage.

Test Plan: cargo test --manifest-path rust/cli/Cargo.toml --no-default-features --features cli,compression,decompression,benchmark; cargo clippy --manifest-path rust/cli/Cargo.toml --all-targets --no-default-features --features cli,compression,decompression,benchmark; make -B -C programs -j2 zstd zstd-small zstd-frugal; make -B -C tests -j2 test-cli-tests
This commit is contained in:
2026-07-18 03:54:20 +02:00
parent 429d5176e9
commit 309e227731
2 changed files with 142 additions and 7 deletions
+11 -7
View File
@@ -309,6 +309,11 @@ static int FIO_shouldDisplayMultipleFileSummary(FIO_ctx_t const* fCtx)
int FIO_rust_checkFilenameCollisions(const char** filenameTable, unsigned nbFiles);
unsigned FIO_rust_highbit64(unsigned long long v);
unsigned long long FIO_rust_getLargestFileSize(const char** inFileNames, unsigned nbFiles);
void FIO_rust_setInBuffer(ZSTD_inBuffer* output, const void* buf, size_t s, size_t pos);
void FIO_rust_setOutBuffer(ZSTD_outBuffer* output, void* buf, size_t s, size_t pos);
#ifdef ZSTD_LZ4COMPRESS
int FIO_rust_LZ4_GetBlockSize_FromBlockId(int id);
#endif
/*-*************************************
@@ -792,18 +797,14 @@ static int FIO_multiFilesConcatWarning(const FIO_ctx_t* fCtx, FIO_prefs_t* prefs
static ZSTD_inBuffer setInBuffer(const void* buf, size_t s, size_t pos)
{
ZSTD_inBuffer i;
i.src = buf;
i.size = s;
i.pos = pos;
FIO_rust_setInBuffer(&i, buf, s, pos);
return i;
}
static ZSTD_outBuffer setOutBuffer(void* buf, size_t s, size_t pos)
{
ZSTD_outBuffer o;
o.dst = buf;
o.size = s;
o.pos = pos;
FIO_rust_setOutBuffer(&o, buf, s, pos);
return o;
}
@@ -1140,7 +1141,10 @@ FIO_compressLzmaFrame(cRess_t* ress,
#define LZ4F_max64KB max64KB
#endif
static int FIO_LZ4_GetBlockSize_FromBlockId (int id) { return (1 << (8 + (2 * id))); }
static int FIO_LZ4_GetBlockSize_FromBlockId (int id)
{
return FIO_rust_LZ4_GetBlockSize_FromBlockId(id);
}
static unsigned long long
FIO_compressLz4Frame(cRess_t* ress,
+131
View File
@@ -20,6 +20,20 @@ const FIO_ZSTD_COMPRESSION: c_int = 0;
const FIO_OVERLAP_LOG_NOTSET: c_int = 9999;
const FIO_LDM_PARAM_NOTSET: c_int = 9999;
#[repr(C)]
pub struct FIO_inBuffer {
src: *const c_void,
size: usize,
pos: usize,
}
#[repr(C)]
pub struct FIO_outBuffer {
dst: *mut c_void,
size: usize,
pos: usize,
}
#[cfg(target_vendor = "apple")]
const ZSTD_SPARSE_DEFAULT: c_int = 0;
#[cfg(not(target_vendor = "apple"))]
@@ -517,6 +531,53 @@ pub unsafe extern "C" fn FIO_rust_getLargestFileSize(
)
}
/// Fill a C-compatible input buffer through an output pointer.
///
/// The pointer form avoids relying on a cross-language struct return ABI while
/// retaining the public `ZSTD_inBuffer` field order and values.
#[no_mangle]
pub unsafe extern "C" fn FIO_rust_setInBuffer(
output: *mut FIO_inBuffer,
buf: *const c_void,
size: usize,
pos: usize,
) {
unsafe {
output.write(FIO_inBuffer {
src: buf,
size,
pos,
});
}
}
/// Fill a C-compatible output buffer through an output pointer.
#[no_mangle]
pub unsafe extern "C" fn FIO_rust_setOutBuffer(
output: *mut FIO_outBuffer,
buf: *mut c_void,
size: usize,
pos: usize,
) {
unsafe {
output.write(FIO_outBuffer {
dst: buf,
size,
pos,
});
}
}
#[inline]
fn lz4_block_size_from_block_id(id: c_int) -> c_int {
1 << (8 + 2 * id)
}
#[no_mangle]
pub extern "C" fn FIO_rust_LZ4_GetBlockSize_FromBlockId(id: c_int) -> c_int {
lz4_block_size_from_block_id(id)
}
#[inline]
fn filename_path_separator() -> u8 {
if cfg!(windows) {
@@ -650,6 +711,76 @@ mod tests {
);
}
#[test]
fn buffer_shims_preserve_fields_and_c_layout() {
let input_word = size_of::<*const c_void>();
let output_word = size_of::<*mut c_void>();
assert_eq!(offset_of!(FIO_inBuffer, src), 0);
assert_eq!(offset_of!(FIO_inBuffer, size), input_word);
assert_eq!(
offset_of!(FIO_inBuffer, pos),
input_word + size_of::<usize>()
);
assert_eq!(
size_of::<FIO_inBuffer>(),
input_word + 2 * size_of::<usize>()
);
assert_eq!(offset_of!(FIO_outBuffer, dst), 0);
assert_eq!(offset_of!(FIO_outBuffer, size), output_word);
assert_eq!(
offset_of!(FIO_outBuffer, pos),
output_word + size_of::<usize>()
);
assert_eq!(
size_of::<FIO_outBuffer>(),
output_word + 2 * size_of::<usize>()
);
let source = [1u8, 2, 3, 4];
let mut destination = [0u8; 8];
let mut input = FIO_inBuffer {
src: ptr::null(),
size: 0,
pos: 0,
};
let mut output = FIO_outBuffer {
dst: ptr::null_mut(),
size: 0,
pos: 0,
};
unsafe {
FIO_rust_setInBuffer(
&mut input,
source.as_ptr().cast::<c_void>(),
source.len(),
1,
);
FIO_rust_setOutBuffer(
&mut output,
destination.as_mut_ptr().cast::<c_void>(),
destination.len(),
2,
);
}
assert_eq!(input.src, source.as_ptr().cast::<c_void>());
assert_eq!(input.size, source.len());
assert_eq!(input.pos, 1);
assert_eq!(output.dst, destination.as_mut_ptr().cast::<c_void>());
assert_eq!(output.size, destination.len());
assert_eq!(output.pos, 2);
}
#[test]
fn lz4_block_size_shim_preserves_the_block_id_formula() {
assert_eq!(FIO_rust_LZ4_GetBlockSize_FromBlockId(0), 1 << 8);
assert_eq!(FIO_rust_LZ4_GetBlockSize_FromBlockId(1), 1 << 10);
assert_eq!(FIO_rust_LZ4_GetBlockSize_FromBlockId(3), 1 << 14);
assert_eq!(FIO_rust_LZ4_GetBlockSize_FromBlockId(4), 1 << 16);
}
#[test]
fn c_layouts_match_the_headers() {
let word = size_of::<usize>();