Skip to main content

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;