Skip to main content

opus_pure/
error.rs

1//! The crate's error type.
2
3use std::fmt;
4
5/// Anything that can go wrong encoding, decoding, or parsing an Opus stream.
6///
7/// The enum is `#[non_exhaustive]`, so match with a `_` arm: new variants are
8/// not a breaking change. The individual variants are not, deliberately —
9/// marking a tuple variant `#[non_exhaustive]` stops callers destructuring it
10/// at all, which would take away the message rather than protect it.
11/// [`BufferTooSmall`](Self::BufferTooSmall) is the exception, because a struct
12/// variant can be marked and still be matched with `..`.
13///
14/// Variants are grouped by who is at fault: [`Error::InvalidArgument`] and
15/// [`Error::BufferTooSmall`] mean the *caller* passed something the codec cannot
16/// honour, [`Error::InvalidPacket`] means the *bitstream* is malformed, and
17/// [`Error::Internal`] means a codec stage failed in a way that is not
18/// attributable to either.
19#[derive(Debug)]
20#[non_exhaustive]
21pub enum Error {
22    /// A configuration value is outside the range Opus allows — an unsupported
23    /// sample rate or channel count, a frame size no coding mode can carry, or a
24    /// mapping family that does not accept the requested layout.
25    InvalidArgument(&'static str),
26
27    /// The caller's output slice cannot hold the result. Both sizes are in the
28    /// unit of the call: bytes for `encode`, samples-per-channel for `decode`.
29    #[non_exhaustive]
30    BufferTooSmall {
31        /// What the operation needs.
32        needed: usize,
33        /// What the caller provided.
34        provided: usize,
35    },
36
37    /// The packet does not decode as Opus: a truncated or self-inconsistent
38    /// frame-length field, an impossible frame count, padding that runs off the
39    /// end, or a total duration above the 120 ms an Opus packet may carry.
40    InvalidPacket(&'static str),
41
42    /// The Ogg container is malformed: a missing capture pattern, an unsupported
43    /// page version, a CRC mismatch, or an `OpusHead`/`OpusTags` packet that does
44    /// not match RFC 7845.
45    InvalidStream(&'static str),
46
47    /// The underlying reader or writer failed.
48    Io(std::io::Error),
49
50    /// A codec stage failed. Reaching this from well-formed input is a bug in
51    /// this crate; the string names the stage.
52    Internal(&'static str),
53}
54
55impl Error {
56    pub(crate) fn buffer_too_small(needed: usize, provided: usize) -> Self {
57        Error::BufferTooSmall { needed, provided }
58    }
59}
60
61impl fmt::Display for Error {
62    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
63        match self {
64            Error::InvalidArgument(what) => write!(f, "invalid argument: {what}"),
65            Error::BufferTooSmall { needed, provided } => {
66                write!(f, "buffer too small: need {needed}, got {provided}")
67            }
68            Error::InvalidPacket(what) => write!(f, "invalid packet: {what}"),
69            Error::InvalidStream(what) => write!(f, "invalid ogg stream: {what}"),
70            Error::Io(e) => write!(f, "io error: {e}"),
71            Error::Internal(what) => write!(f, "internal codec error: {what}"),
72        }
73    }
74}
75
76impl std::error::Error for Error {
77    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
78        match self {
79            Error::Io(e) => Some(e),
80            _ => None,
81        }
82    }
83}
84
85impl From<std::io::Error> for Error {
86    fn from(e: std::io::Error) -> Self {
87        Error::Io(e)
88    }
89}
90
91/// Shorthand for a codec result.
92pub type Result<T> = std::result::Result<T, Error>;