refactor(compress): move CCtx estimate tier policy to Rust
Move the fixed source-size tier traversal used by ZSTD_estimateCCtxSize_internal() into Rust. C retains the authoritative parameter lookup and per-tier workspace estimator behind callbacks, while Rust owns the tier ordering and maximum-selection policy. The projection includes ABI layout assertions and tests for callback order, level propagation, and error-valued maxima. Test Plan: - `ulimit -v 41943040; cargo +nightly fmt --manifest-path rust/Cargo.toml --all -- --check` - `ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo clippy --manifest-path rust/Cargo.toml --all-targets -- -D warnings` - `ulimit -v 41943040; make -j1` - `ulimit -v 41943040; make -j1 -C tests test` - `ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo clippy --manifest-path rust/cli/Cargo.toml --all-targets -- -D warnings` - `ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo test --manifest-path rust/cli/Cargo.toml --all-targets` The integrated checks ran at the combined working-tree tip under a serial 40 GiB virtual-memory limit. Standalone root Rust unit linking remains unavailable because the crate imports C-owned bridge symbols without a Cargo build/link setup.
This commit is contained in:
@@ -8588,6 +8588,57 @@ fn max_estimate_cctx_size(
|
||||
estimate0.max(estimate1).max(estimate2).max(estimate3)
|
||||
}
|
||||
|
||||
type EstimateCCtxSizeGetCParamsFn =
|
||||
unsafe extern "C" fn(*mut c_void, c_int, u64) -> ZSTD_compressionParameters;
|
||||
type EstimateCCtxSizeEstimateFn =
|
||||
unsafe extern "C" fn(*mut c_void, ZSTD_compressionParameters) -> usize;
|
||||
|
||||
/// Rust owns the fixed source-size tier policy for CCtx estimates. C keeps
|
||||
/// the configuration-sensitive parameter lookup and workspace estimator behind
|
||||
/// callbacks, so this seam does not expose any private context layout.
|
||||
#[repr(C)]
|
||||
pub struct ZSTD_rust_estimateCCtxSizeState {
|
||||
callback_context: *mut c_void,
|
||||
compression_level: c_int,
|
||||
get_c_params: EstimateCCtxSizeGetCParamsFn,
|
||||
estimate: EstimateCCtxSizeEstimateFn,
|
||||
}
|
||||
|
||||
const _: () = {
|
||||
assert!(offset_of!(ZSTD_rust_estimateCCtxSizeState, callback_context) == 0);
|
||||
assert!(offset_of!(ZSTD_rust_estimateCCtxSizeState, compression_level) == size_of::<usize>());
|
||||
assert!(offset_of!(ZSTD_rust_estimateCCtxSizeState, get_c_params) == 2 * size_of::<usize>());
|
||||
assert!(offset_of!(ZSTD_rust_estimateCCtxSizeState, estimate) == 3 * size_of::<usize>());
|
||||
assert!(size_of::<ZSTD_rust_estimateCCtxSizeState>() == 4 * size_of::<usize>());
|
||||
};
|
||||
|
||||
/// Evaluate the four source-size tiers used by `ZSTD_estimateCCtxSize()` and
|
||||
/// return the largest raw result, including size_t-encoded error values.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn ZSTD_rust_estimateCCtxSizeInternal(
|
||||
state: *const ZSTD_rust_estimateCCtxSizeState,
|
||||
) -> usize {
|
||||
if state.is_null() {
|
||||
return ERROR(ZstdErrorCode::Generic);
|
||||
}
|
||||
|
||||
let state = unsafe { &*state };
|
||||
let source_size_tiers = [16 * 1024, 128 * 1024, 256 * 1024, ZSTD_CONTENTSIZE_UNKNOWN];
|
||||
let mut estimates = [0usize; 4];
|
||||
for (estimate, &source_size_hint) in estimates.iter_mut().zip(source_size_tiers.iter()) {
|
||||
let c_params = unsafe {
|
||||
(state.get_c_params)(
|
||||
state.callback_context,
|
||||
state.compression_level,
|
||||
source_size_hint,
|
||||
)
|
||||
};
|
||||
*estimate = unsafe { (state.estimate)(state.callback_context, c_params) };
|
||||
}
|
||||
|
||||
max_estimate_cctx_size(estimates[0], estimates[1], estimates[2], estimates[3])
|
||||
}
|
||||
|
||||
/// Return the largest raw estimate, including any C size_t error values.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn ZSTD_rust_maxEstimateCCtxSize(
|
||||
@@ -10177,6 +10228,41 @@ mod tests {
|
||||
const ZSTD_BTOPT: c_int = 7;
|
||||
const ZSTD_BTULTRA2: c_int = 9;
|
||||
|
||||
struct EstimateCCtxSizeTestContext {
|
||||
compression_levels: Vec<c_int>,
|
||||
source_size_hints: Vec<u64>,
|
||||
parameter_tiers: Vec<u32>,
|
||||
}
|
||||
|
||||
unsafe extern "C" fn estimate_cctx_size_test_get_c_params(
|
||||
context: *mut c_void,
|
||||
compression_level: c_int,
|
||||
source_size_hint: u64,
|
||||
) -> ZSTD_compressionParameters {
|
||||
let context = unsafe { &mut *(context.cast::<EstimateCCtxSizeTestContext>()) };
|
||||
context.compression_levels.push(compression_level);
|
||||
context.source_size_hints.push(source_size_hint);
|
||||
ZSTD_compressionParameters {
|
||||
windowLog: context.source_size_hints.len() as u32,
|
||||
..ZSTD_compressionParameters::default()
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn estimate_cctx_size_test_estimate(
|
||||
context: *mut c_void,
|
||||
c_params: ZSTD_compressionParameters,
|
||||
) -> usize {
|
||||
let context = unsafe { &mut *(context.cast::<EstimateCCtxSizeTestContext>()) };
|
||||
context.parameter_tiers.push(c_params.windowLog);
|
||||
match c_params.windowLog {
|
||||
1 => 17,
|
||||
2 => 91,
|
||||
3 => 23,
|
||||
4 => 67,
|
||||
_ => ERROR(ZstdErrorCode::Generic),
|
||||
}
|
||||
}
|
||||
|
||||
struct GenerateSequencesTestContext {
|
||||
events: Vec<&'static str>,
|
||||
target_c_block_size: c_int,
|
||||
@@ -19906,6 +19992,37 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn estimate_cctx_size_internal_preserves_tier_order_and_max_policy() {
|
||||
let mut context = EstimateCCtxSizeTestContext {
|
||||
compression_levels: Vec::new(),
|
||||
source_size_hints: Vec::new(),
|
||||
parameter_tiers: Vec::new(),
|
||||
};
|
||||
let state = ZSTD_rust_estimateCCtxSizeState {
|
||||
callback_context: (&mut context as *mut EstimateCCtxSizeTestContext).cast(),
|
||||
compression_level: 7,
|
||||
get_c_params: estimate_cctx_size_test_get_c_params,
|
||||
estimate: estimate_cctx_size_test_estimate,
|
||||
};
|
||||
|
||||
assert_eq!(unsafe { ZSTD_rust_estimateCCtxSizeInternal(&state) }, 91);
|
||||
assert_eq!(context.compression_levels, vec![7; 4]);
|
||||
assert_eq!(
|
||||
context.source_size_hints,
|
||||
vec![16 * 1024, 128 * 1024, 256 * 1024, ZSTD_CONTENTSIZE_UNKNOWN]
|
||||
);
|
||||
assert_eq!(context.parameter_tiers, vec![1, 2, 3, 4]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn estimate_cctx_size_internal_rejects_a_null_state() {
|
||||
assert_eq!(
|
||||
unsafe { ZSTD_rust_estimateCCtxSizeInternal(ptr::null()) },
|
||||
ERROR(ZstdErrorCode::Generic)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn public_one_shot_abi_is_c_compatible() {
|
||||
let entry: unsafe extern "C" fn(*mut c_void, usize, *const c_void, usize, c_int) -> usize =
|
||||
|
||||
Reference in New Issue
Block a user