Skip to main content

ahx_rs/
error.rs

1use core::fmt;
2
3/// A structural violation of the supported AHX format.
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5#[non_exhaustive]
6pub enum InvalidData {
7    /// The input does not begin with the AHX file signature.
8    FileSignature,
9    /// The encoded header length cannot contain the required fields and signature.
10    HeaderLength,
11    /// The complete header lacks its CRI copyright signature.
12    CopyrightSignature,
13    /// The declared sample count is zero or exceeds the supported signed range.
14    SampleCount(u32),
15    /// A packet does not begin with the supported fixed MPEG header.
16    FrameHeader,
17    /// A grouped quantizer contains a value outside its radix's three-digit range.
18    GroupedQuantizer,
19    /// A compressed frame exceeds the format's byte bound.
20    FrameLength,
21    /// The final packet is not followed by the CRI end marker.
22    EndMarker,
23}
24
25impl fmt::Display for InvalidData {
26    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27        match self {
28            Self::FileSignature => f.write_str("file signature"),
29            Self::HeaderLength => f.write_str("header length"),
30            Self::CopyrightSignature => f.write_str("copyright signature"),
31            Self::SampleCount(count) => write!(f, "declared sample count {count}"),
32            Self::FrameHeader => f.write_str("MPEG frame header"),
33            Self::GroupedQuantizer => f.write_str("grouped quantizer"),
34            Self::FrameLength => f.write_str("frame length"),
35            Self::EndMarker => f.write_str("end marker"),
36        }
37    }
38}
39
40/// A codec profile or playback rate outside the supported AHX subset.
41#[derive(Debug, Clone, Copy, PartialEq, Eq)]
42#[non_exhaustive]
43pub enum UnsupportedData {
44    /// The header is not unencrypted mono type `0x10`, version 6.
45    Profile,
46    /// The declared playback rate in Hz is unsupported.
47    SampleRate(u32),
48}
49
50impl fmt::Display for UnsupportedData {
51    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52        match self {
53            Self::Profile => f.write_str("expected unencrypted mono type 0x10 version 6"),
54            Self::SampleRate(rate) => write!(f, "declared sample rate {rate} Hz"),
55        }
56    }
57}
58
59/// A decoding, profile, caller-buffer, or input/output error.
60#[derive(Debug)]
61#[non_exhaustive]
62pub enum Error {
63    /// Input ended inside a header, frame, or end marker.
64    Truncated,
65    /// The input uses a codec profile or rate that this decoder does not support.
66    Unsupported(UnsupportedData),
67    /// The input violates the supported format.
68    Invalid(InvalidData),
69    /// A container decode previously failed; construct a new decoder to restart.
70    Failed,
71    /// Caller-owned PCM storage cannot hold a complete frame.
72    BufferTooSmall {
73        /// Required number of `i16` elements.
74        required: usize,
75        /// Provided number of `i16` elements.
76        provided: usize,
77    },
78    /// The standard I/O reader failed for a reason other than unexpected EOF.
79    #[cfg(feature = "std")]
80    Io(std::io::Error),
81}
82
83impl fmt::Display for Error {
84    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85        match self {
86            Self::Truncated => f.write_str("truncated AHX data"),
87            Self::Unsupported(reason) => write!(f, "unsupported AHX: {reason}"),
88            Self::Invalid(reason) => write!(f, "invalid AHX: {reason}"),
89            Self::Failed => f.write_str("AHX decoder cannot continue after an error"),
90            Self::BufferTooSmall { required, provided } => write!(
91                f,
92                "PCM buffer needs {required} i16 elements, received {provided}"
93            ),
94            #[cfg(feature = "std")]
95            Self::Io(error) => error.fmt(f),
96        }
97    }
98}
99
100impl core::error::Error for Error {
101    fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
102        #[cfg(feature = "std")]
103        if let Self::Io(error) = self {
104            return Some(error);
105        }
106        None
107    }
108}
109
110#[cfg(feature = "std")]
111impl From<std::io::Error> for Error {
112    fn from(error: std::io::Error) -> Self {
113        if error.kind() == std::io::ErrorKind::UnexpectedEof {
114            Self::Truncated
115        } else {
116            Self::Io(error)
117        }
118    }
119}
120
121pub(crate) type Result<T> = core::result::Result<T, Error>;