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:
@@ -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>();
|
||||
|
||||
Reference in New Issue
Block a user