diff --git a/programs/fileio.c b/programs/fileio.c index 3a278125e..952142a48 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -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, diff --git a/rust/src/fileio_prefs.rs b/rust/src/fileio_prefs.rs index d88dc08ef..abb2f1d1b 100644 --- a/rust/src/fileio_prefs.rs +++ b/rust/src/fileio_prefs.rs @@ -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::() + ); + assert_eq!( + size_of::(), + input_word + 2 * size_of::() + ); + 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::() + ); + assert_eq!( + size_of::(), + output_word + 2 * size_of::() + ); + + 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::(), + source.len(), + 1, + ); + FIO_rust_setOutBuffer( + &mut output, + destination.as_mut_ptr().cast::(), + destination.len(), + 2, + ); + } + + assert_eq!(input.src, source.as_ptr().cast::()); + assert_eq!(input.size, source.len()); + assert_eq!(input.pos, 1); + assert_eq!(output.dst, destination.as_mut_ptr().cast::()); + 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::();