use core::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum ErrorKind {
BadArg,
BufferTooSmall,
InternalError,
InvalidPacket,
Unimplemented,
InvalidState,
AllocFail,
}
impl ErrorKind {
pub const fn to_raw(self) -> i32 {
match self {
ErrorKind::BadArg => -1,
ErrorKind::BufferTooSmall => -2,
ErrorKind::InternalError => -3,
ErrorKind::InvalidPacket => -4,
ErrorKind::Unimplemented => -5,
ErrorKind::InvalidState => -6,
ErrorKind::AllocFail => -7,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Error {
kind: ErrorKind,
message: &'static str,
}
impl Error {
pub(crate) const BAD_ARG: Error = Error::bad_arg("invalid argument");
pub(crate) const BUFFER_TOO_SMALL: Error = Error::buffer_too_small("output buffer too small");
pub(crate) const INTERNAL_ERROR: Error = Error::internal("internal error");
pub(crate) const INVALID_PACKET: Error = Error::invalid_packet("invalid packet");
#[allow(dead_code)]
pub(crate) const UNIMPLEMENTED: Error =
Error::new(ErrorKind::Unimplemented, "request not implemented");
pub(crate) const INVALID_SAMPLING_RATE: Error = Error::bad_arg("invalid sampling rate");
pub(crate) const INVALID_CHANNELS: Error = Error::bad_arg("invalid number of channels");
pub(crate) const INVALID_FRAME_SIZE: Error = Error::bad_arg("invalid frame size");
pub(crate) const INPUT_TOO_SHORT: Error = Error::bad_arg("input buffer too small for frame");
pub(crate) const FRAME_SIZE_TOO_SMALL: Error =
Error::buffer_too_small("output buffer too small: frame_size is shorter than the packet");
pub(crate) const LOST_FRAME_SIZE: Error =
Error::bad_arg("lost frame: frame_size must be a multiple of 2.5 ms");
pub(crate) const INVALID_COMPLEXITY: Error = Error::bad_arg("invalid complexity");
pub(crate) const INVALID_LSB_DEPTH: Error = Error::bad_arg("invalid LSB depth");
pub(crate) const INVALID_PACKET_LOSS: Error = Error::bad_arg("invalid packet loss percentage");
pub(crate) const fn new(kind: ErrorKind, message: &'static str) -> Self {
Error { kind, message }
}
pub(crate) const fn bad_arg(message: &'static str) -> Self {
Error::new(ErrorKind::BadArg, message)
}
pub(crate) const fn buffer_too_small(message: &'static str) -> Self {
Error::new(ErrorKind::BufferTooSmall, message)
}
pub(crate) const fn internal(message: &'static str) -> Self {
Error::new(ErrorKind::InternalError, message)
}
pub(crate) const fn invalid_packet(message: &'static str) -> Self {
Error::new(ErrorKind::InvalidPacket, message)
}
pub const fn kind(&self) -> ErrorKind {
self.kind
}
pub const fn message(&self) -> &'static str {
self.message
}
pub const fn to_raw(&self) -> i32 {
self.kind.to_raw()
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.message)
}
}
impl core::error::Error for Error {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn raw_codes_match_libopus() {
let kinds = [
(ErrorKind::BadArg, -1),
(ErrorKind::BufferTooSmall, -2),
(ErrorKind::InternalError, -3),
(ErrorKind::InvalidPacket, -4),
(ErrorKind::Unimplemented, -5),
(ErrorKind::InvalidState, -6),
(ErrorKind::AllocFail, -7),
];
for (kind, raw) in kinds {
assert_eq!(kind.to_raw(), raw);
assert_eq!(Error::new(kind, "x").to_raw(), raw);
}
}
#[test]
fn display_writes_the_message() {
let err = Error::BUFFER_TOO_SMALL;
assert_eq!(format!("{err}"), "output buffer too small");
assert_eq!(err.kind(), ErrorKind::BufferTooSmall);
assert_eq!(err.message(), "output buffer too small");
}
}