1use std::borrow::Cow;
2use std::cmp;
3use std::error;
4use std::fmt;
5use std::io;
6use std::mem;
7use std::default::Default;
8use std::num::NonZeroUsize;
9
10use crate::Repeat;
11use crate::MemoryLimit;
12use crate::common::{AnyExtension, Block, DisposalMethod, Extension, Frame};
13use crate::reader::DecodeOptions;
14
15use weezl::{BitOrder, decode::Decoder as LzwDecoder, LzwError, LzwStatus};
16
17pub const PLTE_CHANNELS: usize = 3;
19
20#[derive(Debug)]
22pub struct DecodingFormatError {
23 underlying: Box<dyn error::Error + Send + Sync + 'static>,
24}
25
26impl fmt::Display for DecodingFormatError {
27 #[cold]
28 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
29 fmt::Display::fmt(&*self.underlying, fmt)
30 }
31}
32
33impl error::Error for DecodingFormatError {
34 #[cold]
35 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
36 Some(&*self.underlying as _)
37 }
38}
39
40#[derive(Debug)]
41pub enum DecodingError {
43 Format(DecodingFormatError),
45 Io(io::Error),
47}
48
49impl DecodingError {
50 #[cold]
51 pub(crate) fn format(err: &'static str) -> Self {
52 Self::Format(DecodingFormatError {
53 underlying: err.into(),
54 })
55 }
56}
57
58impl fmt::Display for DecodingError {
59 #[cold]
60 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
61 match *self {
62 Self::Format(ref d) => d.fmt(fmt),
63 Self::Io(ref err) => err.fmt(fmt),
64 }
65 }
66}
67
68impl error::Error for DecodingError {
69 #[cold]
70 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
71 match *self {
72 Self::Format(ref err) => Some(err),
73 Self::Io(ref err) => Some(err),
74 }
75 }
76}
77
78impl From<io::Error> for DecodingError {
79 #[inline]
80 fn from(err: io::Error) -> Self {
81 Self::Io(err)
82 }
83}
84
85impl From<io::ErrorKind> for DecodingError {
86 #[cold]
87 fn from(err: io::ErrorKind) -> Self {
88 Self::Io(io::Error::from(err))
89 }
90}
91
92impl From<DecodingFormatError> for DecodingError {
93 #[inline]
94 fn from(err: DecodingFormatError) -> Self {
95 Self::Format(err)
96 }
97}
98
99#[derive(Debug, Copy, Clone)]
101pub enum FrameDataType {
102 Pixels,
104 Lzw {
106 min_code_size: u8,
108 },
109}
110
111#[derive(Debug)]
113#[non_exhaustive]
114pub enum Decoded {
115 Nothing,
117 GlobalPalette(Box<[u8]>),
119 BackgroundColor(u8),
121 Repetitions(Repeat),
123 HeaderEnd,
126 BlockStart(Block),
129 SubBlockFinished(AnyExtension),
136 BlockFinished(AnyExtension),
143 FrameMetadata(FrameDataType),
149 BytesDecoded(NonZeroUsize),
151 LzwDataCopied(usize),
153 DataEnd,
155}
156
157#[derive(Debug, Copy, Clone)]
159enum State {
160 Magic,
161 ScreenDescriptor,
162 ImageBlockStart,
163 GlobalPalette(usize),
164 BlockStart(u8),
165 BlockEnd,
166 ExtensionBlockStart,
167 ExtensionDataBlock(usize),
169 ApplicationExtension,
170 LocalPalette(usize),
171 LzwInit(u8),
172 DecodeSubBlock(usize),
174 CopySubBlock(usize),
176 FrameDecoded,
177 Trailer,
178}
179use self::State::*;
180
181use super::converter::PixelConverter;
182
183pub struct FrameDecoder {
185 lzw_reader: LzwReader,
186 pixel_converter: PixelConverter,
187}
188
189impl FrameDecoder {
190 #[inline]
192 #[must_use]
193 pub fn new(options: DecodeOptions) -> Self {
194 Self {
195 lzw_reader: LzwReader::new(options.check_for_end_code),
196 pixel_converter: PixelConverter::new(options.color_output, options.memory_limit),
197 }
198 }
199
200 #[inline]
202 pub fn set_global_palette(&mut self, palette: Vec<u8>) {
203 self.pixel_converter.set_global_palette(palette);
204 }
205
206 #[inline]
210 pub fn decode_lzw_encoded_frame(&mut self, frame: &mut Frame<'_>) -> Result<(), DecodingError> {
211 let pixel_bytes = self.pixel_converter.check_buffer_size(frame)?;
212 let mut vec = vec![0; pixel_bytes];
213 self.decode_lzw_encoded_frame_into_buffer(frame, &mut vec)?;
214 frame.buffer = Cow::Owned(vec);
215 frame.interlaced = false;
216 Ok(())
217 }
218
219 pub fn decode_lzw_encoded_frame_into_buffer(&mut self, frame: &Frame<'_>, buf: &mut [u8]) -> Result<(), DecodingError> {
223 let (&min_code_size, mut data) = frame.buffer.split_first().unwrap_or((&2, &[]));
224 self.lzw_reader.reset(min_code_size)?;
225 let lzw_reader = &mut self.lzw_reader;
226 self.pixel_converter.read_into_buffer(frame, buf, &mut move |out| {
227 loop {
228 let (bytes_read, bytes_written) = lzw_reader.decode_bytes(data, out)?;
229 data = data.get(bytes_read..).unwrap_or_default();
230 if bytes_written > 0 || bytes_read == 0 || data.is_empty() {
231 return Ok(bytes_written);
232 }
233 }
234 })?;
235 Ok(())
236 }
237
238 #[inline]
240 #[must_use]
241 pub fn buffer_size(&self, frame: &Frame<'_>) -> usize {
242 self.pixel_converter.buffer_size(frame).unwrap()
243 }
244}
245
246struct LzwReader {
247 decoder: Option<LzwDecoder>,
248 min_code_size: u8,
249 check_for_end_code: bool,
250}
251
252impl LzwReader {
253 pub fn new(check_for_end_code: bool) -> Self {
254 Self {
255 decoder: None,
256 min_code_size: 0,
257 check_for_end_code,
258 }
259 }
260
261 pub fn check_code_size(min_code_size: u8) -> Result<(), DecodingError> {
262 if min_code_size > 11 || min_code_size < 1 {
265 return Err(DecodingError::format("invalid minimal code size"));
266 }
267 Ok(())
268 }
269
270 pub fn reset(&mut self, min_code_size: u8) -> Result<(), DecodingError> {
271 Self::check_code_size(min_code_size)?;
272
273 if self.min_code_size != min_code_size || self.decoder.is_none() {
275 self.min_code_size = min_code_size;
276 self.decoder = Some(LzwDecoder::new(BitOrder::Lsb, min_code_size));
277 } else {
278 self.decoder.as_mut().ok_or_else(|| DecodingError::format("bad state"))?.reset();
279 }
280
281 Ok(())
282 }
283
284 pub fn has_ended(&self) -> bool {
285 self.decoder.as_ref().map_or(true, |e| e.has_ended())
286 }
287
288 pub fn decode_bytes(&mut self, lzw_data: &[u8], decode_buffer: &mut OutputBuffer<'_>) -> io::Result<(usize, usize)> {
289 let decoder = self.decoder.as_mut().ok_or(io::ErrorKind::Unsupported)?;
290
291 let decode_buffer = match decode_buffer {
292 OutputBuffer::Slice(buf) => &mut **buf,
293 OutputBuffer::None => &mut [],
294 OutputBuffer::Vec(_) => return Err(io::Error::from(io::ErrorKind::Unsupported)),
295 };
296
297 let decoded = decoder.decode_bytes(lzw_data, decode_buffer);
298
299 match decoded.status {
300 Ok(LzwStatus::Done | LzwStatus::Ok) => {},
301 Ok(LzwStatus::NoProgress) => {
302 if self.check_for_end_code {
303 return Err(io::Error::new(io::ErrorKind::InvalidData, "no end code in lzw stream"));
304 }
305 },
306 Err(err @ LzwError::InvalidCode) => {
307 return Err(io::Error::new(io::ErrorKind::InvalidData, err));
308 }
309 }
310 Ok((decoded.consumed_in, decoded.consumed_out))
311 }
312}
313
314pub struct StreamingDecoder {
318 state: State,
319 internal_buffer: [u8; 9],
321 unused_internal_buffer_len: u8,
322 lzw_reader: LzwReader,
323 skip_frame_decoding: bool,
324 check_frame_consistency: bool,
325 allow_unknown_blocks: bool,
326 memory_limit: MemoryLimit,
327 version: Version,
328 width: u16,
329 height: u16,
330 global_color_table: Vec<u8>,
331 ext: ExtensionData,
333 current: Option<Frame<'static>>,
335 header_end_reached: bool,
337}
338
339#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
341pub enum Version {
342 V87a,
344 V89a,
346}
347
348struct ExtensionData {
349 id: AnyExtension,
350 data: Vec<u8>,
351 is_block_end: bool,
352}
353
354pub enum OutputBuffer<'a> {
356 Slice(&'a mut [u8]),
358 Vec(&'a mut Vec<u8>),
360 None,
362}
363
364impl OutputBuffer<'_> {
365 fn append(&mut self, buf: &[u8], memory_limit: &MemoryLimit) -> Result<(usize, usize), DecodingError> {
366 let (consumed, copied) = match self {
367 OutputBuffer::Slice(slice) => {
368 let len = cmp::min(buf.len(), slice.len());
369 slice[..len].copy_from_slice(&buf[..len]);
370 (len, len)
371 },
372 OutputBuffer::Vec(vec) => {
373 let vec: &mut Vec<u8> = vec;
374 let len = buf.len();
375 memory_limit.check_size(vec.len() + len)?;
376 vec.try_reserve(len).map_err(|_| io::ErrorKind::OutOfMemory)?;
377 if vec.capacity() - vec.len() >= len {
378 vec.extend_from_slice(buf);
379 }
380 (len, len)
381 },
382 OutputBuffer::None => (buf.len(), 0),
385 };
386 Ok((consumed, copied))
387 }
388}
389
390impl StreamingDecoder {
391 #[must_use]
393 pub fn new() -> Self {
394 let options = DecodeOptions::new();
395 Self::with_options(&options)
396 }
397
398 pub(crate) fn with_options(options: &DecodeOptions) -> Self {
399 Self {
400 internal_buffer: [0; 9],
401 unused_internal_buffer_len: 0,
402 state: Magic,
403 lzw_reader: LzwReader::new(options.check_for_end_code),
404 skip_frame_decoding: options.skip_frame_decoding,
405 check_frame_consistency: options.check_frame_consistency,
406 allow_unknown_blocks: options.allow_unknown_blocks,
407 memory_limit: options.memory_limit.clone(),
408 version: Version::V87a,
409 width: 0,
410 height: 0,
411 global_color_table: Vec::new(),
412 ext: ExtensionData {
413 id: AnyExtension(0),
414 data: Vec::with_capacity(256), is_block_end: true,
416 },
417 current: None,
418 header_end_reached: false,
419 }
420 }
421
422 pub fn update(
427 &mut self,
428 mut buf: &[u8],
429 write_into: &mut OutputBuffer<'_>,
430 ) -> Result<(usize, Decoded), DecodingError> {
431 let len = buf.len();
432 while !buf.is_empty() {
433 let (bytes, decoded) = self.next_state(buf, write_into)?;
434 buf = buf.get(bytes..).unwrap_or_default();
435 match decoded {
436 Decoded::Nothing => {},
437 result => {
438 return Ok((len-buf.len(), result));
439 },
440 };
441 }
442 Ok((len - buf.len(), Decoded::Nothing))
443 }
444
445 #[must_use]
447 pub fn last_ext(&self) -> (AnyExtension, &[u8], bool) {
448 (self.ext.id, &self.ext.data, self.ext.is_block_end)
449 }
450
451 #[must_use]
453 #[track_caller]
454 pub fn current_frame_mut(&mut self) -> &mut Frame<'static> {
455 self.current.as_mut().unwrap()
456 }
457
458 #[track_caller]
460 #[must_use]
461 pub fn current_frame(&self) -> &Frame<'static> {
462 self.current.as_ref().unwrap()
463 }
464
465 #[inline(always)]
467 fn try_current_frame(&mut self) -> Result<&mut Frame<'static>, DecodingError> {
468 self.current.as_mut().ok_or_else(|| DecodingError::format("bad state"))
469 }
470
471 #[must_use]
473 pub fn width(&self) -> u16 {
474 self.width
475 }
476
477 #[must_use]
479 pub fn height(&self) -> u16 {
480 self.height
481 }
482
483 #[must_use]
488 pub fn version(&self) -> Version {
489 self.version
490 }
491
492 #[inline]
493 fn next_state(&mut self, buf: &[u8], write_into: &mut OutputBuffer<'_>) -> Result<(usize, Decoded), DecodingError> {
494 macro_rules! goto (
495 ($n:expr, $state:expr) => ({
496 self.state = $state;
497 Ok(($n, Decoded::Nothing))
498 });
499 ($state:expr) => ({
500 self.state = $state;
501 Ok((1, Decoded::Nothing))
502 });
503 ($n:expr, $state:expr, emit $res:expr) => ({
504 self.state = $state;
505 Ok(($n, $res))
506 });
507 ($state:expr, emit $res:expr) => ({
508 self.state = $state;
509 Ok((1, $res))
510 })
511 );
512
513 macro_rules! ensure_min_length_buffer (
514 ($required:expr) => ({
515 let required: usize = $required;
516 if buf.len() >= required && self.unused_internal_buffer_len == 0 {
517 (required, &buf[..required])
518 } else {
519 let has = usize::from(self.unused_internal_buffer_len);
520 let mut consumed = 0;
521 if has < required {
522 let to_copy = buf.len().min(required - has);
523 let new_len = has + to_copy;
524 self.internal_buffer[has .. new_len].copy_from_slice(&buf[..to_copy]);
525 consumed += to_copy;
526 if new_len < required {
527 self.unused_internal_buffer_len = new_len as u8;
528 return Ok((consumed, Decoded::Nothing));
529 } else {
530 self.unused_internal_buffer_len = 0;
531 }
532 }
533 (consumed, &self.internal_buffer[..required])
534 }
535 })
536 );
537
538 let b = *buf.first().ok_or(io::ErrorKind::UnexpectedEof)?;
539
540 match self.state {
541 Magic => {
542 let (consumed, version) = ensure_min_length_buffer!(6);
543
544 self.version = match version {
545 b"GIF87a" => Version::V87a,
546 b"GIF89a" => Version::V89a,
547 _ => return Err(DecodingError::format("malformed GIF header")),
548 };
549
550 goto!(consumed, ScreenDescriptor)
551 },
552 ScreenDescriptor => {
553 let (consumed, desc) = ensure_min_length_buffer!(7);
554
555 self.width = u16::from_le_bytes(desc[..2].try_into().unwrap());
556 self.height = u16::from_le_bytes(desc[2..4].try_into().unwrap());
557 let global_flags = desc[4];
558 let background_color = desc[5];
559
560 let global_table = global_flags & 0x80 != 0;
561 let table_size = if global_table {
562 let table_size = PLTE_CHANNELS * (1 << ((global_flags & 0b111) + 1) as usize);
563 self.global_color_table.try_reserve_exact(table_size).map_err(|_| io::ErrorKind::OutOfMemory)?;
564 table_size
565 } else {
566 0usize
567 };
568
569 goto!(
570 consumed,
571 GlobalPalette(table_size),
572 emit Decoded::BackgroundColor(background_color)
573 )
574 },
575 ImageBlockStart => {
576 let (consumed, header) = ensure_min_length_buffer!(9);
577
578 let frame = self.current.as_mut().ok_or_else(|| DecodingError::format("bad state"))?;
579 frame.left = u16::from_le_bytes(header[..2].try_into().unwrap());
580 frame.top = u16::from_le_bytes(header[2..4].try_into().unwrap());
581 frame.width = u16::from_le_bytes(header[4..6].try_into().unwrap());
582 frame.height = u16::from_le_bytes(header[6..8].try_into().unwrap());
583
584 let flags = header[8];
585 frame.interlaced = (flags & 0b0100_0000) != 0;
586
587 if self.check_frame_consistency {
588 if self.width.checked_sub(frame.width) < Some(frame.left)
590 || self.height.checked_sub(frame.height) < Some(frame.top)
591 {
592 return Err(DecodingError::format("frame descriptor is out-of-bounds"));
593 }
594 }
595
596 let local_table = (flags & 0b1000_0000) != 0;
597 if local_table {
598 let table_size = flags & 0b0000_0111;
599 let pal_len = PLTE_CHANNELS * (1 << (table_size + 1));
600 frame.palette.get_or_insert_with(Vec::new)
601 .try_reserve_exact(pal_len).map_err(|_| io::ErrorKind::OutOfMemory)?;
602 goto!(consumed, LocalPalette(pal_len))
603 } else {
604 goto!(consumed, LocalPalette(0))
605 }
606 },
607 GlobalPalette(left) => {
608 if left > 0 {
610 let n = cmp::min(left, buf.len());
611 if n <= self.global_color_table.capacity() - self.global_color_table.len() {
612 self.global_color_table.extend_from_slice(&buf[..n]);
613 }
614 goto!(n, GlobalPalette(left - n))
615 } else {
616 goto!(BlockStart(b), emit Decoded::GlobalPalette(
617 mem::take(&mut self.global_color_table).into_boxed_slice()
618 ))
619 }
620 }
621 BlockStart(type_) => {
622 if !self.header_end_reached && type_ != Block::Extension as u8 {
623 self.header_end_reached = true;
624 return goto!(0, BlockStart(type_), emit Decoded::HeaderEnd);
625 }
626
627 match Block::from_u8(type_) {
628 Some(Block::Image) => {
629 self.add_frame();
630 goto!(0, ImageBlockStart, emit Decoded::BlockStart(Block::Image))
631 }
632 Some(Block::Extension) => {
633 self.ext.data.clear();
634 self.ext.id = AnyExtension(b);
635 if self.ext.id.into_known().is_none() {
636 return Err(DecodingError::format("unknown block type encountered"));
637 }
638 goto!(ExtensionBlockStart, emit Decoded::BlockStart(Block::Extension))
639 }
640 Some(Block::Trailer) => {
641 goto!(Trailer, emit Decoded::BlockStart(Block::Trailer))
643 }
644 None => {
645 if self.allow_unknown_blocks {
646 goto!(ExtensionDataBlock(b as usize))
647 } else {
648 Err(DecodingError::format("unknown block type encountered"))
649 }
650 }
651 }
652 },
653 BlockEnd => {
654 if b == Block::Trailer as u8 {
655 goto!(0, BlockStart(b))
658 } else {
659 goto!(BlockStart(b))
660 }
661 }
662 ExtensionBlockStart => {
663 self.ext.data.push(b);
664 goto!(ExtensionDataBlock(b as usize))
665 }
666 ExtensionDataBlock(left) => {
667 if left > 0 {
668 let n = cmp::min(left, buf.len());
669 self.memory_limit.check_size(self.ext.data.len() + n)?;
670 self.ext.data.try_reserve(n).map_err(|_| io::Error::from(io::ErrorKind::OutOfMemory))?;
671 self.ext.data.extend_from_slice(&buf[..n]);
672 goto!(n, ExtensionDataBlock(left - n))
673 } else if b == 0 {
674 self.ext.is_block_end = true;
675 match self.ext.id.into_known() {
676 Some(Extension::Application) => {
677 goto!(0, ApplicationExtension, emit Decoded::BlockFinished(self.ext.id))
678 }
679 Some(Extension::Control) => {
680 self.read_control_extension()?;
681 goto!(BlockEnd, emit Decoded::BlockFinished(self.ext.id))
682 },
683 _ => {
684 goto!(BlockEnd, emit Decoded::BlockFinished(self.ext.id))
685 }
686 }
687 } else {
688 self.ext.is_block_end = false;
689 goto!(ExtensionDataBlock(b as usize), emit Decoded::SubBlockFinished(self.ext.id))
690 }
691 }
692 ApplicationExtension => {
693 debug_assert_eq!(0, b);
694 if self.ext.data.len() >= 15 && &self.ext.data[1..13] == b"NETSCAPE2.0\x01" {
696 let repeat = &self.ext.data[13..15];
697 let repeat = u16::from(repeat[0]) | u16::from(repeat[1]) << 8;
698 goto!(BlockEnd, emit Decoded::Repetitions(if repeat == 0 { Repeat::Infinite } else { Repeat::Finite(repeat) }))
699 } else {
700 goto!(BlockEnd)
701 }
702 }
703 LocalPalette(left) => {
704 if left > 0 {
705 let n = cmp::min(left, buf.len());
706 let src = &buf[..n];
707 if let Some(pal) = self.try_current_frame()?.palette.as_mut() {
708 if pal.capacity() - pal.len() >= src.len() {
710 pal.extend_from_slice(src);
711 }
712 }
713 goto!(n, LocalPalette(left - n))
714 } else {
715 goto!(LzwInit(b))
716 }
717 }
718 LzwInit(min_code_size) => {
719 if !self.skip_frame_decoding {
720 self.lzw_reader.reset(min_code_size)?;
722 goto!(DecodeSubBlock(b as usize), emit Decoded::FrameMetadata(FrameDataType::Pixels))
723 } else {
724 LzwReader::check_code_size(min_code_size)?;
725 goto!(CopySubBlock(b as usize), emit Decoded::FrameMetadata(FrameDataType::Lzw { min_code_size }))
726 }
727 }
728 CopySubBlock(left) => {
729 debug_assert!(self.skip_frame_decoding);
730 if left > 0 {
731 let n = cmp::min(left, buf.len());
732 let (consumed, copied) = write_into.append(&buf[..n], &self.memory_limit)?;
733 goto!(consumed, CopySubBlock(left - consumed), emit Decoded::LzwDataCopied(copied))
734 } else if b != 0 {
735 goto!(CopySubBlock(b as usize))
736 } else {
737 goto!(0, FrameDecoded)
738 }
739 }
740 DecodeSubBlock(left) => {
741 debug_assert!(!self.skip_frame_decoding);
742 if left > 0 {
743 let n = cmp::min(left, buf.len());
744 if self.lzw_reader.has_ended() || matches!(write_into, OutputBuffer::None) {
745 return goto!(n, DecodeSubBlock(left - n), emit Decoded::Nothing);
746 }
747
748 let (mut consumed, bytes_len) = self.lzw_reader.decode_bytes(&buf[..n], write_into)?;
749
750 if consumed == 0 && bytes_len == 0 {
752 consumed = n;
753 }
754
755 let decoded = if let Some(bytes_len) = NonZeroUsize::new(bytes_len) {
756 Decoded::BytesDecoded(bytes_len)
757 } else {
758 Decoded::Nothing
759 };
760 goto!(consumed, DecodeSubBlock(left - consumed), emit decoded)
761 } else if b != 0 {
762 goto!(DecodeSubBlock(b as usize))
764 } else {
765 let (_, bytes_len) = self.lzw_reader.decode_bytes(&[], write_into)?;
766
767 if let Some(bytes_len) = NonZeroUsize::new(bytes_len) {
768 goto!(0, DecodeSubBlock(0), emit Decoded::BytesDecoded(bytes_len))
769 } else {
770 goto!(0, FrameDecoded)
771 }
772 }
773 }
774 FrameDecoded => {
775 self.current = None;
777 debug_assert_eq!(0, b);
778 goto!(BlockEnd, emit Decoded::DataEnd)
779 }
780 Trailer => goto!(0, Trailer, emit Decoded::Nothing),
781 }
782 }
783
784 fn read_control_extension(&mut self) -> Result<(), DecodingError> {
785 if self.ext.data.len() != 5 {
786 return Err(DecodingError::format("control extension has wrong length"));
787 }
788 let control = &self.ext.data[1..];
789
790 let frame = self.current.get_or_insert_with(Frame::default);
791 let control_flags = control[0];
792 frame.needs_user_input = control_flags & 0b10 != 0;
793 frame.dispose = match DisposalMethod::from_u8((control_flags & 0b11100) >> 2) {
794 Some(method) => method,
795 None => DisposalMethod::Any,
796 };
797 frame.delay = u16::from_le_bytes(control[1..3].try_into().unwrap());
798 frame.transparent = (control_flags & 1 != 0).then_some(control[3]);
799 Ok(())
800 }
801
802 fn add_frame(&mut self) {
803 if self.current.is_none() {
804 self.current = Some(Frame::default());
805 }
806 }
807}
808
809#[test]
810fn error_cast() {
811 let _ : Box<dyn error::Error> = DecodingError::format("testing").into();
812}