Files
zstd-rs/lib/compress/zstd_lazy.c
T
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

257 lines
11 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 of the above-listed licenses.
*/
/* The lazy matchers are implemented in rust/src/zstd_lazy.rs. Keep only the
* private match-state projection and the established C entry points here. */
#include "zstd_compress_internal.h"
#include "zstd_lazy.h"
#if !defined(ZSTD_EXCLUDE_GREEDY_BLOCK_COMPRESSOR) \
|| !defined(ZSTD_EXCLUDE_LAZY_BLOCK_COMPRESSOR) \
|| !defined(ZSTD_EXCLUDE_LAZY2_BLOCK_COMPRESSOR) \
|| !defined(ZSTD_EXCLUDE_BTLAZY2_BLOCK_COMPRESSOR)
typedef char ZSTD_rust_lazy_seqdef_layout[(sizeof(SeqDef) == 8) ? 1 : -1];
typedef char ZSTD_rust_lazy_seqstore_long_length_pos[
(offsetof(SeqStore_t, longLengthPos) == 9 * sizeof(size_t) + 4) ? 1 : -1];
typedef char ZSTD_rust_lazy_seqstore_layout[
(sizeof(SeqStore_t) == 9 * sizeof(size_t) + 8) ? 1 : -1];
typedef char ZSTD_rust_lazy_rep_count[(ZSTD_REP_NUM == 3) ? 1 : -1];
/* This must remain in lock-step with `ZSTD_RustLazyState` in Rust. The large
* and private `ZSTD_MatchState_t` itself deliberately never crosses FFI. */
typedef struct ZSTD_RustLazyState_s {
U32* hashTable;
U32* chainTable;
BYTE* tagTable;
U32* hashCache;
const BYTE* base;
const BYTE* dictBase;
const BYTE* nextSrc;
U32 dictLimit;
U32 lowLimit;
U32 loadedDictEnd;
U32* nextToUpdate;
int* lazySkipping;
U32 hashLog;
U32 chainLog;
U32 minMatch;
U32 searchLog;
U32 windowLog;
U32 rowHashLog;
U64 hashSalt;
U32* hashSaltEntropy;
const struct ZSTD_RustLazyState_s* dictMatchState;
} ZSTD_RustLazyState;
U32 ZSTD_rust_lazy_insertAndFindFirstIndex(ZSTD_RustLazyState* state,
const void* ip);
void ZSTD_rust_lazy_row_update(ZSTD_RustLazyState* state, const void* ip);
void ZSTD_rust_lazy_loadDedicatedDict(ZSTD_RustLazyState* state,
const void* ip);
size_t ZSTD_rust_compressBlock_lazy(
ZSTD_RustLazyState* state, void* seqStore, U32 rep[ZSTD_REP_NUM],
const void* src, size_t srcSize, int searchMethod, U32 depth,
int dictMode);
enum {
ZSTD_rust_search_hashChain = 0,
ZSTD_rust_search_binaryTree = 1,
ZSTD_rust_search_rowHash = 2,
};
#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,
ZSTD_rust_dict_dedicatedDictSearch = 3,
};
#endif
static void ZSTD_rustLazyState_init(
ZSTD_RustLazyState* const out,
ZSTD_MatchState_t* const ms,
const ZSTD_RustLazyState* const dms)
{
out->hashTable = ms->hashTable;
out->chainTable = ms->chainTable;
out->tagTable = ms->tagTable;
out->hashCache = ms->hashCache;
out->base = ms->window.base;
out->dictBase = ms->window.dictBase;
out->nextSrc = ms->window.nextSrc;
out->dictLimit = ms->window.dictLimit;
out->lowLimit = ms->window.lowLimit;
out->loadedDictEnd = ms->loadedDictEnd;
out->nextToUpdate = &ms->nextToUpdate;
out->lazySkipping = &ms->lazySkipping;
out->hashLog = ms->cParams.hashLog;
out->chainLog = ms->cParams.chainLog;
out->minMatch = ms->cParams.minMatch;
out->searchLog = ms->cParams.searchLog;
out->windowLog = ms->cParams.windowLog;
out->rowHashLog = ms->rowHashLog;
out->hashSalt = ms->hashSalt;
out->hashSaltEntropy = &ms->hashSaltEntropy;
out->dictMatchState = dms;
}
/* Dictionary match states are searched but never updated by this module. */
static void ZSTD_rustLazyState_initDict(
ZSTD_RustLazyState* const out,
const ZSTD_MatchState_t* const ms)
{
out->hashTable = ms->hashTable;
out->chainTable = ms->chainTable;
out->tagTable = ms->tagTable;
out->hashCache = NULL;
out->base = ms->window.base;
out->dictBase = ms->window.dictBase;
out->nextSrc = ms->window.nextSrc;
out->dictLimit = ms->window.dictLimit;
out->lowLimit = ms->window.lowLimit;
out->loadedDictEnd = ms->loadedDictEnd;
out->nextToUpdate = NULL;
out->lazySkipping = NULL;
out->hashLog = ms->cParams.hashLog;
out->chainLog = ms->cParams.chainLog;
out->minMatch = ms->cParams.minMatch;
out->searchLog = ms->cParams.searchLog;
out->windowLog = ms->cParams.windowLog;
out->rowHashLog = ms->rowHashLog;
out->hashSalt = ms->hashSalt;
out->hashSaltEntropy = NULL;
out->dictMatchState = NULL;
}
static size_t ZSTD_rust_compressBlock_lazy_call(
ZSTD_MatchState_t* const ms, SeqStore_t* const seqStore,
U32 rep[ZSTD_REP_NUM], const void* const src, size_t const srcSize,
int const searchMethod, U32 const depth, int const dictMode)
{
ZSTD_RustLazyState state;
ZSTD_RustLazyState dictState;
const ZSTD_RustLazyState* dms = NULL;
if (dictMode == ZSTD_rust_dict_dictMatchState
|| dictMode == ZSTD_rust_dict_dedicatedDictSearch) {
const ZSTD_MatchState_t* const rawDms = ms->dictMatchState;
assert(rawDms != NULL);
ZSTD_rustLazyState_initDict(&dictState, rawDms);
dms = &dictState;
}
ZSTD_rustLazyState_init(&state, ms, dms);
return ZSTD_rust_compressBlock_lazy(
&state, seqStore, rep, src, srcSize, searchMethod, depth, dictMode);
}
U32 ZSTD_insertAndFindFirstIndex(ZSTD_MatchState_t* ms, const BYTE* ip)
{
ZSTD_RustLazyState state;
ZSTD_rustLazyState_init(&state, ms, NULL);
return ZSTD_rust_lazy_insertAndFindFirstIndex(&state, ip);
}
void ZSTD_row_update(ZSTD_MatchState_t* const ms, const BYTE* const ip)
{
ZSTD_RustLazyState state;
ZSTD_rustLazyState_init(&state, ms, NULL);
ZSTD_rust_lazy_row_update(&state, ip);
}
void ZSTD_dedicatedDictSearch_lazy_loadDictionary(
ZSTD_MatchState_t* ms, const BYTE* const ip)
{
ZSTD_RustLazyState state;
ZSTD_rustLazyState_init(&state, ms, NULL);
ZSTD_rust_lazy_loadDedicatedDict(&state, ip);
}
#define ZSTD_RUST_LAZY_WRAPPER(name, method, parserDepth, mode) \
size_t name( \
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], \
const void* src, size_t srcSize) \
{ \
return ZSTD_rust_compressBlock_lazy_call( \
ms, seqStore, rep, src, srcSize, method, parserDepth, mode); \
}
#ifndef ZSTD_EXCLUDE_GREEDY_BLOCK_COMPRESSOR
ZSTD_RUST_LAZY_WRAPPER(ZSTD_compressBlock_greedy,
ZSTD_rust_search_hashChain, 0, ZSTD_rust_dict_noDict)
ZSTD_RUST_LAZY_WRAPPER(ZSTD_compressBlock_greedy_dictMatchState,
ZSTD_rust_search_hashChain, 0, ZSTD_rust_dict_dictMatchState)
ZSTD_RUST_LAZY_WRAPPER(ZSTD_compressBlock_greedy_dedicatedDictSearch,
ZSTD_rust_search_hashChain, 0, ZSTD_rust_dict_dedicatedDictSearch)
ZSTD_RUST_LAZY_WRAPPER(ZSTD_compressBlock_greedy_row,
ZSTD_rust_search_rowHash, 0, ZSTD_rust_dict_noDict)
ZSTD_RUST_LAZY_WRAPPER(ZSTD_compressBlock_greedy_dictMatchState_row,
ZSTD_rust_search_rowHash, 0, ZSTD_rust_dict_dictMatchState)
ZSTD_RUST_LAZY_WRAPPER(ZSTD_compressBlock_greedy_dedicatedDictSearch_row,
ZSTD_rust_search_rowHash, 0, ZSTD_rust_dict_dedicatedDictSearch)
ZSTD_RUST_LAZY_WRAPPER(ZSTD_compressBlock_greedy_extDict,
ZSTD_rust_search_hashChain, 0, ZSTD_rust_dict_extDict)
ZSTD_RUST_LAZY_WRAPPER(ZSTD_compressBlock_greedy_extDict_row,
ZSTD_rust_search_rowHash, 0, ZSTD_rust_dict_extDict)
#endif
#ifndef ZSTD_EXCLUDE_LAZY_BLOCK_COMPRESSOR
ZSTD_RUST_LAZY_WRAPPER(ZSTD_compressBlock_lazy,
ZSTD_rust_search_hashChain, 1, ZSTD_rust_dict_noDict)
ZSTD_RUST_LAZY_WRAPPER(ZSTD_compressBlock_lazy_dictMatchState,
ZSTD_rust_search_hashChain, 1, ZSTD_rust_dict_dictMatchState)
ZSTD_RUST_LAZY_WRAPPER(ZSTD_compressBlock_lazy_dedicatedDictSearch,
ZSTD_rust_search_hashChain, 1, ZSTD_rust_dict_dedicatedDictSearch)
ZSTD_RUST_LAZY_WRAPPER(ZSTD_compressBlock_lazy_row,
ZSTD_rust_search_rowHash, 1, ZSTD_rust_dict_noDict)
ZSTD_RUST_LAZY_WRAPPER(ZSTD_compressBlock_lazy_dictMatchState_row,
ZSTD_rust_search_rowHash, 1, ZSTD_rust_dict_dictMatchState)
ZSTD_RUST_LAZY_WRAPPER(ZSTD_compressBlock_lazy_dedicatedDictSearch_row,
ZSTD_rust_search_rowHash, 1, ZSTD_rust_dict_dedicatedDictSearch)
ZSTD_RUST_LAZY_WRAPPER(ZSTD_compressBlock_lazy_extDict,
ZSTD_rust_search_hashChain, 1, ZSTD_rust_dict_extDict)
ZSTD_RUST_LAZY_WRAPPER(ZSTD_compressBlock_lazy_extDict_row,
ZSTD_rust_search_rowHash, 1, ZSTD_rust_dict_extDict)
#endif
#ifndef ZSTD_EXCLUDE_LAZY2_BLOCK_COMPRESSOR
ZSTD_RUST_LAZY_WRAPPER(ZSTD_compressBlock_lazy2,
ZSTD_rust_search_hashChain, 2, ZSTD_rust_dict_noDict)
ZSTD_RUST_LAZY_WRAPPER(ZSTD_compressBlock_lazy2_dictMatchState,
ZSTD_rust_search_hashChain, 2, ZSTD_rust_dict_dictMatchState)
ZSTD_RUST_LAZY_WRAPPER(ZSTD_compressBlock_lazy2_dedicatedDictSearch,
ZSTD_rust_search_hashChain, 2, ZSTD_rust_dict_dedicatedDictSearch)
ZSTD_RUST_LAZY_WRAPPER(ZSTD_compressBlock_lazy2_row,
ZSTD_rust_search_rowHash, 2, ZSTD_rust_dict_noDict)
ZSTD_RUST_LAZY_WRAPPER(ZSTD_compressBlock_lazy2_dictMatchState_row,
ZSTD_rust_search_rowHash, 2, ZSTD_rust_dict_dictMatchState)
ZSTD_RUST_LAZY_WRAPPER(ZSTD_compressBlock_lazy2_dedicatedDictSearch_row,
ZSTD_rust_search_rowHash, 2, ZSTD_rust_dict_dedicatedDictSearch)
ZSTD_RUST_LAZY_WRAPPER(ZSTD_compressBlock_lazy2_extDict,
ZSTD_rust_search_hashChain, 2, ZSTD_rust_dict_extDict)
ZSTD_RUST_LAZY_WRAPPER(ZSTD_compressBlock_lazy2_extDict_row,
ZSTD_rust_search_rowHash, 2, ZSTD_rust_dict_extDict)
#endif
#ifndef ZSTD_EXCLUDE_BTLAZY2_BLOCK_COMPRESSOR
ZSTD_RUST_LAZY_WRAPPER(ZSTD_compressBlock_btlazy2,
ZSTD_rust_search_binaryTree, 2, ZSTD_rust_dict_noDict)
ZSTD_RUST_LAZY_WRAPPER(ZSTD_compressBlock_btlazy2_dictMatchState,
ZSTD_rust_search_binaryTree, 2, ZSTD_rust_dict_dictMatchState)
ZSTD_RUST_LAZY_WRAPPER(ZSTD_compressBlock_btlazy2_extDict,
ZSTD_rust_search_binaryTree, 2, ZSTD_rust_dict_extDict)
#endif
#undef ZSTD_RUST_LAZY_WRAPPER
#endif /* lazy matcher build exclusions */