Files
ddidderr da0e2c8380 fix(build): restore complete mixed Rust build matrix
`make all` exercises substantially more than the default zstd binary. It also
builds compression-only and decompression-only archives, older contrib tools
that compile program C shims directly, and the single-file amalgamations. The
Rust migration had changed symbol ownership without updating every one of
those feature and link boundaries.

The first failure came from `fileio_asyncio`: it is always compiled, but its
codec bindings unconditionally referenced both `zstd_compress` and
`zstd_decompress`. A compression-only archive therefore required disabled
decoder modules, and the decompression-only configuration had the symmetric
problem. Gate the concrete codec imports, callback types, helpers, and exports
with their Cargo features. Keep the format probe compilable without the
legacy decoder predicate when decompression is disabled.

Once that boundary compiled, the remaining `make all` paths exposed related
integration gaps. Move the C decompression projection declarations out of the
compression preprocessor block, while leaving destination callback types
shared. Link the Rust CLI helpers archive into zlibWrapper, pzstd, and
largeNbDicts, whose util/time/data-generator C files are now declaration shims
rather than implementations.

The generated single-file C sources also call Rust-owned symbols now. Build
and link an appropriately featured Rust archive in their native smoke tests,
and include the pool configuration shim in the decoder case. The full
amalgamation combines `zstd_lazy.c` and `zstd_opt.c` into one translation unit,
so guard their otherwise translation-unit-local dictionary mode enum against
duplicate definition.

A Rust-backed amalgamation is no longer a standalone Emscripten input. Remove
the obsolete emcc/Docker path and report that limitation explicitly; restoring
the WebAssembly smoke test requires a Rust WebAssembly archive and a defined
cross-language amalgamation contract.

Test Plan:
- `cargo check --manifest-path rust/Cargo.toml --no-default-features --features compression` -- passed
- `cargo check --manifest-path rust/Cargo.toml --no-default-features --features decompression` -- passed
- `sh -n build/single_file_libs/build_decoder_test.sh build/single_file_libs/build_library_test.sh` -- passed
- `make all` -- passed, including native single-file and seekable-format tests
- `git diff --cached --check` -- passed
2026-07-22 06:56:06 +02:00

247 lines
8.8 KiB
C

/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
* in the COPYING file in the root directory of this source tree).
* You may select, at your option, one or both of these licenses.
*/
/* The optimal parser is implemented in rust/src/zstd_opt.rs. Keep the
* private ZSTD_MatchState_t and entropy-table layouts on the C side: this
* translation unit only projects the leaves Rust needs and preserves the
* established C entry points. */
#include "zstd_compress_internal.h"
#include "zstd_opt.h"
#if !defined(ZSTD_EXCLUDE_BTLAZY2_BLOCK_COMPRESSOR) \
|| !defined(ZSTD_EXCLUDE_BTOPT_BLOCK_COMPRESSOR) \
|| !defined(ZSTD_EXCLUDE_BTULTRA_BLOCK_COMPRESSOR)
typedef struct {
U32* hashTable;
U32* chainTable;
const BYTE* base;
const BYTE* dictBase;
U32 dictLimit;
U32 lowLimit;
U32 loadedDictEnd;
U32* nextToUpdate;
U32 hashLog;
U32 chainLog;
U32 searchLog;
U32 windowLog;
int useCPredict;
U32* hashTable3;
U32 hashLog3;
const BYTE* nextSrc;
U32 minMatch;
U32 targetLength;
optState_t* opt;
const void* dictMatchState;
const RawSeqStore_t* ldmSeqStore;
const BYTE** windowBase;
U32* windowDictLimit;
U32* windowLowLimit;
const size_t* hufCTable;
int hufRepeatValid;
const U32* fseLitLengthCTable;
const U32* fseMatchLengthCTable;
const U32* fseOffCodeCTable;
} ZSTD_RustOptState;
typedef char ZSTD_rust_opt_seqdef_layout[(sizeof(SeqDef) == 8) ? 1 : -1];
typedef char ZSTD_rust_opt_match_layout[(sizeof(ZSTD_match_t) == 8) ? 1 : -1];
typedef char ZSTD_rust_opt_rawseq_layout[(sizeof(rawSeq) == 12) ? 1 : -1];
typedef char ZSTD_rust_opt_seqstore_layout[
(offsetof(SeqStore_t, longLengthPos) == 9 * sizeof(size_t) + 4) ? 1 : -1];
typedef char ZSTD_rust_optimal_layout[
(sizeof(ZSTD_optimal_t) == 4 * sizeof(U32) + sizeof(U32) * ZSTD_REP_NUM) ? 1 : -1];
typedef char ZSTD_rust_opt_rep_count[(ZSTD_REP_NUM == 3) ? 1 : -1];
static void ZSTD_rustOptState_init(
ZSTD_RustOptState* const out,
ZSTD_MatchState_t* const ms,
const ZSTD_RustOptState* const dms)
{
out->hashTable = ms->hashTable;
out->chainTable = ms->chainTable;
out->base = ms->window.base;
out->dictBase = ms->window.dictBase;
out->dictLimit = ms->window.dictLimit;
out->lowLimit = ms->window.lowLimit;
out->loadedDictEnd = ms->loadedDictEnd;
out->nextToUpdate = &ms->nextToUpdate;
out->hashLog = ms->cParams.hashLog;
out->chainLog = ms->cParams.chainLog;
out->searchLog = ms->cParams.searchLog;
#ifdef ZSTD_C_PREDICT
out->useCPredict = 1;
#else
out->useCPredict = 0;
#endif
out->windowLog = ms->cParams.windowLog;
out->hashTable3 = ms->hashTable3;
out->hashLog3 = ms->hashLog3;
out->nextSrc = ms->window.nextSrc;
out->minMatch = ms->cParams.minMatch;
out->targetLength = ms->cParams.targetLength;
out->opt = &ms->opt;
out->dictMatchState = dms;
out->ldmSeqStore = ms->ldmSeqStore;
out->windowBase = &ms->window.base;
out->windowDictLimit = &ms->window.dictLimit;
out->windowLowLimit = &ms->window.lowLimit;
out->hufCTable = NULL;
out->hufRepeatValid = 0;
out->fseLitLengthCTable = NULL;
out->fseMatchLengthCTable = NULL;
out->fseOffCodeCTable = NULL;
}
static void ZSTD_rustOptState_projectCosts(
ZSTD_RustOptState* const out,
ZSTD_MatchState_t* const ms)
{
const ZSTD_entropyCTables_t* const costs = ms->opt.symbolCosts;
out->hufCTable = costs ? costs->huf.CTable : NULL;
out->hufRepeatValid = costs && costs->huf.repeatMode == HUF_repeat_valid;
out->fseLitLengthCTable = costs ? costs->fse.litlengthCTable : NULL;
out->fseMatchLengthCTable = costs ? costs->fse.matchlengthCTable : NULL;
out->fseOffCodeCTable = costs ? costs->fse.offcodeCTable : NULL;
}
static void ZSTD_rustOptState_init_with_dict(
ZSTD_RustOptState* const out,
ZSTD_MatchState_t* const ms)
{
ZSTD_rustOptState_init(out, ms, NULL);
}
static void ZSTD_rustOptState_init_with_costs(
ZSTD_RustOptState* const out,
ZSTD_MatchState_t* const ms,
const ZSTD_RustOptState* const dms)
{
ZSTD_rustOptState_init(out, ms, dms);
ZSTD_rustOptState_projectCosts(out, ms);
}
void ZSTD_rust_opt_updateTree(
ZSTD_RustOptState* state,
const void* ip, const void* iend,
U32 mls, int dictMode);
size_t ZSTD_rust_compressBlock_opt(
ZSTD_RustOptState* state, void* seqStore, U32 rep[ZSTD_REP_NUM],
const void* src, size_t srcSize, int optLevel, int dictMode);
void ZSTD_rust_initStats_ultra(
ZSTD_RustOptState* state, void* seqStore, const U32 rep[ZSTD_REP_NUM],
const void* src, size_t srcSize);
size_t ZSTD_rust_compressBlock_btultra2(
ZSTD_RustOptState* state, void* seqStore, U32 rep[ZSTD_REP_NUM],
const void* src, size_t srcSize);
#ifndef ZSTD_RUST_DICT_MODE_ENUM
#define ZSTD_RUST_DICT_MODE_ENUM
enum {
ZSTD_rust_dict_noDict = 0,
ZSTD_rust_dict_extDict = 1,
ZSTD_rust_dict_dictMatchState = 2,
};
#endif
void ZSTD_updateTree(ZSTD_MatchState_t* const ms, const BYTE* const ip,
const BYTE* const iend)
{
ZSTD_RustOptState state;
ZSTD_rustOptState_init_with_dict(&state, ms);
ZSTD_rust_opt_updateTree(&state, ip, iend, ms->cParams.minMatch,
ZSTD_rust_dict_noDict);
}
#ifndef ZSTD_EXCLUDE_BTOPT_BLOCK_COMPRESSOR
size_t ZSTD_compressBlock_btopt(
ZSTD_MatchState_t* const ms, SeqStore_t* const seqStore,
U32 rep[ZSTD_REP_NUM], const void* const src, size_t const srcSize)
{
ZSTD_RustOptState state;
ZSTD_rustOptState_init_with_costs(&state, ms, NULL);
return ZSTD_rust_compressBlock_opt(&state, seqStore, rep, src, srcSize,
0, ZSTD_rust_dict_noDict);
}
size_t ZSTD_compressBlock_btopt_dictMatchState(
ZSTD_MatchState_t* const ms, SeqStore_t* const seqStore,
U32 rep[ZSTD_REP_NUM], const void* const src, size_t const srcSize)
{
ZSTD_RustOptState state;
ZSTD_RustOptState dictState;
ZSTD_MatchState_t dictCopy = *ms->dictMatchState;
ZSTD_rustOptState_init(&dictState, &dictCopy, NULL);
ZSTD_rustOptState_init_with_costs(&state, ms, &dictState);
return ZSTD_rust_compressBlock_opt(&state, seqStore, rep, src, srcSize,
0, ZSTD_rust_dict_dictMatchState);
}
size_t ZSTD_compressBlock_btopt_extDict(
ZSTD_MatchState_t* const ms, SeqStore_t* const seqStore,
U32 rep[ZSTD_REP_NUM], const void* const src, size_t const srcSize)
{
ZSTD_RustOptState state;
ZSTD_rustOptState_init_with_costs(&state, ms, NULL);
return ZSTD_rust_compressBlock_opt(&state, seqStore, rep, src, srcSize,
0, ZSTD_rust_dict_extDict);
}
#endif
#ifndef ZSTD_EXCLUDE_BTULTRA_BLOCK_COMPRESSOR
size_t ZSTD_compressBlock_btultra(
ZSTD_MatchState_t* const ms, SeqStore_t* const seqStore,
U32 rep[ZSTD_REP_NUM], const void* const src, size_t const srcSize)
{
ZSTD_RustOptState state;
ZSTD_rustOptState_init_with_costs(&state, ms, NULL);
return ZSTD_rust_compressBlock_opt(&state, seqStore, rep, src, srcSize,
2, ZSTD_rust_dict_noDict);
}
size_t ZSTD_compressBlock_btultra_dictMatchState(
ZSTD_MatchState_t* const ms, SeqStore_t* const seqStore,
U32 rep[ZSTD_REP_NUM], const void* const src, size_t const srcSize)
{
ZSTD_RustOptState state;
ZSTD_RustOptState dictState;
ZSTD_MatchState_t dictCopy = *ms->dictMatchState;
ZSTD_rustOptState_init(&dictState, &dictCopy, NULL);
ZSTD_rustOptState_init_with_costs(&state, ms, &dictState);
return ZSTD_rust_compressBlock_opt(&state, seqStore, rep, src, srcSize,
2, ZSTD_rust_dict_dictMatchState);
}
size_t ZSTD_compressBlock_btultra_extDict(
ZSTD_MatchState_t* const ms, SeqStore_t* const seqStore,
U32 rep[ZSTD_REP_NUM], const void* const src, size_t const srcSize)
{
ZSTD_RustOptState state;
ZSTD_rustOptState_init_with_costs(&state, ms, NULL);
return ZSTD_rust_compressBlock_opt(&state, seqStore, rep, src, srcSize,
2, ZSTD_rust_dict_extDict);
}
size_t ZSTD_compressBlock_btultra2(
ZSTD_MatchState_t* const ms, SeqStore_t* const seqStore,
U32 rep[ZSTD_REP_NUM], const void* const src, size_t const srcSize)
{
ZSTD_RustOptState state;
ZSTD_rustOptState_init_with_costs(&state, ms, NULL);
return ZSTD_rust_compressBlock_btultra2(&state, seqStore, rep, src,
srcSize);
}
#endif
#endif /* any optimal parser entry point is enabled */