audio-codec-bsd 0.1.1

FLAC/PCM/WAV multi-format audio container decoder (symphonia + hound, pure Rust) emitting planar audio-core-bsd AudioFrames
Documentation
//! Codec errors and the crate [`Result`] alias.

use thiserror::Error;

/// Errors that can arise when opening or decoding an audio container.
///
/// All variants carry enough information to build a useful diagnostic without
/// exposing backend-specific error types (`std::io::Error` is not `Eq`, so it
/// is converted to a [`String`] at the boundary).
#[derive(Debug, Clone, PartialEq, Eq, Error)]
pub enum CodecError {
    /// An I/O failure occurred (file open, read, seek).
    #[error("I/O error: {0}")]
    Io(String),

    /// The container format is unsupported or could not be recognised.
    #[error("unsupported or unrecognised format: {0}")]
    Format(String),

    /// A decode failure occurred (corrupt stream or malformed packet).
    #[error("decode error: {0}")]
    Decode(String),

    /// The end of the stream was reached where more data was expected.
    ///
    /// [`ContainerDecoder::next_frame`](crate::ContainerDecoder::next_frame)
    /// returns `Ok(None)` for normal end-of-stream; this variant is reserved
    /// for callers that treat EOF as a hard error.
    #[error("end of stream")]
    Eof,

    /// The sample rate is zero or otherwise unsupported.
    #[error("invalid sample rate: {0} Hz")]
    InvalidSampleRate(u32),

    /// The channel count is zero or otherwise unsupported.
    #[error("invalid channel count: {0}")]
    InvalidChannelCount(u16),

    /// A destination buffer was smaller than required.
    #[error("buffer too small: needed {needed} samples, have {have}")]
    BufferTooSmall {
        /// Required number of samples.
        needed: usize,
        /// Samples actually available.
        have: usize,
    },
}

/// Convenience alias used by consumers of this crate.
pub type Result<T> = core::result::Result<T, CodecError>;

#[cfg(test)]
mod tests {
    use super::{CodecError, Result};

    #[test]
    fn io_display_includes_message() {
        let msg = CodecError::Io("permission denied".into()).to_string();
        assert_eq!(msg, "I/O error: permission denied");
    }

    #[test]
    fn format_display_includes_message() {
        let msg = CodecError::Format("unknown magic bytes".into()).to_string();
        assert_eq!(
            msg,
            "unsupported or unrecognised format: unknown magic bytes"
        );
    }

    #[test]
    fn decode_display_includes_message() {
        let msg = CodecError::Decode("truncated frame".into()).to_string();
        assert_eq!(msg, "decode error: truncated frame");
    }

    #[test]
    fn eof_display_is_stable() {
        assert_eq!(CodecError::Eof.to_string(), "end of stream");
    }

    #[test]
    fn invalid_sample_rate_display_includes_value() {
        let msg = CodecError::InvalidSampleRate(0).to_string();
        assert_eq!(msg, "invalid sample rate: 0 Hz");
    }

    #[test]
    fn invalid_channel_count_display_includes_value() {
        let msg = CodecError::InvalidChannelCount(7).to_string();
        assert_eq!(msg, "invalid channel count: 7");
    }

    #[test]
    fn buffer_too_small_display_includes_both_counts() {
        let msg = CodecError::BufferTooSmall {
            needed: 100,
            have: 50,
        }
        .to_string();
        assert_eq!(msg, "buffer too small: needed 100 samples, have 50");
    }

    #[test]
    fn result_alias_ok_carries_value() {
        let ok: Result<u32> = Ok(42);
        assert_eq!(ok.map(|v| v + 1), Ok(43));
    }

    #[test]
    fn result_alias_err_carries_codec_error() {
        let err: Result<u32> = Err(CodecError::InvalidChannelCount(0));
        assert_eq!(err.err(), Some(CodecError::InvalidChannelCount(0)));
    }

    #[test]
    fn clone_and_partial_eq_hold_across_variants() {
        let a = CodecError::BufferTooSmall { needed: 2, have: 1 };
        assert_eq!(a.clone(), a);
        // Across-variant inequality (both carry the integer `1`).
        assert_ne!(
            CodecError::InvalidSampleRate(1),
            CodecError::InvalidChannelCount(1),
        );
        // String variants compare by content.
        assert_eq!(CodecError::Io("x".into()), CodecError::Io("x".into()),);
    }
}