diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index a0434e0b8..0e86adc40 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -2678,6 +2678,42 @@ typedef char ZSTD_rust_create_cdict_advanced_state_layout[ == 15 * sizeof(void*) + 2 * sizeof(U32)) ? 1 : -1]; +typedef void (*ZSTD_rust_createCDictAdvancedWrapperInitParams_f)( + void* context, void* cctxParams, + const ZSTD_compressionParameters* cParams, + const void* customMem, size_t dictSize, int dictContentType); +typedef void* (*ZSTD_rust_createCDictAdvancedWrapperCreate_f)( + void* context, const void* dict, size_t dictSize, + int dictLoadMethod, int dictContentType, + const void* cctxParams, const void* customMem); +typedef struct { + void* callbackContext; + void* cctxParams; + const ZSTD_compressionParameters* cParams; + const void* customMem; + ZSTD_rust_createCDictAdvancedWrapperInitParams_f initParams; + ZSTD_rust_createCDictAdvancedWrapperCreate_f create; +} ZSTD_rust_createCDictAdvancedWrapperState; +void* ZSTD_rust_createCDictAdvancedWrapper( + const ZSTD_rust_createCDictAdvancedWrapperState* state, + const void* dict, size_t dictSize, + int dictLoadMethod, int dictContentType); +typedef char ZSTD_rust_create_cdict_advanced_wrapper_state_layout[ + (offsetof(ZSTD_rust_createCDictAdvancedWrapperState, callbackContext) == 0 + && offsetof(ZSTD_rust_createCDictAdvancedWrapperState, cctxParams) + == sizeof(void*) + && offsetof(ZSTD_rust_createCDictAdvancedWrapperState, cParams) + == 2 * sizeof(void*) + && offsetof(ZSTD_rust_createCDictAdvancedWrapperState, customMem) + == 3 * sizeof(void*) + && offsetof(ZSTD_rust_createCDictAdvancedWrapperState, initParams) + == 4 * sizeof(void*) + && offsetof(ZSTD_rust_createCDictAdvancedWrapperState, create) + == 5 * sizeof(void*) + && sizeof(ZSTD_rust_createCDictAdvancedWrapperState) + == 6 * sizeof(void*)) + ? 1 : -1]; + typedef size_t (*ZSTD_rust_compressBeginResetInternal_f)( void* context, const void* params, U64 pledgedSrcSize, size_t loadedDictSize, int zbuff); @@ -7040,6 +7076,39 @@ static void ZSTD_rust_createCDictAdvanced_free(void* context, void* cdict) ZSTD_freeCDict((ZSTD_CDict*)cdict); } +static void ZSTD_rust_createCDictAdvancedWrapper_initParams( + void* context, void* opaqueCctxParams, + const ZSTD_compressionParameters* cParams, + const void* opaqueCustomMem, size_t dictSize, int dictContentType) +{ + ZSTD_CCtx_params* const cctxParams = (ZSTD_CCtx_params*)opaqueCctxParams; + ZSTD_customMem const* const customMem = + (const ZSTD_customMem*)opaqueCustomMem; + (void)context; + ZSTD_memset(cctxParams, 0, sizeof(*cctxParams)); + DEBUGLOG(3, "ZSTD_createCDict_advanced, dictSize=%u, mode=%u", + (unsigned)dictSize, (unsigned)dictContentType); + ZSTD_CCtxParams_init(cctxParams, 0); + cctxParams->cParams = *cParams; + cctxParams->customMem = *customMem; +} + +static void* ZSTD_rust_createCDictAdvancedWrapper_create( + void* context, const void* dict, size_t dictSize, + int dictLoadMethod, int dictContentType, + const void* opaqueCctxParams, const void* opaqueCustomMem) +{ + ZSTD_customMem const* const customMem = + (const ZSTD_customMem*)opaqueCustomMem; + (void)context; + return ZSTD_createCDict_advanced2( + dict, dictSize, + (ZSTD_dictLoadMethod_e)dictLoadMethod, + (ZSTD_dictContentType_e)dictContentType, + (const ZSTD_CCtx_params*)opaqueCctxParams, + *customMem); +} + ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType, @@ -7047,15 +7116,16 @@ ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, ZSTD_customMem customMem) { ZSTD_CCtx_params cctxParams; - ZSTD_memset(&cctxParams, 0, sizeof(cctxParams)); - DEBUGLOG(3, "ZSTD_createCDict_advanced, dictSize=%u, mode=%u", (unsigned)dictSize, (unsigned)dictContentType); - ZSTD_CCtxParams_init(&cctxParams, 0); - cctxParams.cParams = cParams; - cctxParams.customMem = customMem; - return ZSTD_createCDict_advanced2( - dictBuffer, dictSize, - dictLoadMethod, dictContentType, - &cctxParams, customMem); + ZSTD_rust_createCDictAdvancedWrapperState state; + state.callbackContext = NULL; + state.cctxParams = &cctxParams; + state.cParams = &cParams; + state.customMem = &customMem; + state.initParams = ZSTD_rust_createCDictAdvancedWrapper_initParams; + state.create = ZSTD_rust_createCDictAdvancedWrapper_create; + return (ZSTD_CDict*)ZSTD_rust_createCDictAdvancedWrapper( + &state, dictBuffer, dictSize, + (int)dictLoadMethod, (int)dictContentType); } ZSTD_CDict* ZSTD_createCDict_advanced2( diff --git a/rust/src/zstd_compress.rs b/rust/src/zstd_compress.rs index faad252bd..098304439 100644 --- a/rust/src/zstd_compress.rs +++ b/rust/src/zstd_compress.rs @@ -2224,6 +2224,100 @@ pub unsafe extern "C" fn ZSTD_rust_createCCtx( cctx } +type CreateCDictAdvancedWrapperInitParamsFn = unsafe extern "C" fn( + *mut c_void, + *mut c_void, + *const ZSTD_compressionParameters, + *const c_void, + usize, + c_int, +); +type CreateCDictAdvancedWrapperCreateFn = unsafe extern "C" fn( + *mut c_void, + *const c_void, + usize, + c_int, + c_int, + *const c_void, + *const c_void, +) -> *mut c_void; + +/// Explicit projection for the public heap-CDict wrapper. +/// +/// Rust owns the wrapper's preparation-to-construction ordering and forwards +/// the dictionary scalars. C retains the private `ZSTD_CCtx_params` setup and +/// the advanced-CDict implementation behind callbacks; allocation and +/// workspace ownership stay in the existing advanced2 path. +#[repr(C)] +pub struct ZSTD_rust_createCDictAdvancedWrapperState { + callback_context: *mut c_void, + cctx_params: *mut c_void, + c_params: *const ZSTD_compressionParameters, + custom_mem: *const c_void, + init_params: CreateCDictAdvancedWrapperInitParamsFn, + create: CreateCDictAdvancedWrapperCreateFn, +} + +const _: () = { + assert!(offset_of!(ZSTD_rust_createCDictAdvancedWrapperState, callback_context) == 0); + assert!( + offset_of!(ZSTD_rust_createCDictAdvancedWrapperState, cctx_params) == size_of::() + ); + assert!( + offset_of!(ZSTD_rust_createCDictAdvancedWrapperState, c_params) == 2 * size_of::() + ); + assert!( + offset_of!(ZSTD_rust_createCDictAdvancedWrapperState, custom_mem) == 3 * size_of::() + ); + assert!( + offset_of!(ZSTD_rust_createCDictAdvancedWrapperState, init_params) + == 4 * size_of::() + ); + assert!( + offset_of!(ZSTD_rust_createCDictAdvancedWrapperState, create) == 5 * size_of::() + ); + assert!(size_of::() == size_of::<[usize; 6]>()); +}; + +/// Prepare a heap-CDict parameter object, then enter the existing advanced +/// construction path in the original callback order. +#[no_mangle] +pub unsafe extern "C" fn ZSTD_rust_createCDictAdvancedWrapper( + state: *const ZSTD_rust_createCDictAdvancedWrapperState, + dict: *const c_void, + dict_size: usize, + dict_load_method: c_int, + dict_content_type: c_int, +) -> *mut c_void { + if state.is_null() { + return ptr::null_mut(); + } + let state = unsafe { &*state }; + if state.cctx_params.is_null() || state.c_params.is_null() || state.custom_mem.is_null() { + return ptr::null_mut(); + } + + unsafe { + (state.init_params)( + state.callback_context, + state.cctx_params, + state.c_params, + state.custom_mem, + dict_size, + dict_content_type, + ); + (state.create)( + state.callback_context, + dict, + dict_size, + dict_load_method, + dict_content_type, + state.cctx_params, + state.custom_mem, + ) + } +} + type InitStaticCCtxFn = unsafe extern "C" fn(*mut c_void) -> *mut c_void; const ZSTD_STATIC_WORKSPACE_ALIGNMENT: usize = 8; @@ -17800,6 +17894,134 @@ mod tests { assert!(context.initialized.is_null()); } + #[derive(Default)] + struct CreateCDictAdvancedWrapperTestContext { + events: Vec<&'static str>, + init_context: *mut c_void, + init_cctx_params: *mut c_void, + init_c_params: *const ZSTD_compressionParameters, + init_custom_mem: *const c_void, + init_dict_size: usize, + init_dict_content_type: c_int, + create_context: *mut c_void, + create_dict: *const c_void, + create_dict_size: usize, + create_dict_load_method: c_int, + create_dict_content_type: c_int, + create_cctx_params: *const c_void, + create_custom_mem: *const c_void, + result: *mut c_void, + } + + unsafe extern "C" fn create_cdict_advanced_wrapper_test_init( + context: *mut c_void, + cctx_params: *mut c_void, + c_params: *const ZSTD_compressionParameters, + custom_mem: *const c_void, + dict_size: usize, + dict_content_type: c_int, + ) { + let context = unsafe { &mut *context.cast::() }; + context.events.push("init"); + context.init_context = context as *mut _ as *mut c_void; + context.init_cctx_params = cctx_params; + context.init_c_params = c_params; + context.init_custom_mem = custom_mem; + context.init_dict_size = dict_size; + context.init_dict_content_type = dict_content_type; + } + + unsafe extern "C" fn create_cdict_advanced_wrapper_test_create( + context: *mut c_void, + dict: *const c_void, + dict_size: usize, + dict_load_method: c_int, + dict_content_type: c_int, + cctx_params: *const c_void, + custom_mem: *const c_void, + ) -> *mut c_void { + let context = unsafe { &mut *context.cast::() }; + context.events.push("create"); + context.create_context = context as *mut _ as *mut c_void; + context.create_dict = dict; + context.create_dict_size = dict_size; + context.create_dict_load_method = dict_load_method; + context.create_dict_content_type = dict_content_type; + context.create_cctx_params = cctx_params; + context.create_custom_mem = custom_mem; + context.result + } + + fn create_cdict_advanced_wrapper_test_state( + context: &mut CreateCDictAdvancedWrapperTestContext, + cctx_params: *mut c_void, + c_params: *const ZSTD_compressionParameters, + custom_mem: *const c_void, + ) -> ZSTD_rust_createCDictAdvancedWrapperState { + ZSTD_rust_createCDictAdvancedWrapperState { + callback_context: context as *mut _ as *mut c_void, + cctx_params, + c_params, + custom_mem, + init_params: create_cdict_advanced_wrapper_test_init, + create: create_cdict_advanced_wrapper_test_create, + } + } + + #[test] + fn create_cdict_advanced_wrapper_preserves_prepare_then_create_order() { + let mut context = CreateCDictAdvancedWrapperTestContext { + result: ptr::dangling_mut(), + ..Default::default() + }; + let cctx_params = ptr::dangling_mut::(); + let c_params = ptr::dangling::(); + let custom_mem = ptr::dangling::(); + let dict = ptr::dangling::().cast::(); + let state = create_cdict_advanced_wrapper_test_state( + &mut context, + cctx_params, + c_params, + custom_mem, + ); + + let result = unsafe { ZSTD_rust_createCDictAdvancedWrapper(&state, dict, 123, 1, 2) }; + + assert_eq!(result, context.result); + assert_eq!(context.events, ["init", "create"]); + assert_eq!(context.init_context, state.callback_context); + assert_eq!(context.init_cctx_params, cctx_params); + assert_eq!(context.init_c_params, c_params); + assert_eq!(context.init_custom_mem, custom_mem); + assert_eq!(context.init_dict_size, 123); + assert_eq!(context.init_dict_content_type, 2); + assert_eq!(context.create_context, state.callback_context); + assert_eq!(context.create_dict, dict); + assert_eq!(context.create_dict_size, 123); + assert_eq!(context.create_dict_load_method, 1); + assert_eq!(context.create_dict_content_type, 2); + assert_eq!(context.create_cctx_params, cctx_params); + assert_eq!(context.create_custom_mem, custom_mem); + } + + #[test] + fn create_cdict_advanced_wrapper_rejects_missing_parameter_storage() { + let mut context = CreateCDictAdvancedWrapperTestContext::default(); + let c_params = ptr::dangling::(); + let custom_mem = ptr::dangling::(); + let state = create_cdict_advanced_wrapper_test_state( + &mut context, + ptr::null_mut(), + c_params, + custom_mem, + ); + + let result = unsafe { ZSTD_rust_createCDictAdvancedWrapper(&state, ptr::null(), 0, 0, 0) }; + + assert!(result.is_null()); + assert!(context.events.is_empty()); + } + #[derive(Default)] struct InitCCtxTestContext { events: Vec<&'static str>,