structured_zstd/encoding/sequences.rs
1//! Sequences that come into the encoder from outside, or go out of it: a parse
2//! of the input into literal runs and matches, laid out as the C
3//! `ZSTD_Sequence` so the C entry points pass caller arrays straight through.
4//!
5//! * [`SequenceReplay`] is a [`Matcher`] that searches nothing and reports a
6//! given parse instead, so a frame is built from it by the ordinary block
7//! pipeline (C `ZSTD_compressSequences`).
8//! * [`SequenceProducer`] is a parser asked for each block in place of the
9//! built-in match finder (C `ZSTD_registerSequenceProducer`).
10//! * [`FrameCompressor::set_sequence_capture`](crate::encoding::FrameCompressor::set_sequence_capture)
11//! records the parse the built-in match finder chose (C
12//! `ZSTD_generateSequences`).
13
14use alloc::vec::Vec;
15
16use crate::encoding::block_input::BlockInput;
17use crate::encoding::{CompressionLevel, HistoryBuf, Matcher, Sequence};
18
19/// The shortest match a sequence can carry (RFC 8878 3.1.1.3.2.1.1: match
20/// length codes start at 3).
21pub const MIN_MATCH: u32 = 3;
22
23/// One sequence of a parse: `lit_len` literal bytes, then `match_len` bytes
24/// copied from `offset` bytes back. A sequence with `offset == 0` and
25/// `match_len == 0` carries only literals and ends a block (a block
26/// delimiter). Laid out as the C `ZSTD_Sequence`.
27#[repr(C)]
28#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
29pub struct ExternalSequence {
30 /// How far back the match copies from, in bytes (not the offset code).
31 pub offset: u32,
32 /// Literal bytes before the match.
33 pub lit_len: u32,
34 /// Bytes the match copies.
35 pub match_len: u32,
36 /// Which repeat offset `offset` is (1..=3, numbered as RFC 8878 3.1.1.5
37 /// numbers them), or 0 when it is none. A captured parse fills it in; the
38 /// encoder works it out itself and never reads it.
39 pub rep: u32,
40}
41
42impl ExternalSequence {
43 /// A block delimiter carrying `lit_len` trailing literals.
44 pub const fn delimiter(lit_len: u32) -> Self {
45 Self {
46 offset: 0,
47 lit_len,
48 match_len: 0,
49 rep: 0,
50 }
51 }
52
53 /// Whether this sequence only ends a block, with its literals.
54 pub const fn is_delimiter(&self) -> bool {
55 self.offset == 0 && self.match_len == 0
56 }
57}
58
59/// Upper bound on the sequences a parse of `src_size` bytes can hold, block
60/// delimiters included (C `ZSTD_sequenceBound`): one per minimal match, and
61/// one delimiter per smallest block.
62///
63/// ```
64/// use structured_zstd::encoding::sequences::sequence_bound;
65/// assert_eq!(sequence_bound(0), 2);
66/// assert_eq!(sequence_bound(3000), 1004);
67/// ```
68pub const fn sequence_bound(src_size: usize) -> usize {
69 (src_size / MIN_MATCH as usize + 1)
70 + (src_size / crate::common::MIN_MAX_BLOCK_SIZE as usize + 1)
71}
72
73/// Heap bytes a compressor keeps for a [`SequenceProducer`]'s parse of blocks
74/// up to `block_size` bytes: room for [`sequence_bound`] sequences, as many as
75/// a parse it can use holds, kept from block to block (upstream reserves the
76/// same for its external sequences, zstd_compress.c:2236-2239).
77///
78/// ```
79/// use structured_zstd::encoding::sequences::{producer_parse_heap_bytes, sequence_bound};
80/// assert_eq!(producer_parse_heap_bytes(131_072), sequence_bound(131_072) * 16);
81/// ```
82pub const fn producer_parse_heap_bytes(block_size: usize) -> usize {
83 sequence_bound(block_size) * core::mem::size_of::<ExternalSequence>()
84}
85
86/// Remove every block delimiter from `sequences`, handing its literals to the
87/// sequence after it, and return how many sequences remain at the front (C
88/// `ZSTD_mergeBlockDelimiters`). A final delimiter's literals become the
89/// parse's trailing literals, which no sequence carries.
90///
91/// ```
92/// use structured_zstd::encoding::sequences::{merge_block_delimiters, ExternalSequence};
93/// let mut parse = [
94/// ExternalSequence { offset: 4, lit_len: 2, match_len: 5, rep: 0 },
95/// ExternalSequence { offset: 0, lit_len: 3, match_len: 0, rep: 0 },
96/// ExternalSequence { offset: 9, lit_len: 1, match_len: 4, rep: 0 },
97/// ];
98/// assert_eq!(merge_block_delimiters(&mut parse), 2);
99/// assert_eq!(parse[1].lit_len, 4);
100/// ```
101pub fn merge_block_delimiters(sequences: &mut [ExternalSequence]) -> usize {
102 let mut kept = 0;
103 for index in 0..sequences.len() {
104 let sequence = sequences[index];
105 if sequence.is_delimiter() {
106 if let Some(next) = sequences.get_mut(index + 1) {
107 // Wrapping, as upstream adds them: the C entry point has no
108 // error to return, a sum past `u32::MAX` describes no block,
109 // and `validate_parse` refuses such a parse later.
110 next.lit_len = next.lit_len.wrapping_add(sequence.lit_len);
111 }
112 } else {
113 sequences[kept] = sequence;
114 kept += 1;
115 }
116 }
117 kept
118}
119
120/// The plain offset an offset code stands for, given the repeat-offset
121/// history before it, which it advances (RFC 8878 3.1.1.5: with no literals
122/// before the match the repeat codes shift by one, and the third is the
123/// first repeat offset less one).
124pub(crate) fn plain_offset(code: u32, lit_len: u32, history: &mut [u32; 3]) -> u32 {
125 if code > 3 {
126 let offset = code - 3;
127 history[2] = history[1];
128 history[1] = history[0];
129 history[0] = offset;
130 return offset;
131 }
132 let index = if lit_len == 0 { code } else { code - 1 };
133 let offset = match index {
134 0 => history[0],
135 1 => history[1],
136 2 => history[2],
137 // Wrapping as the decoder reads it: a history of 1 makes this 0,
138 // which a valid stream never asks for.
139 _ => history[0].wrapping_sub(1),
140 };
141 if index > 0 {
142 if index > 1 {
143 history[2] = history[1];
144 }
145 history[1] = history[0];
146 history[0] = offset;
147 }
148 offset
149}
150
151/// Why a parse cannot build a valid frame.
152#[derive(Copy, Clone, Debug, PartialEq, Eq)]
153#[non_exhaustive]
154pub enum SequenceError {
155 /// The parse covers more bytes than the input holds, or, with explicit
156 /// block delimiters, not exactly the input.
157 LengthMismatch,
158 /// Sequence `index` has an offset but matches fewer than [`MIN_MATCH`]
159 /// bytes; a run of literals alone is a delimiter, with offset 0.
160 MatchTooShort {
161 /// Index of the sequence.
162 index: usize,
163 },
164 /// Sequence `index` copies from further back than the output and the
165 /// dictionary reach, or than the window allows.
166 OffsetTooFar {
167 /// Index of the sequence.
168 index: usize,
169 },
170 /// Sequence `index` has a match but no offset.
171 ZeroOffset {
172 /// Index of the sequence.
173 index: usize,
174 },
175 /// A block between two delimiters is larger than `max_block`.
176 BlockTooLarge,
177 /// Sequence `index` copies bytes that differ from the ones the input has
178 /// where the copy lands, so the frame would decode to something else.
179 MatchMismatch {
180 /// Index of the sequence.
181 index: usize,
182 },
183}
184
185impl core::fmt::Display for SequenceError {
186 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
187 match self {
188 Self::LengthMismatch => f.write_str("the sequences do not cover the input"),
189 Self::MatchTooShort { index } => write!(f, "sequence {index} matches too few bytes"),
190 Self::OffsetTooFar { index } => write!(f, "sequence {index} copies from too far back"),
191 Self::ZeroOffset { index } => write!(f, "sequence {index} matches at offset 0"),
192 Self::BlockTooLarge => f.write_str("a block is larger than the block size"),
193 Self::MatchMismatch { index } => {
194 write!(f, "sequence {index} copies bytes the input does not hold")
195 }
196 }
197 }
198}
199
200#[cfg(feature = "std")]
201impl std::error::Error for SequenceError {}
202
203/// Check that `sequences` is a parse of `src_len` bytes a decoder can follow:
204/// every match at least [`MIN_MATCH`] bytes (literals with no match are a
205/// delimiter, offset 0), every
206/// offset within what is decoded so far plus `dict_len` bytes of dictionary
207/// while that fits the window, and within `window` after. With
208/// `explicit_delimiters` the parse must cover the input exactly and each
209/// delimited block hold at most `max_block` bytes; without, bytes past the
210/// parse are trailing literals.
211///
212/// ```
213/// use structured_zstd::encoding::sequences::{validate_parse, ExternalSequence, SequenceError};
214/// let parse = [ExternalSequence { offset: 3, lit_len: 3, match_len: 6, rep: 0 }];
215/// assert_eq!(validate_parse(&parse, 12, 1 << 20, 0, false, 1 << 17), Ok(()));
216/// let reaching = [ExternalSequence { offset: 9, lit_len: 3, match_len: 6, rep: 0 }];
217/// assert_eq!(
218/// validate_parse(&reaching, 12, 1 << 20, 0, false, 1 << 17),
219/// Err(SequenceError::OffsetTooFar { index: 0 })
220/// );
221/// ```
222pub fn validate_parse(
223 sequences: &[ExternalSequence],
224 src_len: usize,
225 window: u64,
226 dict_len: usize,
227 explicit_delimiters: bool,
228 max_block: usize,
229) -> Result<(), SequenceError> {
230 let mut position: u64 = 0;
231 let mut block_start: u64 = 0;
232 for (index, sequence) in sequences.iter().enumerate() {
233 position += u64::from(sequence.lit_len);
234 if sequence.is_delimiter() {
235 if explicit_delimiters {
236 if position - block_start > max_block as u64 {
237 return Err(SequenceError::BlockTooLarge);
238 }
239 block_start = position;
240 }
241 continue;
242 }
243 if sequence.offset == 0 {
244 return Err(SequenceError::ZeroOffset { index });
245 }
246 // A run of literals that ends the parse is a delimiter, handled above:
247 // with an offset it would be a match of no length (zstd.h,
248 // `ZSTD_Sequence`: offset 0 when matchLength is 0).
249 if sequence.match_len < MIN_MATCH {
250 return Err(SequenceError::MatchTooShort { index });
251 }
252 // RFC 8878 3.1.1.1.2 / 3.1.1.5: while the output is within the window
253 // a match may reach into the dictionary; past it, only the window.
254 let reach = if position > window {
255 window
256 } else {
257 position + dict_len as u64
258 };
259 if u64::from(sequence.offset) > reach {
260 return Err(SequenceError::OffsetTooFar { index });
261 }
262 position += u64::from(sequence.match_len);
263 if position > src_len as u64 {
264 return Err(SequenceError::LengthMismatch);
265 }
266 }
267 let covered = if explicit_delimiters {
268 position == src_len as u64
269 } else {
270 position <= src_len as u64
271 };
272 if !covered {
273 return Err(SequenceError::LengthMismatch);
274 }
275 Ok(())
276}
277
278/// Check that `sequences` decodes to `src`: every match copies the bytes the
279/// input holds where it lands, out of `src` itself or, reaching before the
280/// start, out of the tail of `dict`. A parse that [`validate_parse`] accepts
281/// can still describe different bytes; compressing it would make a frame that
282/// decodes to them, not to `src`.
283///
284/// The decoder has rebuilt the input up to each match, so the input stands
285/// for the output it copies from, overlapping copies included.
286///
287/// # Errors
288/// [`SequenceError::MatchMismatch`] for the first match that copies other
289/// bytes, [`SequenceError::LengthMismatch`] or [`SequenceError::OffsetTooFar`]
290/// for a parse [`validate_parse`] would also refuse.
291///
292/// ```
293/// use structured_zstd::encoding::sequences::{parse_reproduces, ExternalSequence, SequenceError};
294/// let parse = [ExternalSequence { offset: 3, lit_len: 3, match_len: 3, rep: 0 }];
295/// assert_eq!(parse_reproduces(&parse, b"abcabc", &[]), Ok(()));
296/// assert_eq!(
297/// parse_reproduces(&parse, b"abcabd", &[]),
298/// Err(SequenceError::MatchMismatch { index: 0 })
299/// );
300/// ```
301pub fn parse_reproduces(
302 sequences: &[ExternalSequence],
303 src: &[u8],
304 dict: &[u8],
305) -> Result<(), SequenceError> {
306 let mut position = 0usize;
307 for (index, sequence) in sequences.iter().enumerate() {
308 position = position
309 .checked_add(sequence.lit_len as usize)
310 .ok_or(SequenceError::LengthMismatch)?;
311 if sequence.is_delimiter() {
312 continue;
313 }
314 let offset = sequence.offset as usize;
315 let len = sequence.match_len as usize;
316 let end = position
317 .checked_add(len)
318 .filter(|&end| end <= src.len())
319 .ok_or(SequenceError::LengthMismatch)?;
320 let target = &src[position..end];
321 // The bytes copied from before the input come from the dictionary's
322 // tail; the rest from the input.
323 let from_dict = if offset > position {
324 (offset - position).min(len)
325 } else {
326 0
327 };
328 if from_dict > 0 {
329 let start = dict
330 .len()
331 .checked_sub(offset - position)
332 .ok_or(SequenceError::OffsetTooFar { index })?;
333 if dict[start..start + from_dict] != target[..from_dict] {
334 return Err(SequenceError::MatchMismatch { index });
335 }
336 }
337 if len > from_dict {
338 // `offset <= position + from_dict` here: a dictionary part ends
339 // exactly at the start of the input.
340 let from = position + from_dict - offset;
341 if src[from..from + (len - from_dict)] != target[from_dict..] {
342 return Err(SequenceError::MatchMismatch { index });
343 }
344 }
345 position = end;
346 }
347 Ok(())
348}
349
350/// The input a parse decodes to, rebuilt from its literals as it is read, as
351/// a decoder would (C `ZSTD_compressSequencesAndLiterals` takes the literals
352/// rather than the input). Matches reaching before the start read from
353/// `dict`; literals past the last sequence are the trailing ones. Only the
354/// last `window` bytes are held for the matches to copy from (more only
355/// while a match reaching further, into the dictionary, is being copied), so
356/// a frame is built from it without the whole input in memory.
357///
358/// ```
359/// use structured_zstd::encoding::sequences::{ExternalSequence, RebuiltSource};
360/// use std::io::Read;
361/// let parse = [
362/// ExternalSequence { offset: 3, lit_len: 3, match_len: 6, rep: 0 },
363/// ExternalSequence { offset: 0, lit_len: 1, match_len: 0, rep: 0 },
364/// ];
365/// let mut source = RebuiltSource::new(&parse, b"abc!", &[], 1 << 10).unwrap();
366/// assert_eq!(source.len(), 10);
367/// let mut out = Vec::new();
368/// source.read_to_end(&mut out).unwrap();
369/// assert_eq!(out, b"abcabcabc!");
370/// ```
371pub struct RebuiltSource<'a> {
372 sequences: core::slice::Iter<'a, ExternalSequence>,
373 literals: &'a [u8],
374 dict: &'a [u8],
375 window: usize,
376 /// Literals handed out so far.
377 lit_at: usize,
378 /// Literals of the sequence in hand still to come.
379 lit_left: usize,
380 /// Bytes of the match in hand still to come, and its offset.
381 match_left: usize,
382 offset: usize,
383 /// Bytes rebuilt so far.
384 produced: usize,
385 /// The bytes most recently rebuilt: at least the last `window` of them,
386 /// and as far back as the match in hand reaches.
387 history: Vec<u8>,
388 len: usize,
389}
390
391impl<'a> RebuiltSource<'a> {
392 /// Check that `sequences` and `literals` rebuild to a whole input with
393 /// every match within the output so far plus `dict` while the output is
394 /// within `window`, and within `window` after (as [`validate_parse`]
395 /// checks), and set up to read it.
396 ///
397 /// # Errors
398 /// [`SequenceError::LengthMismatch`] when the sequences need more literals
399 /// than there are, [`SequenceError::OffsetTooFar`] when a match reaches
400 /// further back than that, [`SequenceError::ZeroOffset`] for a match at
401 /// offset 0.
402 pub fn new(
403 sequences: &'a [ExternalSequence],
404 literals: &'a [u8],
405 dict: &'a [u8],
406 window: usize,
407 ) -> Result<Self, SequenceError> {
408 let mut position = 0usize;
409 let mut lits = 0usize;
410 for (index, sequence) in sequences.iter().enumerate() {
411 let lit_len = sequence.lit_len as usize;
412 lits = lits
413 .checked_add(lit_len)
414 .filter(|lits| *lits <= literals.len())
415 .ok_or(SequenceError::LengthMismatch)?;
416 // Within the literals, so within `usize`.
417 position += lit_len;
418 if sequence.match_len == 0 {
419 continue;
420 }
421 let offset = sequence.offset as usize;
422 if offset == 0 {
423 return Err(SequenceError::ZeroOffset { index });
424 }
425 // RFC 8878 3.1.1.1.2 / 3.1.1.5, as `validate_parse` reads them:
426 // while the output is within the window a match may reach into
427 // the dictionary; past it, only the window. A reach past `usize`
428 // holds any offset.
429 let past_reach = if position > window {
430 offset > window
431 } else {
432 position
433 .checked_add(dict.len())
434 .is_some_and(|reach| offset > reach)
435 };
436 if past_reach {
437 return Err(SequenceError::OffsetTooFar { index });
438 }
439 position = position
440 .checked_add(sequence.match_len as usize)
441 .ok_or(SequenceError::LengthMismatch)?;
442 }
443 let len = position
444 .checked_add(literals.len() - lits)
445 .ok_or(SequenceError::LengthMismatch)?;
446 Ok(Self {
447 sequences: sequences.iter(),
448 literals,
449 dict,
450 window,
451 lit_at: 0,
452 lit_left: 0,
453 match_left: 0,
454 offset: 0,
455 produced: 0,
456 history: Vec::new(),
457 len,
458 })
459 }
460
461 /// Bytes the source rebuilds in all.
462 pub fn len(&self) -> usize {
463 self.len
464 }
465
466 /// Whether the source rebuilds nothing.
467 pub fn is_empty(&self) -> bool {
468 self.len == 0
469 }
470
471 /// Rebuild up to `want` bytes of the match in hand onto `history`.
472 fn copy_match(&mut self, want: usize) {
473 let mut left = want;
474 while left > 0 {
475 let take = if self.offset > self.produced {
476 // The match starts in the dictionary and runs on into the
477 // output; `new` checked the dictionary reaches that far.
478 let back = self.offset - self.produced;
479 let from = self.dict.len() - back;
480 let take = left.min(back);
481 self.history
482 .extend_from_slice(&self.dict[from..from + take]);
483 take
484 } else {
485 // `history` holds the last `window` bytes, and as far back as
486 // this match reaches (a match past the window starts while the
487 // output is within it, when nothing has been let go yet). An
488 // overlapping match repeats its first `offset` bytes.
489 let from = self.history.len() - self.offset;
490 let take = left.min(self.offset);
491 self.history.extend_from_within(from..from + take);
492 take
493 };
494 self.produced += take;
495 left -= take;
496 }
497 self.match_left -= want;
498 }
499}
500
501impl crate::io::Read for RebuiltSource<'_> {
502 fn read(&mut self, buf: &mut [u8]) -> Result<usize, crate::io::Error> {
503 let mut filled = 0;
504 while filled < buf.len() {
505 let room = buf.len() - filled;
506 let start = self.history.len();
507 if self.lit_left > 0 {
508 let n = self.lit_left.min(room);
509 self.history
510 .extend_from_slice(&self.literals[self.lit_at..self.lit_at + n]);
511 self.lit_at += n;
512 self.lit_left -= n;
513 self.produced += n;
514 } else if self.match_left > 0 {
515 self.copy_match(self.match_left.min(room));
516 } else if let Some(sequence) = self.sequences.next() {
517 self.lit_left = sequence.lit_len as usize;
518 self.match_left = sequence.match_len as usize;
519 self.offset = sequence.offset as usize;
520 continue;
521 } else if self.lit_at < self.literals.len() {
522 self.lit_left = self.literals.len() - self.lit_at;
523 continue;
524 } else {
525 break;
526 }
527 let n = self.history.len() - start;
528 buf[filled..filled + n].copy_from_slice(&self.history[start..]);
529 filled += n;
530 }
531 // Keep what the matches still to come can reach: the window, and the
532 // match in hand's reach while it lasts (later matches stay within the
533 // window, as `new` checked). The rest goes a `keep`'s worth at a time,
534 // so the drain is paid once per that many bytes; a `keep` past half
535 // of `usize` never fills twice over.
536 let keep = if self.match_left > 0 {
537 self.window.max(self.offset)
538 } else {
539 self.window
540 };
541 if keep
542 .checked_mul(2)
543 .is_some_and(|limit| self.history.len() > limit)
544 {
545 let drop = self.history.len() - keep;
546 self.history.drain(..drop);
547 }
548 Ok(filled)
549 }
550}
551
552/// A [`Matcher`] that reports a given parse instead of searching, so the
553/// ordinary block pipeline builds a frame from it (C
554/// `ZSTD_compressSequences`). The parse is consumed as blocks are cut:
555/// wherever the encoder ends a block, a sequence running across the cut is
556/// split there, and a match piece shorter than [`MIN_MATCH`] goes out as
557/// literals. Block delimiters, if any, end blocks: each delimited region is
558/// a block of its own, cut further only where it exceeds the block size.
559///
560/// The parse should pass [`validate_parse`]: offsets are taken as given.
561///
562/// ```
563/// use structured_zstd::encoding::sequences::{ExternalSequence, SequenceReplay};
564/// use structured_zstd::encoding::{CompressionLevel, FrameCompressor};
565///
566/// let input = b"abcabcabcabc";
567/// let parse = [ExternalSequence { offset: 3, lit_len: 3, match_len: 9, rep: 0 }];
568/// let replay = SequenceReplay::new(&parse, 1 << 10);
569/// let mut frame = Vec::new();
570/// let mut compressor = FrameCompressor::new_with_matcher(replay, CompressionLevel::Default);
571/// compressor.set_source(&input[..]);
572/// compressor.set_drain(&mut frame);
573/// compressor.compress();
574/// # let mut decoded = Vec::with_capacity(input.len());
575/// # structured_zstd::decoding::FrameDecoder::new().decode_all_to_vec(&frame, &mut decoded).unwrap();
576/// # assert_eq!(decoded, input);
577/// ```
578pub struct SequenceReplay<'s> {
579 sequences: &'s [ExternalSequence],
580 /// The sequence the next block continues.
581 next: usize,
582 /// Literal bytes of `sequences[next]` earlier blocks took.
583 lit_taken: u32,
584 /// Match bytes of `sequences[next]` earlier blocks took.
585 match_taken: u32,
586 input: BlockInput,
587 window_size: u64,
588 dictionary_priming: bool,
589 /// The parse holds block delimiters, which then lay the blocks out.
590 delimited: bool,
591}
592
593impl<'s> SequenceReplay<'s> {
594 /// Replay `sequences` into frames whose window is `window_size` bytes,
595 /// which every offset must respect.
596 pub fn new(sequences: &'s [ExternalSequence], window_size: u64) -> Self {
597 Self {
598 sequences,
599 next: 0,
600 lit_taken: 0,
601 match_taken: 0,
602 input: BlockInput::default(),
603 window_size,
604 dictionary_priming: false,
605 delimited: sequences.iter().any(ExternalSequence::is_delimiter),
606 }
607 }
608
609 /// Let the frame use the compressor's dictionary: its ID goes in the
610 /// header and its entropy and repeat offsets seed the first block, so
611 /// offsets may reach into its content.
612 pub fn with_dictionary(mut self) -> Self {
613 self.dictionary_priming = true;
614 self
615 }
616
617 /// Step past `len` bytes of the parse without reporting them, for a block
618 /// the encoder writes out unsearched.
619 fn skip(&mut self, len: usize) {
620 self.walk(len, &mut |_| {});
621 }
622
623 /// Report the parse for the next `len` bytes through `emit`.
624 fn walk(&mut self, len: usize, emit: &mut dyn FnMut(Sequence)) {
625 let mut remaining = len as u64;
626 let mut literals = 0usize;
627 while remaining > 0 {
628 let Some(sequence) = self.sequences.get(self.next) else {
629 break;
630 };
631 let lits_left = sequence.lit_len - self.lit_taken;
632 let take = u64::from(lits_left).min(remaining) as u32;
633 self.lit_taken += take;
634 literals += take as usize;
635 remaining -= u64::from(take);
636 if self.lit_taken < sequence.lit_len {
637 break;
638 }
639 let match_left = sequence.match_len - self.match_taken;
640 let take = u64::from(match_left).min(remaining) as u32;
641 if take > 0 {
642 // A piece the cut left shorter than a match can be goes out
643 // as literals: they are the same bytes either way, and the
644 // rest of the match continues in the next block.
645 if take >= MIN_MATCH {
646 emit(Sequence::Triple {
647 literal_len: literals,
648 offset: sequence.offset as usize,
649 match_len: take as usize,
650 });
651 literals = 0;
652 } else {
653 literals += take as usize;
654 }
655 self.match_taken += take;
656 remaining -= u64::from(take);
657 }
658 if self.match_taken == sequence.match_len {
659 self.next += 1;
660 self.lit_taken = 0;
661 self.match_taken = 0;
662 }
663 }
664 // Whatever the parse does not cover is literals.
665 literals += remaining as usize;
666 if literals > 0 {
667 emit(Sequence::Literals { len: literals });
668 }
669 }
670}
671
672impl Matcher for SequenceReplay<'_> {
673 fn get_last_space(&mut self) -> &[u8] {
674 self.input.last_block()
675 }
676
677 fn fill_in_place(
678 &mut self,
679 capacity: usize,
680 fill: &mut dyn FnMut(&mut HistoryBuf) -> (usize, bool),
681 ) -> (usize, bool) {
682 self.input.fill(capacity, fill)
683 }
684
685 fn uncommitted_input(&self) -> &[u8] {
686 self.input.uncommitted()
687 }
688
689 fn commit_filled(&mut self, len: usize) {
690 self.input.commit(len);
691 }
692
693 fn skip_matching(&mut self) {
694 let len = self.input.last_block().len();
695 self.skip(len);
696 }
697
698 fn start_matching(&mut self, mut handle_sequence: impl FnMut(Sequence)) {
699 let len = self.input.last_block().len();
700 self.walk(len, &mut handle_sequence);
701 }
702
703 fn reset(&mut self, _level: CompressionLevel) {
704 self.input.clear();
705 self.next = 0;
706 self.lit_taken = 0;
707 self.match_taken = 0;
708 }
709
710 fn supports_dictionary_priming(&self) -> bool {
711 self.dictionary_priming
712 }
713
714 fn window_size(&self) -> u64 {
715 self.window_size
716 }
717
718 /// The rest of the region up to the next block delimiter, skipping
719 /// regions with nothing in them.
720 fn fixed_block_len(&self) -> Option<usize> {
721 if !self.delimited {
722 return None;
723 }
724 let mut len = 0u64;
725 let (mut lit_taken, mut match_taken) = (self.lit_taken, self.match_taken);
726 for sequence in &self.sequences[self.next..] {
727 len += u64::from(sequence.lit_len - lit_taken)
728 + u64::from(sequence.match_len - match_taken);
729 (lit_taken, match_taken) = (0, 0);
730 if sequence.is_delimiter() && len > 0 {
731 return usize::try_from(len).ok();
732 }
733 }
734 None
735 }
736}
737
738/// Why a [`SequenceProducer`] gave no parse for a block.
739#[derive(Copy, Clone, Debug, PartialEq, Eq)]
740pub struct SequenceProducerError;
741
742/// A parser asked for each block in place of the built-in match finder (C
743/// `ZSTD_registerSequenceProducer`). Its parse covers the block alone, with
744/// no history before it.
745pub trait SequenceProducer {
746 /// Append a parse of `block` to `out`: matches only within `block`, at
747 /// most `window_size` back, ending with a sequence of no match, or one
748 /// whose match reaches the end.
749 ///
750 /// # Errors
751 /// [`SequenceProducerError`] when there is no parse; the encoder then
752 /// falls back to its own match finder or fails the frame, as configured.
753 fn produce(
754 &mut self,
755 block: &[u8],
756 window_size: u64,
757 out: &mut Vec<ExternalSequence>,
758 ) -> Result<(), SequenceProducerError>;
759}
760
761#[cfg(test)]
762mod tests;