Summary
Phase 6.1 of #28: lay the C ABI foundation so external consumers can replace libzstd.so.1 with our build. Covers the verbatim-vendored upstream headers, the new c-api/ workspace member that produces cdylib + staticlib, and the extern "C" wrappers for the simple + context + error + frame-inspection slice of zstd.h.
Phase 6 design (#28 Phase 6) chose vendor upstream headers verbatim + hand-written extern "C" wrappers so macros / typedef names / doxygen comments / enum numeric values are byte-for-byte identical to what consumers parse today. Target upstream version: v1.5.7 (matches Alpine zstd-1.5.7-r2).
Deliverables
1. Vendored headers (upstream v1.5.7 verbatim)
c-api/include/zstd.h
c-api/include/zdict.h
c-api/include/zstd_errors.h
Verbatim copy. No edits. Install path: /usr/include/. Tracking comment at top of each file records the upstream SHA + version we vendored from.
2. New workspace member c-api/
[package]
name = "structured-zstd-c"
# ...
[lib]
crate-type = ["cdylib", "staticlib"]
build.rs:
- Sets
cargo:rustc-cdylib-link-arg=-Wl,-soname,libzstd.so.1 (Linux) — the linker emits the SONAME consumers expect.
- Generates
c-api/libzstd.pc with the Version: 1.5.7 line so pkg-config --modversion libzstd matches upstream.
- Installs the three headers under
OUT_DIR for downstream packaging.
3. Extern "C" wrappers covered by this issue
Scope: the synchronous slice of zstd.h. Advanced/streaming/dictionary moves to 6.2 (#62), CLI moves to 6.3 (#63).
Simple API:
ZSTD_compress, ZSTD_decompress, ZSTD_compressBound
ZSTD_isError, ZSTD_getErrorName
ZSTD_getFrameContentSize, ZSTD_findFrameCompressedSize
ZSTD_minCLevel, ZSTD_maxCLevel, ZSTD_defaultCLevel
ZSTD_versionNumber, ZSTD_versionString
Context API (synchronous part):
ZSTD_createCCtx, ZSTD_freeCCtx
ZSTD_createDCtx, ZSTD_freeDCtx
ZSTD_compressCCtx, ZSTD_decompressDCtx
ZSTD_sizeof_CCtx, ZSTD_sizeof_DCtx
Error code mapping (zstd_errors.h):
ZSTD_ErrorCode enum exposed to Rust as #[repr(u32)]
- Rust
Err(...) variants → ZSTD_ErrorCode via a From impl
ZSTD_getErrorCode, ZSTD_getErrorString, ZSTD_isError all bottomed on this mapping
Frame inspection:
ZSTD_getFrameHeader, ZSTD_getFrameHeader_advanced
ZSTD_findDecompressedSize
ZSTD_decompressBound, ZSTD_frameHeaderSize
4. ABI invariants locked in tests
c-api/tests/abi.rs: static asserts on opaque struct sizes/alignments via core::mem::size_of so a Rust-side refactor that grows CCtx/DCtx past the upstream sentinel size fails CI rather than ABI-breaking consumers.
c-api/tests/c_consumer.c (compiled by build.rs via cc for the test cfg): a tiny program that #include <zstd.h>s the vendored header, calls ZSTD_compress + ZSTD_decompress, asserts roundtrip. Catches "compiles in Rust but a real C consumer can't link" regressions.
c-api/tests/symbols.rs: parses nm -D output of the built .so and asserts every symbol declared in the vendored .h is exported with the right binding (T, not U).
Out of scope (covered by sibling Phase 6 issues)
Acceptance criteria
Estimate
~10-12 working days (vendoring + workspace plumbing + ~30 wrappers + ABI tests).
Blocked by
References
Summary
Phase 6.1 of #28: lay the C ABI foundation so external consumers can replace
libzstd.so.1with our build. Covers the verbatim-vendored upstream headers, the newc-api/workspace member that producescdylib+staticlib, and theextern "C"wrappers for the simple + context + error + frame-inspection slice ofzstd.h.Phase 6 design (#28 Phase 6) chose vendor upstream headers verbatim + hand-written extern "C" wrappers so macros / typedef names / doxygen comments /
enumnumeric values are byte-for-byte identical to what consumers parse today. Target upstream version: v1.5.7 (matches Alpinezstd-1.5.7-r2).Deliverables
1. Vendored headers (upstream v1.5.7 verbatim)
c-api/include/zstd.hc-api/include/zdict.hc-api/include/zstd_errors.hVerbatim copy. No edits. Install path:
/usr/include/. Tracking comment at top of each file records the upstream SHA + version we vendored from.2. New workspace member
c-api/build.rs:cargo:rustc-cdylib-link-arg=-Wl,-soname,libzstd.so.1(Linux) — the linker emits the SONAME consumers expect.c-api/libzstd.pcwith theVersion: 1.5.7line sopkg-config --modversion libzstdmatches upstream.OUT_DIRfor downstream packaging.3. Extern "C" wrappers covered by this issue
Scope: the synchronous slice of
zstd.h. Advanced/streaming/dictionary moves to 6.2 (#62), CLI moves to 6.3 (#63).Simple API:
ZSTD_compress,ZSTD_decompress,ZSTD_compressBoundZSTD_isError,ZSTD_getErrorNameZSTD_getFrameContentSize,ZSTD_findFrameCompressedSizeZSTD_minCLevel,ZSTD_maxCLevel,ZSTD_defaultCLevelZSTD_versionNumber,ZSTD_versionStringContext API (synchronous part):
ZSTD_createCCtx,ZSTD_freeCCtxZSTD_createDCtx,ZSTD_freeDCtxZSTD_compressCCtx,ZSTD_decompressDCtxZSTD_sizeof_CCtx,ZSTD_sizeof_DCtxError code mapping (zstd_errors.h):
ZSTD_ErrorCodeenum exposed to Rust as#[repr(u32)]Err(...)variants →ZSTD_ErrorCodevia aFromimplZSTD_getErrorCode,ZSTD_getErrorString,ZSTD_isErrorall bottomed on this mappingFrame inspection:
ZSTD_getFrameHeader,ZSTD_getFrameHeader_advancedZSTD_findDecompressedSizeZSTD_decompressBound,ZSTD_frameHeaderSize4. ABI invariants locked in tests
c-api/tests/abi.rs: static asserts on opaque struct sizes/alignments viacore::mem::size_ofso a Rust-side refactor that growsCCtx/DCtxpast the upstream sentinel size fails CI rather than ABI-breaking consumers.c-api/tests/c_consumer.c(compiled bybuild.rsviaccfor the test cfg): a tiny program that#include <zstd.h>s the vendored header, callsZSTD_compress+ZSTD_decompress, asserts roundtrip. Catches "compiles in Rust but a real C consumer can't link" regressions.c-api/tests/symbols.rs: parsesnm -Doutput of the built.soand asserts every symbol declared in the vendored.his exported with the right binding (T, notU).Out of scope (covered by sibling Phase 6 issues)
ZSTD_CStream/DStreamAPI → 6.2 (perf(bench): add rust/ffi delta charts by corpus+compression params #62)ZSTD_CCtx_setParameterfamily) → 6.2 (perf(bench): add rust/ffi delta charts by corpus+compression params #62)ZSTD_CDict/ZSTD_DDict,ZDICT_trainFromBuffer) → 6.2 (perf(bench): add rust/ffi delta charts by corpus+compression params #62)zstdCLI binary → 6.3 (feat(encoding): numeric compression levels (1-22) API #63)ZSTD_c_nbWorkers) → 6.4 (chore: release v0.0.7 #64)Acceptance criteria
c-api/workspace member builds bothcdylib(libstructured_zstd.so) andstaticlib(libstructured_zstd.a) without unsafe-feature opt-outs..sohasSONAME=libzstd.so.1verifiable viareadelf -d/otool -D.zstd.h/zdict.h/zstd_errors.hare byte-for-byte identical to upstream v1.5.7 release tarballs (CI diff against pinned SHA).c-api/libzstd.pcreportsVersion: 1.5.7,Libs: -lzstd,Cflags: -I${includedir}.ZSTD_compress→ZSTD_decompress(inc_consumer.c).ZSTD_ErrorCode, andZSTD_getErrorCode(ZSTD_compress(...))recovers it.symbols.rssnapshot test: every symbol declared in vendoredzstd.hheaders appears innm -Doutput of the built.so.cargo nextest run --features hash,std,dict_builder).Estimate
~10-12 working days (vendoring + workspace plumbing + ~30 wrappers + ABI tests).
Blocked by
ZSTD_CCtx_setParameterin 6.2, but 6.1 only needs the simple + context API which doesn't depend on it. 6.1 is unblocked by feat: configurable compression parameters API #27 itself but the broader phase is.References
zstdpackage: https://pkgs.alphalinux.org/package/edge/main/x86_64/zstd