Coverage Report

Created: 2026-06-07 07:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/lz4_flex/src/frame/decompress.rs
Line
Count
Source
1
use std::{
2
    fmt,
3
    hash::Hasher,
4
    io::{self, BufRead, ErrorKind},
5
    mem::size_of,
6
};
7
use twox_hash::XxHash32;
8
9
use super::header::{
10
    BlockInfo, BlockMode, FrameInfo, LZ4F_LEGACY_MAGIC_NUMBER, MAGIC_NUMBER_SIZE,
11
    MAX_FRAME_INFO_SIZE, MIN_FRAME_INFO_SIZE,
12
};
13
use super::Error;
14
use crate::{
15
    block::WINDOW_SIZE,
16
    sink::{vec_sink_for_decompression, SliceSink},
17
};
18
19
/// A reader for decompressing the LZ4 frame format
20
///
21
/// This Decoder wraps any other reader that implements `io::Read`.
22
/// Bytes read will be decompressed according to the [LZ4 frame format](
23
/// https://github.com/lz4/lz4/blob/dev/doc/lz4_Frame_format.md).
24
///
25
/// # Example 1
26
/// Deserializing json values out of a compressed file.
27
///
28
/// ```no_run
29
/// let compressed_input = std::fs::File::open("datafile").unwrap();
30
/// let mut decompressed_input = lz4_flex::frame::FrameDecoder::new(compressed_input);
31
/// let json: serde_json::Value = serde_json::from_reader(decompressed_input).unwrap();
32
/// ```
33
///
34
/// # Example
35
/// Deserializing multiple json values out of a compressed file
36
///
37
/// ```no_run
38
/// let compressed_input = std::fs::File::open("datafile").unwrap();
39
/// let mut decompressed_input = lz4_flex::frame::FrameDecoder::new(compressed_input);
40
/// loop {
41
///     match serde_json::from_reader::<_, serde_json::Value>(&mut decompressed_input) {
42
///         Ok(json) => { println!("json {:?}", json); }
43
///         Err(e) if e.is_eof() => break,
44
///         Err(e) => panic!("{}", e),
45
///     }
46
/// }
47
/// ```
48
pub struct FrameDecoder<R: io::Read> {
49
    /// The underlying reader.
50
    r: R,
51
    /// The FrameInfo of the frame currently being decoded.
52
    /// It starts as `None` and is filled with the FrameInfo is read from the input.
53
    /// It's reset to `None` once the frame EndMarker is read from the input.
54
    current_frame_info: Option<FrameInfo>,
55
    /// Xxhash32 used when content checksum is enabled.
56
    content_hasher: XxHash32,
57
    /// Total length of decompressed output for the current frame.
58
    content_len: u64,
59
    /// The compressed bytes buffer, taken from the underlying reader.
60
    src: Vec<u8>,
61
    /// The decompressed bytes buffer. Bytes are decompressed from src to dst
62
    /// before being passed back to the caller.
63
    dst: Vec<u8>,
64
    /// Index into dst and length: starting point of bytes previously output
65
    /// that are still part of the decompressor window.
66
    ext_dict_offset: usize,
67
    ext_dict_len: usize,
68
    /// Index into dst: starting point of bytes not yet read by caller.
69
    dst_start: usize,
70
    /// Index into dst: ending point of bytes not yet read by caller.
71
    dst_end: usize,
72
}
73
74
impl<R: io::Read> FrameDecoder<R> {
75
    /// Creates a new Decoder for the specified reader.
76
39.3k
    pub fn new(rdr: R) -> FrameDecoder<R> {
77
39.3k
        FrameDecoder {
78
39.3k
            r: rdr,
79
39.3k
            src: Default::default(),
80
39.3k
            dst: Default::default(),
81
39.3k
            ext_dict_offset: 0,
82
39.3k
            ext_dict_len: 0,
83
39.3k
            dst_start: 0,
84
39.3k
            dst_end: 0,
85
39.3k
            current_frame_info: None,
86
39.3k
            content_hasher: XxHash32::with_seed(0),
87
39.3k
            content_len: 0,
88
39.3k
        }
89
39.3k
    }
<lz4_flex::frame::decompress::FrameDecoder<&[u8]>>::new
Line
Count
Source
76
17.1k
    pub fn new(rdr: R) -> FrameDecoder<R> {
77
17.1k
        FrameDecoder {
78
17.1k
            r: rdr,
79
17.1k
            src: Default::default(),
80
17.1k
            dst: Default::default(),
81
17.1k
            ext_dict_offset: 0,
82
17.1k
            ext_dict_len: 0,
83
17.1k
            dst_start: 0,
84
17.1k
            dst_end: 0,
85
17.1k
            current_frame_info: None,
86
17.1k
            content_hasher: XxHash32::with_seed(0),
87
17.1k
            content_len: 0,
88
17.1k
        }
89
17.1k
    }
Unexecuted instantiation: <lz4_flex::frame::decompress::FrameDecoder<_>>::new
<lz4_flex::frame::decompress::FrameDecoder<&[u8]>>::new
Line
Count
Source
76
22.1k
    pub fn new(rdr: R) -> FrameDecoder<R> {
77
22.1k
        FrameDecoder {
78
22.1k
            r: rdr,
79
22.1k
            src: Default::default(),
80
22.1k
            dst: Default::default(),
81
22.1k
            ext_dict_offset: 0,
82
22.1k
            ext_dict_len: 0,
83
22.1k
            dst_start: 0,
84
22.1k
            dst_end: 0,
85
22.1k
            current_frame_info: None,
86
22.1k
            content_hasher: XxHash32::with_seed(0),
87
22.1k
            content_len: 0,
88
22.1k
        }
89
22.1k
    }
90
91
    /// Gets a reference to the underlying reader in this decoder.
92
0
    pub fn get_ref(&self) -> &R {
93
0
        &self.r
94
0
    }
95
96
    /// Gets a mutable reference to the underlying reader in this decoder.
97
    ///
98
    /// Note that mutation of the stream may result in surprising results if
99
    /// this decoder is continued to be used.
100
0
    pub fn get_mut(&mut self) -> &mut R {
101
0
        &mut self.r
102
0
    }
103
104
    /// Consumes the FrameDecoder and returns the underlying reader.
105
0
    pub fn into_inner(self) -> R {
106
0
        self.r
107
0
    }
108
109
39.3k
    fn read_frame_info(&mut self) -> Result<usize, io::Error> {
110
39.3k
        let mut buffer = [0u8; MAX_FRAME_INFO_SIZE];
111
112
39.3k
        match self.r.read(&mut buffer[..MAGIC_NUMBER_SIZE])? {
113
0
            0 => return Ok(0),
114
39.0k
            MAGIC_NUMBER_SIZE => (),
115
226
            read => self.r.read_exact(&mut buffer[read..MAGIC_NUMBER_SIZE])?,
116
        }
117
118
39.0k
        if u32::from_le_bytes(buffer[0..MAGIC_NUMBER_SIZE].try_into().unwrap())
119
39.0k
            != LZ4F_LEGACY_MAGIC_NUMBER
120
        {
121
38.7k
            match self
122
38.7k
                .r
123
38.7k
                .read(&mut buffer[MAGIC_NUMBER_SIZE..MIN_FRAME_INFO_SIZE])?
124
            {
125
348
                0 => return Ok(0),
126
0
                MIN_FRAME_INFO_SIZE => (),
127
38.3k
                read => self
128
38.3k
                    .r
129
38.3k
                    .read_exact(&mut buffer[MAGIC_NUMBER_SIZE + read..MIN_FRAME_INFO_SIZE])?,
130
            }
131
388
        }
132
38.5k
        let required = FrameInfo::read_size(&buffer[..MIN_FRAME_INFO_SIZE])?;
133
33.9k
        if required != MIN_FRAME_INFO_SIZE && required != MAGIC_NUMBER_SIZE {
134
2.00k
            self.r
135
2.00k
                .read_exact(&mut buffer[MIN_FRAME_INFO_SIZE..required])?;
136
31.9k
        }
137
138
33.6k
        let frame_info = FrameInfo::read(&buffer[..required])?;
139
31.4k
        if frame_info.dict_id.is_some() {
140
            // Unsupported right now so it must be None
141
6
            return Err(Error::DictionaryNotSupported.into());
142
31.4k
        }
143
144
31.4k
        let max_block_size = frame_info.block_size.get_size();
145
31.4k
        let dst_size = if frame_info.block_mode == BlockMode::Linked {
146
            // In linked mode we consume the output (bumping dst_start) but leave the
147
            // beginning of dst to be used as a prefix in subsequent blocks.
148
            // That is at least until we have at least `max_block_size + WINDOW_SIZE`
149
            // bytes in dst, then we setup an ext_dict with the last WINDOW_SIZE bytes
150
            // and the output goes to the beginning of dst again.
151
            // Since we always want to be able to write a full block (up to max_block_size)
152
            // we need a buffer with at least `max_block_size * 2 + WINDOW_SIZE` bytes.
153
15.5k
            max_block_size * 2 + WINDOW_SIZE
154
        } else {
155
15.9k
            max_block_size
156
        };
157
31.4k
        self.src.clear();
158
31.4k
        self.dst.clear();
159
31.4k
        self.src.reserve_exact(max_block_size);
160
31.4k
        self.dst.reserve_exact(dst_size);
161
31.4k
        self.current_frame_info = Some(frame_info);
162
31.4k
        self.content_hasher = XxHash32::with_seed(0);
163
31.4k
        self.content_len = 0;
164
31.4k
        self.ext_dict_len = 0;
165
31.4k
        self.dst_start = 0;
166
31.4k
        self.dst_end = 0;
167
31.4k
        Ok(required)
168
39.3k
    }
<lz4_flex::frame::decompress::FrameDecoder<&[u8]>>::read_frame_info
Line
Count
Source
109
17.1k
    fn read_frame_info(&mut self) -> Result<usize, io::Error> {
110
17.1k
        let mut buffer = [0u8; MAX_FRAME_INFO_SIZE];
111
112
17.1k
        match self.r.read(&mut buffer[..MAGIC_NUMBER_SIZE])? {
113
0
            0 => return Ok(0),
114
17.1k
            MAGIC_NUMBER_SIZE => (),
115
0
            read => self.r.read_exact(&mut buffer[read..MAGIC_NUMBER_SIZE])?,
116
        }
117
118
17.1k
        if u32::from_le_bytes(buffer[0..MAGIC_NUMBER_SIZE].try_into().unwrap())
119
17.1k
            != LZ4F_LEGACY_MAGIC_NUMBER
120
        {
121
17.1k
            match self
122
17.1k
                .r
123
17.1k
                .read(&mut buffer[MAGIC_NUMBER_SIZE..MIN_FRAME_INFO_SIZE])?
124
            {
125
0
                0 => return Ok(0),
126
0
                MIN_FRAME_INFO_SIZE => (),
127
17.1k
                read => self
128
17.1k
                    .r
129
17.1k
                    .read_exact(&mut buffer[MAGIC_NUMBER_SIZE + read..MIN_FRAME_INFO_SIZE])?,
130
            }
131
0
        }
132
17.1k
        let required = FrameInfo::read_size(&buffer[..MIN_FRAME_INFO_SIZE])?;
133
17.1k
        if required != MIN_FRAME_INFO_SIZE && required != MAGIC_NUMBER_SIZE {
134
0
            self.r
135
0
                .read_exact(&mut buffer[MIN_FRAME_INFO_SIZE..required])?;
136
17.1k
        }
137
138
17.1k
        let frame_info = FrameInfo::read(&buffer[..required])?;
139
17.1k
        if frame_info.dict_id.is_some() {
140
            // Unsupported right now so it must be None
141
0
            return Err(Error::DictionaryNotSupported.into());
142
17.1k
        }
143
144
17.1k
        let max_block_size = frame_info.block_size.get_size();
145
17.1k
        let dst_size = if frame_info.block_mode == BlockMode::Linked {
146
            // In linked mode we consume the output (bumping dst_start) but leave the
147
            // beginning of dst to be used as a prefix in subsequent blocks.
148
            // That is at least until we have at least `max_block_size + WINDOW_SIZE`
149
            // bytes in dst, then we setup an ext_dict with the last WINDOW_SIZE bytes
150
            // and the output goes to the beginning of dst again.
151
            // Since we always want to be able to write a full block (up to max_block_size)
152
            // we need a buffer with at least `max_block_size * 2 + WINDOW_SIZE` bytes.
153
8.57k
            max_block_size * 2 + WINDOW_SIZE
154
        } else {
155
8.57k
            max_block_size
156
        };
157
17.1k
        self.src.clear();
158
17.1k
        self.dst.clear();
159
17.1k
        self.src.reserve_exact(max_block_size);
160
17.1k
        self.dst.reserve_exact(dst_size);
161
17.1k
        self.current_frame_info = Some(frame_info);
162
17.1k
        self.content_hasher = XxHash32::with_seed(0);
163
17.1k
        self.content_len = 0;
164
17.1k
        self.ext_dict_len = 0;
165
17.1k
        self.dst_start = 0;
166
17.1k
        self.dst_end = 0;
167
17.1k
        Ok(required)
168
17.1k
    }
Unexecuted instantiation: <lz4_flex::frame::decompress::FrameDecoder<_>>::read_frame_info
<lz4_flex::frame::decompress::FrameDecoder<&[u8]>>::read_frame_info
Line
Count
Source
109
22.1k
    fn read_frame_info(&mut self) -> Result<usize, io::Error> {
110
22.1k
        let mut buffer = [0u8; MAX_FRAME_INFO_SIZE];
111
112
22.1k
        match self.r.read(&mut buffer[..MAGIC_NUMBER_SIZE])? {
113
0
            0 => return Ok(0),
114
21.9k
            MAGIC_NUMBER_SIZE => (),
115
226
            read => self.r.read_exact(&mut buffer[read..MAGIC_NUMBER_SIZE])?,
116
        }
117
118
21.9k
        if u32::from_le_bytes(buffer[0..MAGIC_NUMBER_SIZE].try_into().unwrap())
119
21.9k
            != LZ4F_LEGACY_MAGIC_NUMBER
120
        {
121
21.5k
            match self
122
21.5k
                .r
123
21.5k
                .read(&mut buffer[MAGIC_NUMBER_SIZE..MIN_FRAME_INFO_SIZE])?
124
            {
125
348
                0 => return Ok(0),
126
0
                MIN_FRAME_INFO_SIZE => (),
127
21.2k
                read => self
128
21.2k
                    .r
129
21.2k
                    .read_exact(&mut buffer[MAGIC_NUMBER_SIZE + read..MIN_FRAME_INFO_SIZE])?,
130
            }
131
388
        }
132
21.4k
        let required = FrameInfo::read_size(&buffer[..MIN_FRAME_INFO_SIZE])?;
133
16.8k
        if required != MIN_FRAME_INFO_SIZE && required != MAGIC_NUMBER_SIZE {
134
2.00k
            self.r
135
2.00k
                .read_exact(&mut buffer[MIN_FRAME_INFO_SIZE..required])?;
136
14.8k
        }
137
138
16.4k
        let frame_info = FrameInfo::read(&buffer[..required])?;
139
14.3k
        if frame_info.dict_id.is_some() {
140
            // Unsupported right now so it must be None
141
6
            return Err(Error::DictionaryNotSupported.into());
142
14.2k
        }
143
144
14.2k
        let max_block_size = frame_info.block_size.get_size();
145
14.2k
        let dst_size = if frame_info.block_mode == BlockMode::Linked {
146
            // In linked mode we consume the output (bumping dst_start) but leave the
147
            // beginning of dst to be used as a prefix in subsequent blocks.
148
            // That is at least until we have at least `max_block_size + WINDOW_SIZE`
149
            // bytes in dst, then we setup an ext_dict with the last WINDOW_SIZE bytes
150
            // and the output goes to the beginning of dst again.
151
            // Since we always want to be able to write a full block (up to max_block_size)
152
            // we need a buffer with at least `max_block_size * 2 + WINDOW_SIZE` bytes.
153
6.94k
            max_block_size * 2 + WINDOW_SIZE
154
        } else {
155
7.35k
            max_block_size
156
        };
157
14.2k
        self.src.clear();
158
14.2k
        self.dst.clear();
159
14.2k
        self.src.reserve_exact(max_block_size);
160
14.2k
        self.dst.reserve_exact(dst_size);
161
14.2k
        self.current_frame_info = Some(frame_info);
162
14.2k
        self.content_hasher = XxHash32::with_seed(0);
163
14.2k
        self.content_len = 0;
164
14.2k
        self.ext_dict_len = 0;
165
14.2k
        self.dst_start = 0;
166
14.2k
        self.dst_end = 0;
167
14.2k
        Ok(required)
168
22.1k
    }
169
170
    #[inline]
171
97.3M
    fn read_checksum(r: &mut R) -> Result<u32, io::Error> {
172
97.3M
        let mut checksum_buffer = [0u8; size_of::<u32>()];
173
97.3M
        r.read_exact(&mut checksum_buffer[..])?;
174
97.3M
        let checksum = u32::from_le_bytes(checksum_buffer);
175
97.3M
        Ok(checksum)
176
97.3M
    }
<lz4_flex::frame::decompress::FrameDecoder<&[u8]>>::read_checksum
Line
Count
Source
171
97.3M
    fn read_checksum(r: &mut R) -> Result<u32, io::Error> {
172
97.3M
        let mut checksum_buffer = [0u8; size_of::<u32>()];
173
97.3M
        r.read_exact(&mut checksum_buffer[..])?;
174
97.3M
        let checksum = u32::from_le_bytes(checksum_buffer);
175
97.3M
        Ok(checksum)
176
97.3M
    }
Unexecuted instantiation: <lz4_flex::frame::decompress::FrameDecoder<_>>::read_checksum
<lz4_flex::frame::decompress::FrameDecoder<&[u8]>>::read_checksum
Line
Count
Source
171
2.22k
    fn read_checksum(r: &mut R) -> Result<u32, io::Error> {
172
2.22k
        let mut checksum_buffer = [0u8; size_of::<u32>()];
173
2.22k
        r.read_exact(&mut checksum_buffer[..])?;
174
2.20k
        let checksum = u32::from_le_bytes(checksum_buffer);
175
2.20k
        Ok(checksum)
176
2.22k
    }
177
178
    #[inline]
179
97.3M
    fn check_block_checksum(data: &[u8], expected_checksum: u32) -> Result<(), io::Error> {
180
97.3M
        let mut block_hasher = XxHash32::with_seed(0);
181
97.3M
        block_hasher.write(data);
182
97.3M
        let calc_checksum = block_hasher.finish() as u32;
183
97.3M
        if calc_checksum != expected_checksum {
184
336
            return Err(Error::BlockChecksumError.into());
185
97.3M
        }
186
97.3M
        Ok(())
187
97.3M
    }
<lz4_flex::frame::decompress::FrameDecoder<&[u8]>>::check_block_checksum
Line
Count
Source
179
97.3M
    fn check_block_checksum(data: &[u8], expected_checksum: u32) -> Result<(), io::Error> {
180
97.3M
        let mut block_hasher = XxHash32::with_seed(0);
181
97.3M
        block_hasher.write(data);
182
97.3M
        let calc_checksum = block_hasher.finish() as u32;
183
97.3M
        if calc_checksum != expected_checksum {
184
0
            return Err(Error::BlockChecksumError.into());
185
97.3M
        }
186
97.3M
        Ok(())
187
97.3M
    }
Unexecuted instantiation: <lz4_flex::frame::decompress::FrameDecoder<_>>::check_block_checksum
<lz4_flex::frame::decompress::FrameDecoder<&[u8]>>::check_block_checksum
Line
Count
Source
179
2.08k
    fn check_block_checksum(data: &[u8], expected_checksum: u32) -> Result<(), io::Error> {
180
2.08k
        let mut block_hasher = XxHash32::with_seed(0);
181
2.08k
        block_hasher.write(data);
182
2.08k
        let calc_checksum = block_hasher.finish() as u32;
183
2.08k
        if calc_checksum != expected_checksum {
184
336
            return Err(Error::BlockChecksumError.into());
185
1.75k
        }
186
1.75k
        Ok(())
187
2.08k
    }
188
189
194M
    fn read_block(&mut self) -> io::Result<usize> {
190
194M
        debug_assert_eq!(self.dst_start, self.dst_end);
191
194M
        let frame_info = self.current_frame_info.as_ref().unwrap();
192
193
        // Adjust dst buffer offsets to decompress the next block
194
194M
        let max_block_size = frame_info.block_size.get_size();
195
194M
        if frame_info.block_mode == BlockMode::Linked {
196
            // In linked mode we consume the output (bumping dst_start) but leave the
197
            // beginning of dst to be used as a prefix in subsequent blocks.
198
            // That is at least until we have at least `max_block_size + WINDOW_SIZE`
199
            // bytes in dst, then we setup an ext_dict with the last WINDOW_SIZE bytes
200
            // and the output goes to the beginning of dst again.
201
97.4M
            debug_assert_eq!(self.dst.capacity(), max_block_size * 2 + WINDOW_SIZE);
202
97.4M
            if self.dst_start + max_block_size > self.dst.capacity() {
203
                // Output might not fit in the buffer.
204
                // The ext_dict will become the last WINDOW_SIZE bytes
205
14.0k
                debug_assert!(self.dst_start >= max_block_size + WINDOW_SIZE);
206
14.0k
                self.ext_dict_offset = self.dst_start - WINDOW_SIZE;
207
14.0k
                self.ext_dict_len = WINDOW_SIZE;
208
                // Output goes in the beginning of the buffer again.
209
14.0k
                self.dst_start = 0;
210
14.0k
                self.dst_end = 0;
211
97.3M
            } else if self.dst_start + self.ext_dict_len > WINDOW_SIZE {
212
                // There's more than WINDOW_SIZE bytes of lookback adding the prefix and ext_dict.
213
                // Since we have a limited buffer we must shrink ext_dict in favor of the prefix,
214
                // so that we can fit up to max_block_size bytes between dst_start and ext_dict
215
                // start.
216
83.9M
                let delta = self
217
83.9M
                    .ext_dict_len
218
83.9M
                    .min(self.dst_start + self.ext_dict_len - WINDOW_SIZE);
219
83.9M
                self.ext_dict_offset += delta;
220
83.9M
                self.ext_dict_len -= delta;
221
83.9M
                debug_assert!(self.dst_start + self.ext_dict_len >= WINDOW_SIZE)
222
13.4M
            }
223
        } else {
224
97.3M
            debug_assert_eq!(self.ext_dict_len, 0);
225
97.3M
            debug_assert_eq!(self.dst.capacity(), max_block_size);
226
97.3M
            self.dst_start = 0;
227
97.3M
            self.dst_end = 0;
228
        }
229
230
        // Read and decompress block
231
194M
        let block_info = {
232
194M
            let mut buffer = [0u8; 4];
233
194M
            if let Err(err) = self.r.read_exact(&mut buffer) {
234
1.34k
                if err.kind() == ErrorKind::UnexpectedEof {
235
1.34k
                    return Ok(0);
236
                } else {
237
0
                    return Err(err);
238
                }
239
194M
            }
240
194M
            BlockInfo::read(&buffer)?
241
        };
242
194M
        match block_info {
243
92.6M
            BlockInfo::Uncompressed(len) => {
244
92.6M
                let len = len as usize;
245
92.6M
                if len > max_block_size {
246
708
                    return Err(Error::BlockTooBig.into());
247
92.6M
                }
248
                // TODO: Attempt to avoid initialization of read buffer when
249
                // https://github.com/rust-lang/rust/issues/78485 stabilizes
250
92.6M
                self.r.read_exact(vec_resize_and_get_mut(
251
92.6M
                    &mut self.dst,
252
92.6M
                    self.dst_start,
253
92.6M
                    self.dst_start + len,
254
92.6M
                ))?;
255
92.6M
                if frame_info.block_checksums {
256
46.3M
                    let expected_checksum = Self::read_checksum(&mut self.r)?;
257
46.3M
                    Self::check_block_checksum(
258
46.3M
                        &self.dst[self.dst_start..self.dst_start + len],
259
46.3M
                        expected_checksum,
260
244
                    )?;
261
46.3M
                }
262
263
92.6M
                self.dst_end += len;
264
92.6M
                self.content_len += len as u64;
265
            }
266
102M
            BlockInfo::Compressed(len) => {
267
102M
                let len = len as usize;
268
102M
                if len > max_block_size {
269
4.11k
                    return Err(Error::BlockTooBig.into());
270
102M
                }
271
                // TODO: Attempt to avoid initialization of read buffer when
272
                // https://github.com/rust-lang/rust/issues/78485 stabilizes
273
102M
                self.r
274
102M
                    .read_exact(vec_resize_and_get_mut(&mut self.src, 0, len))?;
275
102M
                if frame_info.block_checksums {
276
51.0M
                    let expected_checksum = Self::read_checksum(&mut self.r)?;
277
51.0M
                    Self::check_block_checksum(&self.src[..len], expected_checksum)?;
278
51.0M
                }
279
280
102M
                let with_dict_mode =
281
102M
                    frame_info.block_mode == BlockMode::Linked && self.ext_dict_len != 0;
282
102M
                let decomp_size = if with_dict_mode {
283
8.55M
                    debug_assert!(self.dst_start + max_block_size <= self.ext_dict_offset);
284
8.55M
                    let (head, tail) = self.dst.split_at_mut(self.ext_dict_offset);
285
8.55M
                    let ext_dict = &tail[..self.ext_dict_len];
286
287
8.55M
                    debug_assert!(head.len() - self.dst_start >= max_block_size);
288
8.55M
                    crate::block::decompress::decompress_internal::<true, _>(
289
8.55M
                        &self.src[..len],
290
8.55M
                        &mut SliceSink::new(head, self.dst_start),
291
8.55M
                        ext_dict,
292
                    )
293
                } else {
294
                    // Independent blocks OR linked blocks with only prefix data
295
93.5M
                    debug_assert!(self.dst.capacity() - self.dst_start >= max_block_size);
296
93.5M
                    crate::block::decompress::decompress_internal::<false, _>(
297
93.5M
                        &self.src[..len],
298
93.5M
                        &mut vec_sink_for_decompression(
299
93.5M
                            &mut self.dst,
300
93.5M
                            0,
301
93.5M
                            self.dst_start,
302
93.5M
                            self.dst_start + max_block_size,
303
93.5M
                        ),
304
93.5M
                        b"",
305
                    )
306
                }
307
102M
                .map_err(Error::DecompressionError)?;
308
309
102M
                self.dst_end += decomp_size;
310
102M
                self.content_len += decomp_size as u64;
311
            }
312
313
            BlockInfo::EndMark => {
314
17.3k
                if let Some(expected) = frame_info.content_size {
315
98
                    if self.content_len != expected {
316
95
                        return Err(Error::ContentLengthError {
317
95
                            expected,
318
95
                            actual: self.content_len,
319
95
                        }
320
95
                        .into());
321
3
                    }
322
17.2k
                }
323
17.2k
                if frame_info.content_checksum {
324
8.69k
                    let expected_checksum = Self::read_checksum(&mut self.r)?;
325
8.69k
                    let calc_checksum = self.content_hasher.finish() as u32;
326
8.69k
                    if calc_checksum != expected_checksum {
327
111
                        return Err(Error::ContentChecksumError.into());
328
8.58k
                    }
329
8.59k
                }
330
17.1k
                self.current_frame_info = None;
331
17.1k
                return Ok(0);
332
            }
333
        }
334
335
        // Content checksum, if applicable
336
194M
        if frame_info.content_checksum {
337
97.3M
            self.content_hasher
338
97.3M
                .write(&self.dst[self.dst_start..self.dst_end]);
339
97.3M
        }
340
341
194M
        Ok(self.dst_end - self.dst_start)
342
194M
    }
<lz4_flex::frame::decompress::FrameDecoder<&[u8]>>::read_block
Line
Count
Source
189
194M
    fn read_block(&mut self) -> io::Result<usize> {
190
194M
        debug_assert_eq!(self.dst_start, self.dst_end);
191
194M
        let frame_info = self.current_frame_info.as_ref().unwrap();
192
193
        // Adjust dst buffer offsets to decompress the next block
194
194M
        let max_block_size = frame_info.block_size.get_size();
195
194M
        if frame_info.block_mode == BlockMode::Linked {
196
            // In linked mode we consume the output (bumping dst_start) but leave the
197
            // beginning of dst to be used as a prefix in subsequent blocks.
198
            // That is at least until we have at least `max_block_size + WINDOW_SIZE`
199
            // bytes in dst, then we setup an ext_dict with the last WINDOW_SIZE bytes
200
            // and the output goes to the beginning of dst again.
201
97.3M
            debug_assert_eq!(self.dst.capacity(), max_block_size * 2 + WINDOW_SIZE);
202
97.3M
            if self.dst_start + max_block_size > self.dst.capacity() {
203
                // Output might not fit in the buffer.
204
                // The ext_dict will become the last WINDOW_SIZE bytes
205
13.3k
                debug_assert!(self.dst_start >= max_block_size + WINDOW_SIZE);
206
13.3k
                self.ext_dict_offset = self.dst_start - WINDOW_SIZE;
207
13.3k
                self.ext_dict_len = WINDOW_SIZE;
208
                // Output goes in the beginning of the buffer again.
209
13.3k
                self.dst_start = 0;
210
13.3k
                self.dst_end = 0;
211
97.3M
            } else if self.dst_start + self.ext_dict_len > WINDOW_SIZE {
212
                // There's more than WINDOW_SIZE bytes of lookback adding the prefix and ext_dict.
213
                // Since we have a limited buffer we must shrink ext_dict in favor of the prefix,
214
                // so that we can fit up to max_block_size bytes between dst_start and ext_dict
215
                // start.
216
83.9M
                let delta = self
217
83.9M
                    .ext_dict_len
218
83.9M
                    .min(self.dst_start + self.ext_dict_len - WINDOW_SIZE);
219
83.9M
                self.ext_dict_offset += delta;
220
83.9M
                self.ext_dict_len -= delta;
221
83.9M
                debug_assert!(self.dst_start + self.ext_dict_len >= WINDOW_SIZE)
222
13.4M
            }
223
        } else {
224
97.3M
            debug_assert_eq!(self.ext_dict_len, 0);
225
97.3M
            debug_assert_eq!(self.dst.capacity(), max_block_size);
226
97.3M
            self.dst_start = 0;
227
97.3M
            self.dst_end = 0;
228
        }
229
230
        // Read and decompress block
231
194M
        let block_info = {
232
194M
            let mut buffer = [0u8; 4];
233
194M
            if let Err(err) = self.r.read_exact(&mut buffer) {
234
0
                if err.kind() == ErrorKind::UnexpectedEof {
235
0
                    return Ok(0);
236
                } else {
237
0
                    return Err(err);
238
                }
239
194M
            }
240
194M
            BlockInfo::read(&buffer)?
241
        };
242
194M
        match block_info {
243
92.6M
            BlockInfo::Uncompressed(len) => {
244
92.6M
                let len = len as usize;
245
92.6M
                if len > max_block_size {
246
0
                    return Err(Error::BlockTooBig.into());
247
92.6M
                }
248
                // TODO: Attempt to avoid initialization of read buffer when
249
                // https://github.com/rust-lang/rust/issues/78485 stabilizes
250
92.6M
                self.r.read_exact(vec_resize_and_get_mut(
251
92.6M
                    &mut self.dst,
252
92.6M
                    self.dst_start,
253
92.6M
                    self.dst_start + len,
254
92.6M
                ))?;
255
92.6M
                if frame_info.block_checksums {
256
46.3M
                    let expected_checksum = Self::read_checksum(&mut self.r)?;
257
46.3M
                    Self::check_block_checksum(
258
46.3M
                        &self.dst[self.dst_start..self.dst_start + len],
259
46.3M
                        expected_checksum,
260
0
                    )?;
261
46.3M
                }
262
263
92.6M
                self.dst_end += len;
264
92.6M
                self.content_len += len as u64;
265
            }
266
102M
            BlockInfo::Compressed(len) => {
267
102M
                let len = len as usize;
268
102M
                if len > max_block_size {
269
0
                    return Err(Error::BlockTooBig.into());
270
102M
                }
271
                // TODO: Attempt to avoid initialization of read buffer when
272
                // https://github.com/rust-lang/rust/issues/78485 stabilizes
273
102M
                self.r
274
102M
                    .read_exact(vec_resize_and_get_mut(&mut self.src, 0, len))?;
275
102M
                if frame_info.block_checksums {
276
51.0M
                    let expected_checksum = Self::read_checksum(&mut self.r)?;
277
51.0M
                    Self::check_block_checksum(&self.src[..len], expected_checksum)?;
278
51.0M
                }
279
280
102M
                let with_dict_mode =
281
102M
                    frame_info.block_mode == BlockMode::Linked && self.ext_dict_len != 0;
282
102M
                let decomp_size = if with_dict_mode {
283
8.55M
                    debug_assert!(self.dst_start + max_block_size <= self.ext_dict_offset);
284
8.55M
                    let (head, tail) = self.dst.split_at_mut(self.ext_dict_offset);
285
8.55M
                    let ext_dict = &tail[..self.ext_dict_len];
286
287
8.55M
                    debug_assert!(head.len() - self.dst_start >= max_block_size);
288
8.55M
                    crate::block::decompress::decompress_internal::<true, _>(
289
8.55M
                        &self.src[..len],
290
8.55M
                        &mut SliceSink::new(head, self.dst_start),
291
8.55M
                        ext_dict,
292
                    )
293
                } else {
294
                    // Independent blocks OR linked blocks with only prefix data
295
93.5M
                    debug_assert!(self.dst.capacity() - self.dst_start >= max_block_size);
296
93.5M
                    crate::block::decompress::decompress_internal::<false, _>(
297
93.5M
                        &self.src[..len],
298
93.5M
                        &mut vec_sink_for_decompression(
299
93.5M
                            &mut self.dst,
300
93.5M
                            0,
301
93.5M
                            self.dst_start,
302
93.5M
                            self.dst_start + max_block_size,
303
93.5M
                        ),
304
93.5M
                        b"",
305
                    )
306
                }
307
102M
                .map_err(Error::DecompressionError)?;
308
309
102M
                self.dst_end += decomp_size;
310
102M
                self.content_len += decomp_size as u64;
311
            }
312
313
            BlockInfo::EndMark => {
314
17.1k
                if let Some(expected) = frame_info.content_size {
315
0
                    if self.content_len != expected {
316
0
                        return Err(Error::ContentLengthError {
317
0
                            expected,
318
0
                            actual: self.content_len,
319
0
                        }
320
0
                        .into());
321
0
                    }
322
17.1k
                }
323
17.1k
                if frame_info.content_checksum {
324
8.57k
                    let expected_checksum = Self::read_checksum(&mut self.r)?;
325
8.57k
                    let calc_checksum = self.content_hasher.finish() as u32;
326
8.57k
                    if calc_checksum != expected_checksum {
327
0
                        return Err(Error::ContentChecksumError.into());
328
8.57k
                    }
329
8.57k
                }
330
17.1k
                self.current_frame_info = None;
331
17.1k
                return Ok(0);
332
            }
333
        }
334
335
        // Content checksum, if applicable
336
194M
        if frame_info.content_checksum {
337
97.3M
            self.content_hasher
338
97.3M
                .write(&self.dst[self.dst_start..self.dst_end]);
339
97.3M
        }
340
341
194M
        Ok(self.dst_end - self.dst_start)
342
194M
    }
Unexecuted instantiation: <lz4_flex::frame::decompress::FrameDecoder<_>>::read_block
<lz4_flex::frame::decompress::FrameDecoder<&[u8]>>::read_block
Line
Count
Source
189
39.6k
    fn read_block(&mut self) -> io::Result<usize> {
190
39.6k
        debug_assert_eq!(self.dst_start, self.dst_end);
191
39.6k
        let frame_info = self.current_frame_info.as_ref().unwrap();
192
193
        // Adjust dst buffer offsets to decompress the next block
194
39.6k
        let max_block_size = frame_info.block_size.get_size();
195
39.6k
        if frame_info.block_mode == BlockMode::Linked {
196
            // In linked mode we consume the output (bumping dst_start) but leave the
197
            // beginning of dst to be used as a prefix in subsequent blocks.
198
            // That is at least until we have at least `max_block_size + WINDOW_SIZE`
199
            // bytes in dst, then we setup an ext_dict with the last WINDOW_SIZE bytes
200
            // and the output goes to the beginning of dst again.
201
23.7k
            debug_assert_eq!(self.dst.capacity(), max_block_size * 2 + WINDOW_SIZE);
202
23.7k
            if self.dst_start + max_block_size > self.dst.capacity() {
203
                // Output might not fit in the buffer.
204
                // The ext_dict will become the last WINDOW_SIZE bytes
205
694
                debug_assert!(self.dst_start >= max_block_size + WINDOW_SIZE);
206
694
                self.ext_dict_offset = self.dst_start - WINDOW_SIZE;
207
694
                self.ext_dict_len = WINDOW_SIZE;
208
                // Output goes in the beginning of the buffer again.
209
694
                self.dst_start = 0;
210
694
                self.dst_end = 0;
211
23.1k
            } else if self.dst_start + self.ext_dict_len > WINDOW_SIZE {
212
                // There's more than WINDOW_SIZE bytes of lookback adding the prefix and ext_dict.
213
                // Since we have a limited buffer we must shrink ext_dict in favor of the prefix,
214
                // so that we can fit up to max_block_size bytes between dst_start and ext_dict
215
                // start.
216
8.55k
                let delta = self
217
8.55k
                    .ext_dict_len
218
8.55k
                    .min(self.dst_start + self.ext_dict_len - WINDOW_SIZE);
219
8.55k
                self.ext_dict_offset += delta;
220
8.55k
                self.ext_dict_len -= delta;
221
8.55k
                debug_assert!(self.dst_start + self.ext_dict_len >= WINDOW_SIZE)
222
14.5k
            }
223
        } else {
224
15.8k
            debug_assert_eq!(self.ext_dict_len, 0);
225
15.8k
            debug_assert_eq!(self.dst.capacity(), max_block_size);
226
15.8k
            self.dst_start = 0;
227
15.8k
            self.dst_end = 0;
228
        }
229
230
        // Read and decompress block
231
38.3k
        let block_info = {
232
39.6k
            let mut buffer = [0u8; 4];
233
39.6k
            if let Err(err) = self.r.read_exact(&mut buffer) {
234
1.34k
                if err.kind() == ErrorKind::UnexpectedEof {
235
1.34k
                    return Ok(0);
236
                } else {
237
0
                    return Err(err);
238
                }
239
38.3k
            }
240
38.3k
            BlockInfo::read(&buffer)?
241
        };
242
38.3k
        match block_info {
243
18.7k
            BlockInfo::Uncompressed(len) => {
244
18.7k
                let len = len as usize;
245
18.7k
                if len > max_block_size {
246
708
                    return Err(Error::BlockTooBig.into());
247
18.0k
                }
248
                // TODO: Attempt to avoid initialization of read buffer when
249
                // https://github.com/rust-lang/rust/issues/78485 stabilizes
250
18.0k
                self.r.read_exact(vec_resize_and_get_mut(
251
18.0k
                    &mut self.dst,
252
18.0k
                    self.dst_start,
253
18.0k
                    self.dst_start + len,
254
18.0k
                ))?;
255
17.7k
                if frame_info.block_checksums {
256
1.66k
                    let expected_checksum = Self::read_checksum(&mut self.r)?;
257
1.66k
                    Self::check_block_checksum(
258
1.66k
                        &self.dst[self.dst_start..self.dst_start + len],
259
1.66k
                        expected_checksum,
260
244
                    )?;
261
16.1k
                }
262
263
17.5k
                self.dst_end += len;
264
17.5k
                self.content_len += len as u64;
265
            }
266
19.3k
            BlockInfo::Compressed(len) => {
267
19.3k
                let len = len as usize;
268
19.3k
                if len > max_block_size {
269
4.11k
                    return Err(Error::BlockTooBig.into());
270
15.2k
                }
271
                // TODO: Attempt to avoid initialization of read buffer when
272
                // https://github.com/rust-lang/rust/issues/78485 stabilizes
273
15.2k
                self.r
274
15.2k
                    .read_exact(vec_resize_and_get_mut(&mut self.src, 0, len))?;
275
14.9k
                if frame_info.block_checksums {
276
432
                    let expected_checksum = Self::read_checksum(&mut self.r)?;
277
425
                    Self::check_block_checksum(&self.src[..len], expected_checksum)?;
278
14.5k
                }
279
280
14.8k
                let with_dict_mode =
281
14.8k
                    frame_info.block_mode == BlockMode::Linked && self.ext_dict_len != 0;
282
14.8k
                let decomp_size = if with_dict_mode {
283
1.04k
                    debug_assert!(self.dst_start + max_block_size <= self.ext_dict_offset);
284
1.04k
                    let (head, tail) = self.dst.split_at_mut(self.ext_dict_offset);
285
1.04k
                    let ext_dict = &tail[..self.ext_dict_len];
286
287
1.04k
                    debug_assert!(head.len() - self.dst_start >= max_block_size);
288
1.04k
                    crate::block::decompress::decompress_internal::<true, _>(
289
1.04k
                        &self.src[..len],
290
1.04k
                        &mut SliceSink::new(head, self.dst_start),
291
1.04k
                        ext_dict,
292
                    )
293
                } else {
294
                    // Independent blocks OR linked blocks with only prefix data
295
13.8k
                    debug_assert!(self.dst.capacity() - self.dst_start >= max_block_size);
296
13.8k
                    crate::block::decompress::decompress_internal::<false, _>(
297
13.8k
                        &self.src[..len],
298
13.8k
                        &mut vec_sink_for_decompression(
299
13.8k
                            &mut self.dst,
300
13.8k
                            0,
301
13.8k
                            self.dst_start,
302
13.8k
                            self.dst_start + max_block_size,
303
13.8k
                        ),
304
13.8k
                        b"",
305
                    )
306
                }
307
14.8k
                .map_err(Error::DecompressionError)?;
308
309
8.03k
                self.dst_end += decomp_size;
310
8.03k
                self.content_len += decomp_size as u64;
311
            }
312
313
            BlockInfo::EndMark => {
314
240
                if let Some(expected) = frame_info.content_size {
315
98
                    if self.content_len != expected {
316
95
                        return Err(Error::ContentLengthError {
317
95
                            expected,
318
95
                            actual: self.content_len,
319
95
                        }
320
95
                        .into());
321
3
                    }
322
142
                }
323
145
                if frame_info.content_checksum {
324
122
                    let expected_checksum = Self::read_checksum(&mut self.r)?;
325
115
                    let calc_checksum = self.content_hasher.finish() as u32;
326
115
                    if calc_checksum != expected_checksum {
327
111
                        return Err(Error::ContentChecksumError.into());
328
4
                    }
329
23
                }
330
27
                self.current_frame_info = None;
331
27
                return Ok(0);
332
            }
333
        }
334
335
        // Content checksum, if applicable
336
25.5k
        if frame_info.content_checksum {
337
4.80k
            self.content_hasher
338
4.80k
                .write(&self.dst[self.dst_start..self.dst_end]);
339
20.7k
        }
340
341
25.5k
        Ok(self.dst_end - self.dst_start)
342
39.6k
    }
343
344
194M
    fn read_more(&mut self) -> io::Result<usize> {
345
194M
        if self.current_frame_info.is_none() && self.read_frame_info()? == 0 {
346
348
            return Ok(0);
347
194M
        }
348
194M
        self.read_block()
349
194M
    }
<lz4_flex::frame::decompress::FrameDecoder<&[u8]>>::read_more
Line
Count
Source
344
194M
    fn read_more(&mut self) -> io::Result<usize> {
345
194M
        if self.current_frame_info.is_none() && self.read_frame_info()? == 0 {
346
0
            return Ok(0);
347
194M
        }
348
194M
        self.read_block()
349
194M
    }
Unexecuted instantiation: <lz4_flex::frame::decompress::FrameDecoder<_>>::read_more
<lz4_flex::frame::decompress::FrameDecoder<&[u8]>>::read_more
Line
Count
Source
344
47.5k
    fn read_more(&mut self) -> io::Result<usize> {
345
47.5k
        if self.current_frame_info.is_none() && self.read_frame_info()? == 0 {
346
348
            return Ok(0);
347
39.6k
        }
348
39.6k
        self.read_block()
349
47.5k
    }
350
}
351
352
impl<R: io::Read> io::Read for FrameDecoder<R> {
353
194M
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
354
        loop {
355
            // Fill read buffer if there's uncompressed data left
356
389M
            if self.dst_start < self.dst_end {
357
194M
                let read_len = std::cmp::min(self.dst_end - self.dst_start, buf.len());
358
194M
                let dst_read_end = self.dst_start + read_len;
359
194M
                buf[..read_len].copy_from_slice(&self.dst[self.dst_start..dst_read_end]);
360
194M
                self.dst_start = dst_read_end;
361
194M
                return Ok(read_len);
362
194M
            }
363
194M
            if self.read_more()? == 0 {
364
17.1k
                return Ok(0);
365
194M
            }
366
        }
367
194M
    }
<lz4_flex::frame::decompress::FrameDecoder<&[u8]> as std::io::Read>::read
Line
Count
Source
353
194M
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
354
        loop {
355
            // Fill read buffer if there's uncompressed data left
356
389M
            if self.dst_start < self.dst_end {
357
194M
                let read_len = std::cmp::min(self.dst_end - self.dst_start, buf.len());
358
194M
                let dst_read_end = self.dst_start + read_len;
359
194M
                buf[..read_len].copy_from_slice(&self.dst[self.dst_start..dst_read_end]);
360
194M
                self.dst_start = dst_read_end;
361
194M
                return Ok(read_len);
362
194M
            }
363
194M
            if self.read_more()? == 0 {
364
17.1k
                return Ok(0);
365
194M
            }
366
        }
367
194M
    }
Unexecuted instantiation: <lz4_flex::frame::decompress::FrameDecoder<_> as std::io::Read>::read
368
369
0
    fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
370
0
        let mut written = 0;
371
        loop {
372
0
            match self.fill_buf() {
373
0
                Ok([]) => return Ok(written),
374
0
                Ok(b) => {
375
0
                    let s = std::str::from_utf8(b).map_err(|_| {
376
0
                        io::Error::new(
377
0
                            io::ErrorKind::InvalidData,
378
                            "stream did not contain valid UTF-8",
379
                        )
380
0
                    })?;
381
0
                    buf.push_str(s);
382
0
                    let len = s.len();
383
0
                    self.consume(len);
384
0
                    written += len;
385
                }
386
0
                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
387
0
                Err(e) => return Err(e),
388
            }
389
        }
390
0
    }
391
392
22.1k
    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
393
22.1k
        let mut written = 0;
394
        loop {
395
47.5k
            match self.fill_buf() {
396
27.2k
                Ok([]) => return Ok(written),
397
25.3k
                Ok(b) => {
398
25.3k
                    buf.extend_from_slice(b);
399
25.3k
                    let len = b.len();
400
25.3k
                    self.consume(len);
401
25.3k
                    written += len;
402
25.3k
                }
403
20.2k
                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
404
20.2k
                Err(e) => return Err(e),
405
            }
406
        }
407
22.1k
    }
Unexecuted instantiation: <lz4_flex::frame::decompress::FrameDecoder<_> as std::io::Read>::read_to_end
<lz4_flex::frame::decompress::FrameDecoder<&[u8]> as std::io::Read>::read_to_end
Line
Count
Source
392
22.1k
    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
393
22.1k
        let mut written = 0;
394
        loop {
395
47.5k
            match self.fill_buf() {
396
27.2k
                Ok([]) => return Ok(written),
397
25.3k
                Ok(b) => {
398
25.3k
                    buf.extend_from_slice(b);
399
25.3k
                    let len = b.len();
400
25.3k
                    self.consume(len);
401
25.3k
                    written += len;
402
25.3k
                }
403
20.2k
                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
404
20.2k
                Err(e) => return Err(e),
405
            }
406
        }
407
22.1k
    }
408
}
409
410
impl<R: io::Read> io::BufRead for FrameDecoder<R> {
411
47.5k
    fn fill_buf(&mut self) -> io::Result<&[u8]> {
412
47.5k
        if self.dst_start == self.dst_end {
413
47.5k
            self.read_more()?;
414
0
        }
415
27.2k
        Ok(&self.dst[self.dst_start..self.dst_end])
416
47.5k
    }
Unexecuted instantiation: <lz4_flex::frame::decompress::FrameDecoder<_> as std::io::BufRead>::fill_buf
<lz4_flex::frame::decompress::FrameDecoder<&[u8]> as std::io::BufRead>::fill_buf
Line
Count
Source
411
47.5k
    fn fill_buf(&mut self) -> io::Result<&[u8]> {
412
47.5k
        if self.dst_start == self.dst_end {
413
47.5k
            self.read_more()?;
414
0
        }
415
27.2k
        Ok(&self.dst[self.dst_start..self.dst_end])
416
47.5k
    }
417
418
25.3k
    fn consume(&mut self, amt: usize) {
419
25.3k
        assert!(amt <= self.dst_end - self.dst_start);
420
25.3k
        self.dst_start += amt;
421
25.3k
    }
Unexecuted instantiation: <lz4_flex::frame::decompress::FrameDecoder<_> as std::io::BufRead>::consume
<lz4_flex::frame::decompress::FrameDecoder<&[u8]> as std::io::BufRead>::consume
Line
Count
Source
418
25.3k
    fn consume(&mut self, amt: usize) {
419
25.3k
        assert!(amt <= self.dst_end - self.dst_start);
420
25.3k
        self.dst_start += amt;
421
25.3k
    }
422
}
423
424
impl<R: fmt::Debug + io::Read> fmt::Debug for FrameDecoder<R> {
425
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
426
0
        f.debug_struct("FrameDecoder")
427
0
            .field("r", &self.r)
428
0
            .field("content_hasher", &self.content_hasher)
429
0
            .field("content_len", &self.content_len)
430
0
            .field("src", &"[...]")
431
0
            .field("dst", &"[...]")
432
0
            .field("dst_start", &self.dst_start)
433
0
            .field("dst_end", &self.dst_end)
434
0
            .field("ext_dict_offset", &self.ext_dict_offset)
435
0
            .field("ext_dict_len", &self.ext_dict_len)
436
0
            .field("current_frame_info", &self.current_frame_info)
437
0
            .finish()
438
0
    }
439
}
440
441
/// Similar to `v.get_mut(start..end) but will adjust the len if needed.
442
#[inline]
443
194M
fn vec_resize_and_get_mut(v: &mut Vec<u8>, start: usize, end: usize) -> &mut [u8] {
444
194M
    if end > v.len() {
445
29.9M
        v.resize(end, 0)
446
164M
    }
447
194M
    &mut v[start..end]
448
194M
}
lz4_flex::frame::decompress::vec_resize_and_get_mut
Line
Count
Source
443
194M
fn vec_resize_and_get_mut(v: &mut Vec<u8>, start: usize, end: usize) -> &mut [u8] {
444
194M
    if end > v.len() {
445
29.9M
        v.resize(end, 0)
446
164M
    }
447
194M
    &mut v[start..end]
448
194M
}
Unexecuted instantiation: lz4_flex::frame::decompress::vec_resize_and_get_mut
lz4_flex::frame::decompress::vec_resize_and_get_mut
Line
Count
Source
443
33.2k
fn vec_resize_and_get_mut(v: &mut Vec<u8>, start: usize, end: usize) -> &mut [u8] {
444
33.2k
    if end > v.len() {
445
15.8k
        v.resize(end, 0)
446
17.3k
    }
447
33.2k
    &mut v[start..end]
448
33.2k
}