feat(compress): move stream2 fallback orchestration to Rust
The public ZSTD_compressStream2_c entry point still contained the complete fallback state machine even though its validation, initialization policy, serial-versus-MT dispatch, and result accounting were already represented by Rust policy helpers. That left the main streaming entry point as a large C orchestration island and made the Rust rewrite boundary misleading. Project the scalar stream state and private CCtx operations through a checked C ABI, then let Rust own the fallback ordering. Rust now validates buffers and the end directive, handles transparent one-shot completion and stable-input deferral, performs the initialization and stability decisions, selects the serial or MT path, and publishes the result policy. C retains the private context layout, stream adapter, MT operations, checksum/epilogue side effects, and trace/reset callbacks. ABI offset assertions and focused callback-order and stable-input tests protect the projection without requiring a standalone Rust test binary to link every C bridge symbol. Test Plan: - `ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo +nightly fmt --manifest-path rust/Cargo.toml --all` -- passed. - `ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo clippy --manifest-path rust/Cargo.toml --all-targets -- -D warnings` -- passed before and after formatting. - `git diff --cached --check` -- passed. - Native `make -j1` and the original suite remain the next post-commit verification gates.
This commit is contained in:
+176
-145
@@ -1042,6 +1042,109 @@ typedef char ZSTD_rust_compress_stream2_mt_coordinator_state_layout[
|
||||
&& sizeof(ZSTD_rust_compressStream2MTCoordinatorState)
|
||||
== 6 * sizeof(void*))
|
||||
? 1 : -1];
|
||||
typedef size_t (*ZSTD_rust_compressStream2Init_f)(
|
||||
void* context, int endOp, size_t inputSize);
|
||||
typedef size_t (*ZSTD_rust_compressStream2CheckBuffer_f)(
|
||||
void* context, const void* output, const void* input);
|
||||
typedef size_t (*ZSTD_rust_compressStream2Stream_f)(
|
||||
void* context, ZSTD_outBuffer* output, ZSTD_inBuffer* input, int endOp);
|
||||
typedef void (*ZSTD_rust_compressStream2UpdateMT_f)(void* context);
|
||||
typedef struct {
|
||||
void* callbackContext;
|
||||
ZSTD_outBuffer* output;
|
||||
ZSTD_inBuffer* input;
|
||||
int* streamStage;
|
||||
size_t* stableInNotConsumed;
|
||||
ZSTD_inBuffer* expectedInBuffer;
|
||||
unsigned* simpleCompress2Completed;
|
||||
int* cParamsChanged;
|
||||
const size_t* outBuffContentSize;
|
||||
const size_t* outBuffFlushedSize;
|
||||
unsigned long long pledgedSrcSizePlusOne;
|
||||
int inBufferMode;
|
||||
int outBufferMode;
|
||||
int format;
|
||||
int nbWorkers;
|
||||
} ZSTD_rust_compressStream2Fields;
|
||||
typedef struct {
|
||||
ZSTD_rust_compressStream2Init_f initCompressStream2;
|
||||
ZSTD_rust_compressStream2CheckBuffer_f checkBufferStability;
|
||||
ZSTD_rust_compressStream2SetBufferExpectations_f setBufferExpectations;
|
||||
ZSTD_rust_compressStream2Stream_f compressStream;
|
||||
ZSTD_rust_compressStream2UpdateMT_f updateMTCParams;
|
||||
ZSTD_rust_compressStream2MTStep_f mtStep;
|
||||
ZSTD_rust_compressStream2MTTrace_f mtTrace;
|
||||
ZSTD_rust_compressStream2MTReset_f mtReset;
|
||||
} ZSTD_rust_compressStream2Callbacks;
|
||||
typedef struct {
|
||||
const ZSTD_rust_compressStream2Fields* fields;
|
||||
const ZSTD_rust_compressStream2Callbacks* callbacks;
|
||||
int endOp;
|
||||
} ZSTD_rust_compressStream2State;
|
||||
size_t ZSTD_rust_compressStream2(
|
||||
const ZSTD_rust_compressStream2State* state);
|
||||
typedef char ZSTD_rust_compress_stream2_fields_layout[
|
||||
(offsetof(ZSTD_rust_compressStream2Fields, callbackContext) == 0
|
||||
&& offsetof(ZSTD_rust_compressStream2Fields, output)
|
||||
== sizeof(void*)
|
||||
&& offsetof(ZSTD_rust_compressStream2Fields, input)
|
||||
== 2 * sizeof(void*)
|
||||
&& offsetof(ZSTD_rust_compressStream2Fields, streamStage)
|
||||
== 3 * sizeof(void*)
|
||||
&& offsetof(ZSTD_rust_compressStream2Fields, stableInNotConsumed)
|
||||
== 4 * sizeof(void*)
|
||||
&& offsetof(ZSTD_rust_compressStream2Fields, expectedInBuffer)
|
||||
== 5 * sizeof(void*)
|
||||
&& offsetof(ZSTD_rust_compressStream2Fields, simpleCompress2Completed)
|
||||
== 6 * sizeof(void*)
|
||||
&& offsetof(ZSTD_rust_compressStream2Fields, cParamsChanged)
|
||||
== 7 * sizeof(void*)
|
||||
&& offsetof(ZSTD_rust_compressStream2Fields, outBuffContentSize)
|
||||
== 8 * sizeof(void*)
|
||||
&& offsetof(ZSTD_rust_compressStream2Fields, outBuffFlushedSize)
|
||||
== 9 * sizeof(void*)
|
||||
&& offsetof(ZSTD_rust_compressStream2Fields, pledgedSrcSizePlusOne)
|
||||
== 10 * sizeof(void*)
|
||||
&& offsetof(ZSTD_rust_compressStream2Fields, inBufferMode)
|
||||
== 10 * sizeof(void*) + sizeof(unsigned long long)
|
||||
&& offsetof(ZSTD_rust_compressStream2Fields, outBufferMode)
|
||||
== 10 * sizeof(void*) + sizeof(unsigned long long) + sizeof(int)
|
||||
&& offsetof(ZSTD_rust_compressStream2Fields, format)
|
||||
== 10 * sizeof(void*) + sizeof(unsigned long long) + 2 * sizeof(int)
|
||||
&& offsetof(ZSTD_rust_compressStream2Fields, nbWorkers)
|
||||
== 10 * sizeof(void*) + sizeof(unsigned long long) + 3 * sizeof(int)
|
||||
&& sizeof(ZSTD_rust_compressStream2Fields)
|
||||
== ((10 * sizeof(void*) + sizeof(unsigned long long) + 4 * sizeof(int)
|
||||
+ sizeof(void*) - 1) / sizeof(void*)) * sizeof(void*))
|
||||
? 1 : -1];
|
||||
typedef char ZSTD_rust_compress_stream2_callbacks_layout[
|
||||
(offsetof(ZSTD_rust_compressStream2Callbacks, initCompressStream2) == 0
|
||||
&& offsetof(ZSTD_rust_compressStream2Callbacks, checkBufferStability)
|
||||
== sizeof(void*)
|
||||
&& offsetof(ZSTD_rust_compressStream2Callbacks, setBufferExpectations)
|
||||
== 2 * sizeof(void*)
|
||||
&& offsetof(ZSTD_rust_compressStream2Callbacks, compressStream)
|
||||
== 3 * sizeof(void*)
|
||||
&& offsetof(ZSTD_rust_compressStream2Callbacks, updateMTCParams)
|
||||
== 4 * sizeof(void*)
|
||||
&& offsetof(ZSTD_rust_compressStream2Callbacks, mtStep)
|
||||
== 5 * sizeof(void*)
|
||||
&& offsetof(ZSTD_rust_compressStream2Callbacks, mtTrace)
|
||||
== 6 * sizeof(void*)
|
||||
&& offsetof(ZSTD_rust_compressStream2Callbacks, mtReset)
|
||||
== 7 * sizeof(void*)
|
||||
&& sizeof(ZSTD_rust_compressStream2Callbacks) == 8 * sizeof(void*))
|
||||
? 1 : -1];
|
||||
typedef char ZSTD_rust_compress_stream2_state_layout[
|
||||
(offsetof(ZSTD_rust_compressStream2State, fields) == 0
|
||||
&& offsetof(ZSTD_rust_compressStream2State, callbacks)
|
||||
== sizeof(void*)
|
||||
&& offsetof(ZSTD_rust_compressStream2State, endOp)
|
||||
== 2 * sizeof(void*)
|
||||
&& sizeof(ZSTD_rust_compressStream2State)
|
||||
== ((2 * sizeof(void*) + sizeof(int) + sizeof(void*) - 1)
|
||||
/ sizeof(void*)) * sizeof(void*))
|
||||
? 1 : -1];
|
||||
int ZSTD_rust_simpleCompress2Level(const void* cctx, size_t srcSize);
|
||||
typedef struct {
|
||||
int format;
|
||||
@@ -8769,157 +8872,85 @@ static size_t ZSTD_rust_compressStream2MT_step(
|
||||
}
|
||||
#endif /* ZSTD_MULTITHREAD */
|
||||
|
||||
static size_t ZSTD_rust_compressStream2_init(void* context, int endOp, size_t inputSize)
|
||||
{
|
||||
return ZSTD_CCtx_init_compressStream2(
|
||||
(ZSTD_CCtx*)context, (ZSTD_EndDirective)endOp, inputSize);
|
||||
}
|
||||
|
||||
static size_t ZSTD_rust_compressStream2_checkBuffer(
|
||||
void* context, const void* output, const void* input)
|
||||
{
|
||||
return ZSTD_checkBufferStability(
|
||||
(const ZSTD_CCtx*)context,
|
||||
(const ZSTD_outBuffer*)output,
|
||||
(const ZSTD_inBuffer*)input);
|
||||
}
|
||||
|
||||
static size_t ZSTD_rust_compressStream2_compressStream(
|
||||
void* context, ZSTD_outBuffer* output, ZSTD_inBuffer* input, int endOp)
|
||||
{
|
||||
return ZSTD_compressStream_generic(
|
||||
(ZSTD_CStream*)context, output, input, (ZSTD_EndDirective)endOp);
|
||||
}
|
||||
|
||||
#ifdef ZSTD_MULTITHREAD
|
||||
static void ZSTD_rust_compressStream2_updateMTCParams(void* context)
|
||||
{
|
||||
ZSTD_CCtx* const cctx = (ZSTD_CCtx*)context;
|
||||
ZSTDMT_updateCParams_whileCompressing(cctx->mtctx, &cctx->requestedParams);
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t ZSTD_compressStream2_c( ZSTD_CCtx* cctx,
|
||||
ZSTD_outBuffer* output,
|
||||
ZSTD_inBuffer* input,
|
||||
ZSTD_EndDirective endOp)
|
||||
{
|
||||
DEBUGLOG(5, "ZSTD_compressStream2, endOp=%u ", (unsigned)endOp);
|
||||
/* check conditions */
|
||||
{ ZSTD_rust_compressStream2BufferPolicyState const state = {
|
||||
output->pos, output->size, input->pos, input->size};
|
||||
int const bufferPolicy = ZSTD_rust_compressStream2BufferPolicy(&state);
|
||||
RETURN_ERROR_IF(bufferPolicy == ZSTD_RUST_COMPRESS_STREAM2_BUFFER_OUTPUT_INVALID,
|
||||
dstSize_tooSmall, "invalid output buffer");
|
||||
RETURN_ERROR_IF(bufferPolicy == ZSTD_RUST_COMPRESS_STREAM2_BUFFER_INPUT_INVALID,
|
||||
srcSize_wrong, "invalid input buffer");
|
||||
}
|
||||
{ ZSTD_rust_compressStream2PolicyState const state = {(int)endOp};
|
||||
RETURN_ERROR_IF(!ZSTD_rust_compressStream2Policy(&state),
|
||||
parameter_outOfBound, "invalid endDirective");
|
||||
}
|
||||
assert(cctx != NULL);
|
||||
|
||||
/* transparent initialization stage */
|
||||
if (cctx->rustSimpleCompress2Completed) {
|
||||
if (endOp == ZSTD_e_end
|
||||
&& cctx->streamStage == zcss_init
|
||||
&& cctx->pledgedSrcSizePlusOne == 0
|
||||
&& ZSTD_rust_simpleCompress2Level(
|
||||
cctx, input->size - input->pos) != (-2147483647 - 1)) {
|
||||
void* const dst = output->dst ?
|
||||
(char*)output->dst + output->pos : output->dst;
|
||||
const void* const src = input->src ?
|
||||
(const char*)input->src + input->pos : input->src;
|
||||
size_t const result = ZSTD_compress2(
|
||||
cctx, dst, output->size - output->pos,
|
||||
src, input->size - input->pos);
|
||||
cctx->rustSimpleCompress2Completed = 0;
|
||||
if (!ZSTD_isError(result)) {
|
||||
output->pos += result;
|
||||
input->pos = input->size;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* A different streaming directive or an advanced parameter means the
|
||||
* frame can no longer reuse the one-shot Rust result. */
|
||||
cctx->rustSimpleCompress2Completed = 0;
|
||||
}
|
||||
|
||||
if (cctx->streamStage == zcss_init) {
|
||||
size_t const inputSize = input->size - input->pos; /* no obligation to start from pos==0 */
|
||||
ZSTD_rust_compressStream2InitPolicyState const state = {
|
||||
(int)cctx->requestedParams.inBufferMode,
|
||||
(int)endOp,
|
||||
inputSize,
|
||||
cctx->stableIn_notConsumed,
|
||||
input->src,
|
||||
input->pos,
|
||||
cctx->expectedInBuffer.src,
|
||||
cctx->expectedInBuffer.size,
|
||||
(int)cctx->requestedParams.format
|
||||
};
|
||||
int const initPolicy = ZSTD_rust_compressStream2InitPolicy(&state);
|
||||
RETURN_ERROR_IF(
|
||||
initPolicy == ZSTD_RUST_COMPRESS_STREAM2_INIT_POLICY_STABLE_SRC_INVALID,
|
||||
stabilityCondition_notRespected,
|
||||
"stableInBuffer condition not respected: wrong src pointer");
|
||||
RETURN_ERROR_IF(
|
||||
initPolicy == ZSTD_RUST_COMPRESS_STREAM2_INIT_POLICY_STABLE_POS_INVALID,
|
||||
stabilityCondition_notRespected,
|
||||
"stableInBuffer condition not respected: externally modified pos");
|
||||
if (initPolicy == ZSTD_RUST_COMPRESS_STREAM2_INIT_POLICY_DEFER_MAGICLESS
|
||||
|| initPolicy == ZSTD_RUST_COMPRESS_STREAM2_INIT_POLICY_DEFER_ZSTD) {
|
||||
/* pretend input was consumed, to give a sense forward progress */
|
||||
input->pos = input->size;
|
||||
/* save stable inBuffer, for later control, and flush/end */
|
||||
cctx->expectedInBuffer = *input;
|
||||
/* but actually input wasn't consumed, so keep track of position from where compression shall resume */
|
||||
cctx->stableIn_notConsumed += inputSize;
|
||||
/* don't initialize yet, wait for the first block of flush() order, for better parameters adaptation */
|
||||
return (size_t)initPolicy; /* at least some header to produce */
|
||||
}
|
||||
FORWARD_IF_ERROR(
|
||||
ZSTD_CCtx_init_compressStream2(
|
||||
cctx, endOp,
|
||||
inputSize + cctx->stableIn_notConsumed),
|
||||
"compressStream2 initialization failed");
|
||||
ZSTD_setBufferExpectations(cctx, output, input); /* Set initial buffer expectations now that we've initialized */
|
||||
}
|
||||
/* end of transparent initialization stage */
|
||||
|
||||
FORWARD_IF_ERROR(ZSTD_checkBufferStability(cctx, output, input), "invalid buffers");
|
||||
/* compression stage */
|
||||
ZSTD_rust_compressStream2Fields const fields = {
|
||||
cctx,
|
||||
output,
|
||||
input,
|
||||
(int*)&cctx->streamStage,
|
||||
&cctx->stableIn_notConsumed,
|
||||
&cctx->expectedInBuffer,
|
||||
&cctx->rustSimpleCompress2Completed,
|
||||
&cctx->cParamsChanged,
|
||||
&cctx->outBuffContentSize,
|
||||
&cctx->outBuffFlushedSize,
|
||||
cctx->pledgedSrcSizePlusOne,
|
||||
(int)cctx->requestedParams.inBufferMode,
|
||||
(int)cctx->requestedParams.outBufferMode,
|
||||
(int)cctx->requestedParams.format,
|
||||
#ifdef ZSTD_MULTITHREAD
|
||||
if (cctx->appliedParams.nbWorkers > 0) {
|
||||
size_t flushMin;
|
||||
if (cctx->cParamsChanged) {
|
||||
ZSTDMT_updateCParams_whileCompressing(cctx->mtctx, &cctx->requestedParams);
|
||||
cctx->cParamsChanged = 0;
|
||||
}
|
||||
if (cctx->stableIn_notConsumed) {
|
||||
assert(cctx->appliedParams.inBufferMode == ZSTD_bm_stable);
|
||||
/* some early data was skipped - make it available for consumption */
|
||||
assert(input->pos >= cctx->stableIn_notConsumed);
|
||||
input->pos -= cctx->stableIn_notConsumed;
|
||||
cctx->stableIn_notConsumed = 0;
|
||||
}
|
||||
{ ZSTD_rust_compressStream2MTCompletionCallbacks const callbacks = {
|
||||
cctx,
|
||||
ZSTD_rust_compressStream2MT_trace,
|
||||
ZSTD_rust_compressStream2MT_reset
|
||||
};
|
||||
ZSTD_rust_compressStream2MTCoordinatorState const state = {
|
||||
cctx,
|
||||
ZSTD_rust_compressStream2MT_step,
|
||||
output,
|
||||
input,
|
||||
&callbacks,
|
||||
(int)endOp
|
||||
};
|
||||
flushMin = ZSTD_rust_compressStream2MTCoordinator(&state);
|
||||
}
|
||||
FORWARD_IF_ERROR(flushMin, "ZSTDMT_compressStream_generic failed");
|
||||
DEBUGLOG(5, "completed ZSTD_compressStream2 delegating to ZSTDMT_compressStream_generic");
|
||||
/* Either we don't require maximum forward progress, we've finished the
|
||||
* flush, or we are out of output space.
|
||||
*/
|
||||
assert(endOp == ZSTD_e_continue || flushMin == 0 || output->pos == output->size);
|
||||
ZSTD_setBufferExpectations(cctx, output, input);
|
||||
return flushMin;
|
||||
}
|
||||
#endif /* ZSTD_MULTITHREAD */
|
||||
{ size_t const compressResult =
|
||||
ZSTD_compressStream_generic(cctx, output, input, endOp);
|
||||
if (!ERR_isError(compressResult)) {
|
||||
DEBUGLOG(5, "completed ZSTD_compressStream2");
|
||||
}
|
||||
{ ZSTD_rust_compressStream2ResultPolicyState const state = {
|
||||
cctx,
|
||||
ZSTD_rust_compressStream2_setBufferExpectations,
|
||||
output,
|
||||
input,
|
||||
compressResult,
|
||||
cctx->outBuffContentSize,
|
||||
cctx->outBuffFlushedSize
|
||||
};
|
||||
{ size_t const policyResult =
|
||||
ZSTD_rust_compressStream2ResultPolicy(&state);
|
||||
FORWARD_IF_ERROR(policyResult, "");
|
||||
return policyResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
(int)cctx->appliedParams.nbWorkers,
|
||||
#else
|
||||
0,
|
||||
#endif
|
||||
};
|
||||
ZSTD_rust_compressStream2Callbacks const callbacks = {
|
||||
ZSTD_rust_compressStream2_init,
|
||||
ZSTD_rust_compressStream2_checkBuffer,
|
||||
ZSTD_rust_compressStream2_setBufferExpectations,
|
||||
ZSTD_rust_compressStream2_compressStream,
|
||||
#ifdef ZSTD_MULTITHREAD
|
||||
ZSTD_rust_compressStream2_updateMTCParams,
|
||||
ZSTD_rust_compressStream2MT_step,
|
||||
ZSTD_rust_compressStream2MT_trace,
|
||||
ZSTD_rust_compressStream2MT_reset,
|
||||
#else
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
#endif
|
||||
};
|
||||
ZSTD_rust_compressStream2State const state = {
|
||||
&fields,
|
||||
&callbacks,
|
||||
(int)endOp,
|
||||
};
|
||||
return ZSTD_rust_compressStream2(&state);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressStream2_simpleArgs (
|
||||
|
||||
Reference in New Issue
Block a user