Coverage Report

Created: 2026-02-26 07:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/gif-0.14.1/src/encoder.rs
Line
Count
Source
1
//! # Minimal gif encoder
2
3
use alloc::borrow::Cow;
4
use alloc::fmt;
5
use alloc::vec::Vec;
6
use std::error;
7
use std::io;
8
use std::io::Write;
9
10
use weezl::{encode::Encoder as LzwEncoder, BitOrder};
11
12
use crate::common::{AnyExtension, Block, DisposalMethod, Extension, Frame};
13
use crate::traits::WriteBytesExt;
14
15
/// The image has incorrect properties, making it impossible to encode as a gif.
16
#[derive(Debug)]
17
#[non_exhaustive]
18
pub enum EncodingFormatError {
19
    /// The image has too many colors.
20
    TooManyColors,
21
    /// The image has no color palette which is required.
22
    MissingColorPalette,
23
    /// LZW data is not valid for GIF. This may happen when wrong buffer is given to `write_lzw_pre_encoded_frame`
24
    InvalidMinCodeSize,
25
}
26
27
impl error::Error for EncodingFormatError {}
28
impl fmt::Display for EncodingFormatError {
29
    #[cold]
30
0
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
31
0
        match self {
32
0
            Self::TooManyColors => write!(fmt, "the image has too many colors"),
33
0
            Self::MissingColorPalette => write!(
34
0
                fmt,
35
0
                "the GIF format requires a color palette but none was given"
36
            ),
37
0
            Self::InvalidMinCodeSize => write!(fmt, "LZW data is invalid"),
38
        }
39
0
    }
40
}
41
42
/// Encoding error.
43
#[derive(Debug)]
44
#[non_exhaustive]
45
pub enum EncodingError {
46
    /// Frame buffer is too small for the declared dimensions.
47
    FrameBufferTooSmallForDimensions,
48
    /// Failed to internally allocate a buffer of sufficient size.
49
    OutOfMemory,
50
    /// Expected a writer but none found.
51
    WriterNotFound,
52
    /// Returned if the to image is not encodable as a gif.
53
    Format(EncodingFormatError),
54
    /// Wraps `std::io::Error`.
55
    Io(io::Error),
56
}
57
58
impl fmt::Display for EncodingError {
59
    #[cold]
60
0
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
61
0
        match self {
62
            Self::FrameBufferTooSmallForDimensions => {
63
0
                fmt.write_str("Frame Buffer Too Small for Dimensions")
64
            }
65
0
            Self::OutOfMemory => fmt.write_str("Out of Memory"),
66
0
            Self::WriterNotFound => fmt.write_str("Writer Not Found"),
67
0
            Self::Io(err) => err.fmt(fmt),
68
0
            Self::Format(err) => err.fmt(fmt),
69
        }
70
0
    }
71
}
72
73
impl error::Error for EncodingError {
74
    #[cold]
75
0
    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
76
0
        match self {
77
0
            Self::FrameBufferTooSmallForDimensions => None,
78
0
            Self::OutOfMemory => None,
79
0
            Self::WriterNotFound => None,
80
0
            Self::Io(err) => Some(err),
81
0
            Self::Format(err) => Some(err),
82
        }
83
0
    }
84
}
85
86
impl From<io::Error> for EncodingError {
87
    #[cold]
88
0
    fn from(err: io::Error) -> Self {
89
0
        Self::Io(err)
90
0
    }
91
}
92
93
impl From<EncodingFormatError> for EncodingError {
94
    #[cold]
95
0
    fn from(err: EncodingFormatError) -> Self {
96
0
        Self::Format(err)
97
0
    }
98
}
99
100
/// Number of repetitions
101
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
102
pub enum Repeat {
103
    /// Finite number of repetitions
104
    Finite(u16),
105
    /// Infinite number of repetitions
106
    Infinite,
107
}
108
109
impl Default for Repeat {
110
4.32k
    fn default() -> Self {
111
4.32k
        Self::Finite(0)
112
4.32k
    }
113
}
114
115
/// Extension data.
116
#[non_exhaustive]
117
pub enum ExtensionData {
118
    /// Control extension. Use `ExtensionData::new_control_ext` to construct.
119
    Control {
120
        /// Flags.
121
        flags: u8,
122
        /// Frame delay.
123
        delay: u16,
124
        /// Transparent index.
125
        trns: u8,
126
    },
127
    /// Sets the number of repetitions
128
    Repetitions(Repeat),
129
}
130
131
impl ExtensionData {
132
    /// Constructor for control extension data.
133
    ///
134
    /// `delay` is given in units of 10 ms.
135
    #[must_use]
136
0
    pub fn new_control_ext(
137
0
        delay: u16,
138
0
        dispose: DisposalMethod,
139
0
        needs_user_input: bool,
140
0
        trns: Option<u8>,
141
0
    ) -> Self {
142
0
        let mut flags = 0;
143
0
        let trns = match trns {
144
0
            Some(trns) => {
145
0
                flags |= 1;
146
0
                trns
147
            }
148
0
            None => 0,
149
        };
150
0
        flags |= u8::from(needs_user_input) << 1;
151
0
        flags |= (dispose as u8) << 2;
152
0
        Self::Control { flags, delay, trns }
153
0
    }
154
}
155
156
impl<W: Write> Encoder<W> {
157
    /// Creates a new encoder.
158
    ///
159
    /// `global_palette` gives the global color palette in the format `[r, g, b, ...]`,
160
    /// if no global palette shall be used an empty slice may be supplied.
161
0
    pub fn new(
162
0
        w: W,
163
0
        width: u16,
164
0
        height: u16,
165
0
        global_palette: &[u8],
166
0
    ) -> Result<Self, EncodingError> {
167
0
        Self {
168
0
            w: Some(w),
169
0
            global_palette: false,
170
0
            width,
171
0
            height,
172
0
            buffer: Vec::new(),
173
0
        }
174
0
        .write_global_palette(global_palette)
175
0
    }
Unexecuted instantiation: <gif::encoder::Encoder<_>>::new
Unexecuted instantiation: <gif::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::new
176
177
    /// Write an extension block that signals a repeat behaviour.
178
0
    pub fn set_repeat(&mut self, repeat: Repeat) -> Result<(), EncodingError> {
179
0
        self.write_extension(ExtensionData::Repetitions(repeat))
180
0
    }
Unexecuted instantiation: <gif::encoder::Encoder<_>>::set_repeat
Unexecuted instantiation: <gif::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::set_repeat
181
182
    /// Writes the global color palette.
183
0
    fn write_global_palette(mut self, palette: &[u8]) -> Result<Self, EncodingError> {
184
0
        let mut flags = 0;
185
0
        flags |= 0b1000_0000;
186
0
        let (palette, padding, table_size) = Self::check_color_table(palette)?;
187
0
        self.global_palette = !palette.is_empty();
188
        // Size of global color table.
189
0
        flags |= table_size;
190
        // Color resolution .. FIXME. This is mostly ignored (by ImageMagick at least) but hey, we
191
        // should use some sensible value here or even allow configuring it?
192
0
        flags |= table_size << 4; // wtf flag
193
0
        self.write_screen_desc(flags)?;
194
0
        Self::write_color_table(self.writer()?, palette, padding)?;
195
0
        Ok(self)
196
0
    }
Unexecuted instantiation: <gif::encoder::Encoder<_>>::write_global_palette
Unexecuted instantiation: <gif::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_global_palette
197
198
    /// Writes a frame to the image.
199
    ///
200
    /// Note: This function also writes a control extension if necessary.
201
0
    pub fn write_frame(&mut self, frame: &Frame<'_>) -> Result<(), EncodingError> {
202
0
        if usize::from(frame.width)
203
0
            .checked_mul(usize::from(frame.height))
204
0
            .map_or(true, |size| frame.buffer.len() < size)
Unexecuted instantiation: <gif::encoder::Encoder<_>>::write_frame::{closure#0}
Unexecuted instantiation: <gif::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_frame::{closure#0}
205
        {
206
0
            return Err(EncodingError::FrameBufferTooSmallForDimensions);
207
0
        }
208
0
        debug_assert!(
209
0
            (frame.width > 0 && frame.height > 0) || frame.buffer.is_empty(),
210
0
            "the frame has 0 pixels, but non-empty buffer"
211
        );
212
0
        self.write_frame_header(frame)?;
213
0
        self.write_image_block(&frame.buffer)
214
0
    }
Unexecuted instantiation: <gif::encoder::Encoder<_>>::write_frame
Unexecuted instantiation: <gif::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_frame
215
216
0
    fn write_frame_header(&mut self, frame: &Frame<'_>) -> Result<(), EncodingError> {
217
0
        self.write_extension(ExtensionData::new_control_ext(
218
0
            frame.delay,
219
0
            frame.dispose,
220
0
            frame.needs_user_input,
221
0
            frame.transparent,
222
0
        ))?;
223
0
        let mut flags = 0;
224
0
        if frame.interlaced {
225
0
            flags |= 0b0100_0000;
226
0
        }
227
0
        let palette = match frame.palette {
228
0
            Some(ref palette) => {
229
0
                flags |= 0b1000_0000;
230
0
                let (palette, padding, table_size) = Self::check_color_table(palette)?;
231
0
                flags |= table_size;
232
0
                Some((palette, padding))
233
            }
234
0
            None if self.global_palette => None,
235
            _ => {
236
0
                return Err(EncodingError::from(
237
0
                    EncodingFormatError::MissingColorPalette,
238
0
                ))
239
            }
240
        };
241
0
        let mut tmp = tmp_buf::<10>();
242
0
        tmp.write_le(Block::Image as u8)?;
243
0
        tmp.write_le(frame.left)?;
244
0
        tmp.write_le(frame.top)?;
245
0
        tmp.write_le(frame.width)?;
246
0
        tmp.write_le(frame.height)?;
247
0
        tmp.write_le(flags)?;
248
0
        let writer = self.writer()?;
249
0
        tmp.finish(&mut *writer)?;
250
0
        if let Some((palette, padding)) = palette {
251
0
            Self::write_color_table(writer, palette, padding)?;
252
0
        }
253
0
        Ok(())
254
0
    }
Unexecuted instantiation: <gif::encoder::Encoder<_>>::write_frame_header
Unexecuted instantiation: <gif::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_frame_header
255
256
0
    fn write_image_block(&mut self, data: &[u8]) -> Result<(), EncodingError> {
257
0
        self.buffer.clear();
258
0
        self.buffer
259
0
            .try_reserve(data.len() / 4)
260
0
            .map_err(|_| EncodingError::OutOfMemory)?;
261
0
        lzw_encode(data, &mut self.buffer);
262
263
0
        let writer = self.w.as_mut().ok_or(EncodingError::WriterNotFound)?;
264
0
        Self::write_encoded_image_block(writer, &self.buffer)
265
0
    }
Unexecuted instantiation: <gif::encoder::Encoder<_>>::write_image_block
Unexecuted instantiation: <gif::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_image_block
266
267
0
    fn write_encoded_image_block(
268
0
        writer: &mut W,
269
0
        data_with_min_code_size: &[u8],
270
0
    ) -> Result<(), EncodingError> {
271
0
        let (&min_code_size, data) = data_with_min_code_size.split_first().unwrap_or((&2, &[]));
272
0
        writer.write_le(min_code_size)?;
273
274
        // Write blocks. `chunks_exact` seems to be slightly faster
275
        // than `chunks` according to both Rust docs and benchmark results.
276
0
        let mut iter = data.chunks_exact(0xFF);
277
0
        for full_block in iter.by_ref() {
278
0
            writer.write_le(0xFFu8)?;
279
0
            writer.write_all(full_block)?;
280
        }
281
0
        let last_block = iter.remainder();
282
0
        if !last_block.is_empty() {
283
0
            writer.write_le(last_block.len() as u8)?;
284
0
            writer.write_all(last_block)?;
285
0
        }
286
0
        writer.write_le(0u8).map_err(Into::into)
287
0
    }
Unexecuted instantiation: <gif::encoder::Encoder<_>>::write_encoded_image_block
Unexecuted instantiation: <gif::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_encoded_image_block
288
289
0
    fn write_color_table(
290
0
        writer: &mut W,
291
0
        table: &[u8],
292
0
        padding: usize,
293
0
    ) -> Result<(), EncodingError> {
294
0
        writer.write_all(table)?;
295
        // Waste some space as of gif spec
296
0
        for _ in 0..padding {
297
0
            writer.write_all(&[0, 0, 0])?;
298
        }
299
0
        Ok(())
300
0
    }
Unexecuted instantiation: <gif::encoder::Encoder<_>>::write_color_table
Unexecuted instantiation: <gif::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_color_table
301
302
    /// returns rounded palette size, number of missing colors, and table size flag
303
0
    fn check_color_table(table: &[u8]) -> Result<(&[u8], usize, u8), EncodingError> {
304
0
        let num_colors = table.len() / 3;
305
0
        if num_colors > 256 {
306
0
            return Err(EncodingError::from(EncodingFormatError::TooManyColors));
307
0
        }
308
0
        let table_size = flag_size(num_colors);
309
0
        let padding = (2 << table_size) - num_colors;
310
0
        Ok((&table[..num_colors * 3], padding, table_size))
311
0
    }
Unexecuted instantiation: <gif::encoder::Encoder<_>>::check_color_table
Unexecuted instantiation: <gif::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::check_color_table
312
313
    /// Writes an extension to the image.
314
    ///
315
    /// It is normally not necessary to call this method manually.
316
0
    pub fn write_extension(&mut self, extension: ExtensionData) -> Result<(), EncodingError> {
317
        use self::ExtensionData::*;
318
        // 0 finite repetitions can only be achieved
319
        // if the corresponting extension is not written
320
0
        if let Repetitions(Repeat::Finite(0)) = extension {
321
0
            return Ok(());
322
0
        }
323
0
        let writer = self.writer()?;
324
0
        writer.write_le(Block::Extension as u8)?;
325
0
        match extension {
326
0
            Control { flags, delay, trns } => {
327
0
                let mut tmp = tmp_buf::<6>();
328
0
                tmp.write_le(Extension::Control as u8)?;
329
0
                tmp.write_le(4u8)?;
330
0
                tmp.write_le(flags)?;
331
0
                tmp.write_le(delay)?;
332
0
                tmp.write_le(trns)?;
333
0
                tmp.finish(&mut *writer)?;
334
            }
335
0
            Repetitions(repeat) => {
336
0
                let mut tmp = tmp_buf::<17>();
337
0
                tmp.write_le(Extension::Application as u8)?;
338
0
                tmp.write_le(11u8)?;
339
0
                tmp.write_all(b"NETSCAPE2.0")?;
340
0
                tmp.write_le(3u8)?;
341
0
                tmp.write_le(1u8)?;
342
0
                tmp.write_le(match repeat {
343
0
                    Repeat::Finite(no) => no,
344
0
                    Repeat::Infinite => 0u16,
345
0
                })?;
346
0
                tmp.finish(&mut *writer)?;
347
            }
348
        }
349
0
        writer.write_le(0u8).map_err(Into::into)
350
0
    }
Unexecuted instantiation: <gif::encoder::Encoder<_>>::write_extension
Unexecuted instantiation: <gif::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_extension
351
352
    /// Writes a raw extension to the image.
353
    ///
354
    /// This method can be used to write an unsupported extension to the file. `func` is the extension
355
    /// identifier (e.g. `Extension::Application as u8`). `data` are the extension payload blocks. If any
356
    /// contained slice has a lenght > 255 it is automatically divided into sub-blocks.
357
0
    pub fn write_raw_extension(
358
0
        &mut self,
359
0
        func: AnyExtension,
360
0
        data: &[&[u8]],
361
0
    ) -> Result<(), EncodingError> {
362
0
        let writer = self.writer()?;
363
0
        writer.write_le(Block::Extension as u8)?;
364
0
        writer.write_le(func.0)?;
365
0
        for block in data {
366
0
            for chunk in block.chunks(0xFF) {
367
0
                writer.write_le(chunk.len() as u8)?;
368
0
                writer.write_all(chunk)?;
369
            }
370
        }
371
0
        Ok(writer.write_le(0u8)?)
372
0
    }
373
374
    /// Writes a frame to the image, but expects `Frame.buffer` to contain LZW-encoded data
375
    /// from [`Frame::make_lzw_pre_encoded`].
376
    ///
377
    /// Note: This function also writes a control extension if necessary.
378
0
    pub fn write_lzw_pre_encoded_frame(&mut self, frame: &Frame<'_>) -> Result<(), EncodingError> {
379
        // empty data is allowed
380
0
        if let Some(&min_code_size) = frame.buffer.first() {
381
0
            if min_code_size > 11 || min_code_size < 2 {
382
0
                return Err(EncodingError::Format(
383
0
                    EncodingFormatError::InvalidMinCodeSize,
384
0
                ));
385
0
            }
386
0
        }
387
388
0
        self.write_frame_header(frame)?;
389
0
        let writer = self.writer()?;
390
0
        Self::write_encoded_image_block(writer, &frame.buffer)
391
0
    }
392
393
    /// Writes the logical screen desriptor
394
0
    fn write_screen_desc(&mut self, flags: u8) -> Result<(), EncodingError> {
395
0
        let mut tmp = tmp_buf::<13>();
396
0
        tmp.write_all(b"GIF89a")?;
397
0
        tmp.write_le(self.width)?;
398
0
        tmp.write_le(self.height)?;
399
0
        tmp.write_le(flags)?; // packed field
400
0
        tmp.write_le(0u8)?; // bg index
401
0
        tmp.write_le(0u8)?; // aspect ratio
402
0
        Ok(tmp.finish(self.writer()?)?)
403
0
    }
Unexecuted instantiation: <gif::encoder::Encoder<_>>::write_screen_desc
Unexecuted instantiation: <gif::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_screen_desc
404
405
    /// Gets a reference to the writer instance used by this encoder.
406
0
    pub fn get_ref(&self) -> &W {
407
0
        self.w.as_ref().unwrap()
408
0
    }
409
410
    /// Gets a mutable reference to the writer instance used by this encoder.
411
    ///
412
    /// It is inadvisable to directly write to the underlying writer.
413
0
    pub fn get_mut(&mut self) -> &mut W {
414
0
        self.w.as_mut().unwrap()
415
0
    }
416
417
    /// Finishes writing, and returns the `io::Write` instance used by this encoder
418
0
    pub fn into_inner(mut self) -> Result<W, EncodingError> {
419
0
        self.write_trailer()?;
420
0
        self.w.take().ok_or(EncodingError::WriterNotFound)
421
0
    }
422
423
    /// Write the final tailer.
424
0
    fn write_trailer(&mut self) -> Result<(), EncodingError> {
425
0
        Ok(self.writer()?.write_le(Block::Trailer as u8)?)
426
0
    }
Unexecuted instantiation: <gif::encoder::Encoder<_>>::write_trailer
Unexecuted instantiation: <gif::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_trailer
427
428
    #[inline]
429
0
    fn writer(&mut self) -> Result<&mut W, EncodingError> {
430
0
        self.w.as_mut().ok_or(EncodingError::WriterNotFound)
431
0
    }
Unexecuted instantiation: <gif::encoder::Encoder<_>>::writer
Unexecuted instantiation: <gif::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::writer
432
}
433
434
/// Encodes the data into the provided buffer.
435
///
436
/// The first byte is the minimum code size, followed by LZW data.
437
0
fn lzw_encode(data: &[u8], buffer: &mut Vec<u8>) {
438
0
    let mut max_byte = 0;
439
0
    for &byte in data {
440
0
        if byte > max_byte {
441
0
            max_byte = byte;
442
            // code size is the same after that
443
0
            if byte > 127 {
444
0
                break;
445
0
            }
446
0
        }
447
    }
448
0
    let palette_min_len = u32::from(max_byte) + 1;
449
    // As per gif spec: The minimal code size has to be >= 2
450
0
    let min_code_size = palette_min_len.max(4).next_power_of_two().trailing_zeros() as u8;
451
0
    buffer.push(min_code_size);
452
0
    let mut enc = LzwEncoder::new(BitOrder::Lsb, min_code_size);
453
0
    let len = enc.into_vec(buffer).encode_all(data).consumed_out;
454
0
    buffer.truncate(len + 1);
455
0
}
456
457
impl Frame<'_> {
458
    /// Replace frame's buffer with a LZW-compressed one for use with [`Encoder::write_lzw_pre_encoded_frame`].
459
    ///
460
    /// Frames can be compressed in any order, separately from the `Encoder`, which can be used to compress frames in parallel.
461
0
    pub fn make_lzw_pre_encoded(&mut self) {
462
0
        let mut buffer = Vec::new();
463
0
        buffer.try_reserve(self.buffer.len() / 2).expect("OOM");
464
0
        lzw_encode(&self.buffer, &mut buffer);
465
0
        self.buffer = Cow::Owned(buffer);
466
0
    }
467
}
468
469
/// GIF encoder.
470
pub struct Encoder<W: Write> {
471
    w: Option<W>,
472
    global_palette: bool,
473
    width: u16,
474
    height: u16,
475
    buffer: Vec<u8>,
476
}
477
478
impl<W: Write> Drop for Encoder<W> {
479
    #[cfg(feature = "raii_no_panic")]
480
0
    fn drop(&mut self) {
481
0
        if self.w.is_some() {
482
0
            let _ = self.write_trailer();
483
0
        }
484
0
    }
Unexecuted instantiation: <gif::encoder::Encoder<_> as core::ops::drop::Drop>::drop
Unexecuted instantiation: <gif::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as core::ops::drop::Drop>::drop
485
486
    #[cfg(not(feature = "raii_no_panic"))]
487
    fn drop(&mut self) {
488
        if self.w.is_some() {
489
            self.write_trailer().unwrap();
490
        }
491
    }
492
}
493
494
// Color table size converted to flag bits
495
0
fn flag_size(size: usize) -> u8 {
496
0
    (size.clamp(2, 255).next_power_of_two().trailing_zeros() - 1) as u8
497
0
}
498
499
#[test]
500
fn test_flag_size() {
501
    #[rustfmt::skip]
502
    fn expected(size: usize) -> u8 {
503
        match size {
504
            0  ..=2   => 0,
505
            3  ..=4   => 1,
506
            5  ..=8   => 2,
507
            9  ..=16  => 3,
508
            17 ..=32  => 4,
509
            33 ..=64  => 5,
510
            65 ..=128 => 6,
511
            129..=256 => 7,
512
            _ => 7
513
        }
514
    }
515
516
    for i in 0..300 {
517
        assert_eq!(flag_size(i), expected(i));
518
    }
519
    for i in 4..=255u8 {
520
        let expected = match flag_size(1 + i as usize) + 1 {
521
            1 => 2,
522
            n => n,
523
        };
524
        let actual = (u32::from(i) + 1)
525
            .max(4)
526
            .next_power_of_two()
527
            .trailing_zeros() as u8;
528
        assert_eq!(actual, expected);
529
    }
530
}
531
532
struct Buf<const N: usize> {
533
    buf: [u8; N],
534
    pos: usize,
535
}
536
537
impl<const N: usize> Write for Buf<N> {
538
    #[inline(always)]
539
0
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
540
0
        let len = buf.len();
541
0
        let pos = self.pos;
542
0
        self.buf
543
0
            .get_mut(pos..pos + len)
544
0
            .ok_or(io::ErrorKind::WriteZero)?
545
0
            .copy_from_slice(buf);
546
0
        self.pos += len;
547
0
        Ok(len)
548
0
    }
Unexecuted instantiation: <gif::encoder::Buf<_> as std::io::Write>::write
Unexecuted instantiation: <gif::encoder::Buf<17> as std::io::Write>::write
Unexecuted instantiation: <gif::encoder::Buf<6> as std::io::Write>::write
Unexecuted instantiation: <gif::encoder::Buf<10> as std::io::Write>::write
Unexecuted instantiation: <gif::encoder::Buf<13> as std::io::Write>::write
549
550
0
    fn flush(&mut self) -> io::Result<()> {
551
0
        Ok(())
552
0
    }
553
}
554
555
0
fn tmp_buf<const N: usize>() -> Buf<N> {
556
0
    Buf {
557
0
        buf: [0; N],
558
0
        pos: 0,
559
0
    }
560
0
}
Unexecuted instantiation: gif::encoder::tmp_buf::<_>
Unexecuted instantiation: gif::encoder::tmp_buf::<17>
Unexecuted instantiation: gif::encoder::tmp_buf::<6>
Unexecuted instantiation: gif::encoder::tmp_buf::<10>
Unexecuted instantiation: gif::encoder::tmp_buf::<13>
561
562
impl<const N: usize> Buf<N> {
563
    #[inline(always)]
564
0
    fn finish(&self, mut w: impl Write) -> io::Result<()> {
565
0
        debug_assert_eq!(self.pos, N);
566
0
        w.write_all(&self.buf)
567
0
    }
Unexecuted instantiation: <gif::encoder::Buf<_>>::finish::<_>
Unexecuted instantiation: <gif::encoder::Buf<17>>::finish::<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>
Unexecuted instantiation: <gif::encoder::Buf<6>>::finish::<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>
Unexecuted instantiation: <gif::encoder::Buf<10>>::finish::<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>
Unexecuted instantiation: <gif::encoder::Buf<13>>::finish::<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>
568
}
569
570
#[test]
571
fn error_cast() {
572
    use alloc::boxed::Box;
573
    let _: Box<dyn error::Error> =
574
        EncodingError::from(EncodingFormatError::MissingColorPalette).into();
575
}