use std::io;
use blazen_audio::AudioError;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum CodecError {
#[error(
"blazen-audio-codec was built without the matching backend feature -- \
rebuild with `--features <backend>` (e.g. `encodec`) to enable on-device codec inference"
)]
EngineNotAvailable,
#[error("{0}")]
NotYetImplemented(String),
#[error("hf-hub fetch failed for {repo}: {source}")]
HfHub {
repo: String,
#[source]
source: io::Error,
},
#[error("io error: {0}")]
Io(#[from] io::Error),
#[error("candle error: {0}")]
Candle(String),
#[error("invalid input: {0}")]
InvalidInput(String),
#[error("{0}")]
Other(String),
}
impl CodecError {
#[must_use]
pub fn not_yet_implemented(message: impl Into<String>) -> Self {
Self::NotYetImplemented(message.into())
}
#[must_use]
pub fn invalid_input(message: impl Into<String>) -> Self {
Self::InvalidInput(message.into())
}
#[must_use]
pub fn other(message: impl Into<String>) -> Self {
Self::Other(message.into())
}
}
#[cfg(feature = "candle-backbone")]
impl From<candle_core::Error> for CodecError {
fn from(err: candle_core::Error) -> Self {
Self::Candle(err.to_string())
}
}
impl From<CodecError> for AudioError {
fn from(err: CodecError) -> Self {
match err {
CodecError::EngineNotAvailable => Self::Unsupported(
"codec backend not built (rebuild with the matching feature flag)".to_string(),
),
CodecError::NotYetImplemented(msg) => Self::Unsupported(msg),
CodecError::InvalidInput(msg) => Self::InvalidInput(msg),
CodecError::Io(io) => Self::Io(io),
CodecError::HfHub { repo, source } => {
Self::Backend(format!("hf-hub fetch failed for {repo}: {source}"))
}
CodecError::Candle(msg) => Self::Backend(format!("candle error: {msg}")),
CodecError::Other(msg) => Self::Backend(msg),
}
}
}
pub type Result<T> = std::result::Result<T, CodecError>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn constructors_round_trip_messages() {
let nyi = CodecError::not_yet_implemented("foo");
assert!(matches!(nyi, CodecError::NotYetImplemented(ref m) if m == "foo"));
let invalid = CodecError::invalid_input("bar");
assert!(matches!(invalid, CodecError::InvalidInput(ref m) if m == "bar"));
let other = CodecError::other("baz");
assert!(matches!(other, CodecError::Other(ref m) if m == "baz"));
}
#[test]
fn engine_not_available_projects_to_unsupported() {
let err: AudioError = CodecError::EngineNotAvailable.into();
assert!(matches!(err, AudioError::Unsupported(_)));
}
#[test]
fn invalid_input_projects_to_invalid_input() {
let err: AudioError = CodecError::invalid_input("empty").into();
match err {
AudioError::InvalidInput(msg) => assert_eq!(msg, "empty"),
other => panic!("expected InvalidInput, got {other:?}"),
}
}
}