caller-workspace only.Expand description
Streaming decoder that runs entirely in caller-owned memory.
WorkspaceDecoder decodes a stream of zstd frames chunk by chunk without
touching the heap: the window, the entropy tables, the literals and the
staging for blocks split across input chunks all live in one byte slice the
caller supplies. workspace_bytes says how large that slice must be for a
given window limit, so the caller can admit the memory in its own accounting
before decoding starts, and keep the charge for as long as the slice lives.
Every step is bounded three ways, all chosen by the caller: the window a
frame may declare and the total output (DecodeLimits), and the work a
step may do (WorkBudget). A refusal is reported apart from malformed
input, an unsupported feature, and input that ends mid-frame, and it ends
the stream: every later step fails with WorkspaceDecodeError::Failed
until WorkspaceDecoder::reset.
Frames that name a dictionary are refused with
Unsupported::Dictionary; this decoder keeps no dictionary registry.
The decoding itself is the same code the other decoders run, so output is identical to theirs.
§Examples
use structured_zstd::decoding::workspace::{
workspace_bytes, DecodeLimits, StepState, WorkBudget, WorkspaceDecoder,
};
use structured_zstd::encoding::{compress_slice_to_vec, CompressionLevel};
let data = b"the same words, the same words, the same words".repeat(100);
let compressed = compress_slice_to_vec(&data, CompressionLevel::Default);
let limits = DecodeLimits::new(1 << 20).with_max_output(1 << 20);
let mut workspace = vec![0u8; workspace_bytes(limits.max_window_size).unwrap()];
let mut decoder = WorkspaceDecoder::new(&mut workspace, limits).unwrap();
let mut work = WorkBudget::new(1 << 24);
let mut decoded = Vec::new();
let mut out = [0u8; 512];
let mut input = &compressed[..];
loop {
// Feed at most 100 bytes at a time; say when nothing more will come.
let chunk = &input[..input.len().min(100)];
let last = chunk.len() == input.len();
let progress = decoder.step(chunk, last, &mut out, &mut work).unwrap();
decoded.extend_from_slice(&out[..progress.produced]);
input = &input[progress.consumed..];
if progress.state == StepState::Done {
break;
}
}
assert_eq!(decoded, data);Structs§
- Decode
Limits - Limits a
WorkspaceDecoderholds every frame of the stream to. - Progress
- What one
WorkspaceDecoder::stepdid. - Work
Budget - Work a caller allows its decode steps, in units charged before the work they pay for runs.
- Workspace
Decoder - Allocation-free streaming zstd decoder over a caller-owned workspace.
Enums§
- Limit
Exceeded - A limit from
DecodeLimitsorWorkBudgetthat refused the stream. - Malformed
Input - How the input breaks the zstd format.
- Step
State - Why a
WorkspaceDecoder::stepreturned. - Unsupported
- Something this decoder does not do, met in otherwise valid input.
- Workspace
Config Error - A workspace size or limit
workspace_bytesorWorkspaceDecoder::newrefused. - Workspace
Decode Error - Why a
WorkspaceDecoder::stepfailed. Every variant ends the stream: later steps returnSelf::FaileduntilWorkspaceDecoder::reset.
Constants§
- COMPRESSED_
BLOCK_ UNITS - Work units charged before a compressed block decodes, on top of its input
bytes and its output bound: the most its entropy-table builds can cost
(one Huffman table of
1 << 12entries and the literal-length, match-length and offset tables at1 << 9,1 << 9and1 << 8).
Functions§
- workspace_
bytes - Bytes of workspace a
WorkspaceDecoderneeds to decode frames whose window is at mostmax_window_size.