ruzstd/decoding/
sequence_execution.rs1use super::{decodebuffer::DecodeBufferError, scratch::DecoderScratch};
2
3#[derive(Debug)]
4#[non_exhaustive]
5pub enum ExecuteSequencesError {
6 DecodebufferError(DecodeBufferError),
7 NotEnoughBytesForSequence { wanted: usize, have: usize },
8 ZeroOffset,
9}
10
11impl core::fmt::Display for ExecuteSequencesError {
12 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
13 match self {
14 ExecuteSequencesError::DecodebufferError(e) => {
15 write!(f, "{:?}", e)
16 }
17 ExecuteSequencesError::NotEnoughBytesForSequence { wanted, have } => {
18 write!(
19 f,
20 "Sequence wants to copy up to byte {}. Bytes in literalsbuffer: {}",
21 wanted, have
22 )
23 }
24 ExecuteSequencesError::ZeroOffset => {
25 write!(f, "Illegal offset: 0 found")
26 }
27 }
28 }
29}
30
31#[cfg(feature = "std")]
32impl std::error::Error for ExecuteSequencesError {
33 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
34 match self {
35 ExecuteSequencesError::DecodebufferError(source) => Some(source),
36 _ => None,
37 }
38 }
39}
40
41impl From<DecodeBufferError> for ExecuteSequencesError {
42 fn from(val: DecodeBufferError) -> Self {
43 Self::DecodebufferError(val)
44 }
45}
46
47pub fn execute_sequences(scratch: &mut DecoderScratch) -> Result<(), ExecuteSequencesError> {
49 let mut literals_copy_counter = 0;
50 let old_buffer_size = scratch.buffer.len();
51 let mut seq_sum = 0;
52
53 for idx in 0..scratch.sequences.len() {
54 let seq = scratch.sequences[idx];
55
56 if seq.ll > 0 {
57 let high = literals_copy_counter + seq.ll as usize;
58 if high > scratch.literals_buffer.len() {
59 return Err(ExecuteSequencesError::NotEnoughBytesForSequence {
60 wanted: high,
61 have: scratch.literals_buffer.len(),
62 });
63 }
64 let literals = &scratch.literals_buffer[literals_copy_counter..high];
65 literals_copy_counter += seq.ll as usize;
66
67 scratch.buffer.push(literals);
68 }
69
70 let actual_offset = do_offset_history(seq.of, seq.ll, &mut scratch.offset_hist);
71 if actual_offset == 0 {
72 return Err(ExecuteSequencesError::ZeroOffset);
73 }
74 if seq.ml > 0 {
75 scratch
76 .buffer
77 .repeat(actual_offset as usize, seq.ml as usize)?;
78 }
79
80 seq_sum += seq.ml;
81 seq_sum += seq.ll;
82 }
83 if literals_copy_counter < scratch.literals_buffer.len() {
84 let rest_literals = &scratch.literals_buffer[literals_copy_counter..];
85 scratch.buffer.push(rest_literals);
86 seq_sum += rest_literals.len() as u32;
87 }
88
89 let diff = scratch.buffer.len() - old_buffer_size;
90 assert!(
91 seq_sum as usize == diff,
92 "Seq_sum: {} is different from the difference in buffersize: {}",
93 seq_sum,
94 diff
95 );
96 Ok(())
97}
98
99fn do_offset_history(offset_value: u32, lit_len: u32, scratch: &mut [u32; 3]) -> u32 {
103 let actual_offset = if lit_len > 0 {
104 match offset_value {
105 1..=3 => scratch[offset_value as usize - 1],
106 _ => {
107 offset_value - 3
109 }
110 }
111 } else {
112 match offset_value {
113 1..=2 => scratch[offset_value as usize],
114 3 => scratch[0] - 1,
115 _ => {
116 offset_value - 3
118 }
119 }
120 };
121
122 if lit_len > 0 {
124 match offset_value {
125 1 => {
126 }
128 2 => {
129 scratch[1] = scratch[0];
130 scratch[0] = actual_offset;
131 }
132 _ => {
133 scratch[2] = scratch[1];
134 scratch[1] = scratch[0];
135 scratch[0] = actual_offset;
136 }
137 }
138 } else {
139 match offset_value {
140 1 => {
141 scratch[1] = scratch[0];
142 scratch[0] = actual_offset;
143 }
144 2 => {
145 scratch[2] = scratch[1];
146 scratch[1] = scratch[0];
147 scratch[0] = actual_offset;
148 }
149 _ => {
150 scratch[2] = scratch[1];
151 scratch[1] = scratch[0];
152 scratch[0] = actual_offset;
153 }
154 }
155 }
156
157 actual_offset
158}