blazen_audio_codec/
error.rs1use std::io;
11
12use blazen_audio::AudioError;
13use thiserror::Error;
14
15#[derive(Debug, Error)]
17pub enum CodecError {
18 #[error(
22 "blazen-audio-codec was built without the matching backend feature -- \
23 rebuild with `--features <backend>` (e.g. `encodec`) to enable on-device codec inference"
24 )]
25 EngineNotAvailable,
26
27 #[error("{0}")]
31 NotYetImplemented(String),
32
33 #[error("hf-hub fetch failed for {repo}: {source}")]
36 HfHub {
37 repo: String,
39 #[source]
41 source: io::Error,
42 },
43
44 #[error("io error: {0}")]
46 Io(#[from] io::Error),
47
48 #[error("candle error: {0}")]
50 Candle(String),
51
52 #[error("invalid input: {0}")]
56 InvalidInput(String),
57
58 #[error("{0}")]
60 Other(String),
61}
62
63impl CodecError {
64 #[must_use]
66 pub fn not_yet_implemented(message: impl Into<String>) -> Self {
67 Self::NotYetImplemented(message.into())
68 }
69
70 #[must_use]
72 pub fn invalid_input(message: impl Into<String>) -> Self {
73 Self::InvalidInput(message.into())
74 }
75
76 #[must_use]
78 pub fn other(message: impl Into<String>) -> Self {
79 Self::Other(message.into())
80 }
81}
82
83#[cfg(feature = "candle-backbone")]
84impl From<candle_core::Error> for CodecError {
85 fn from(err: candle_core::Error) -> Self {
86 Self::Candle(err.to_string())
87 }
88}
89
90impl From<CodecError> for AudioError {
93 fn from(err: CodecError) -> Self {
94 match err {
95 CodecError::EngineNotAvailable => Self::Unsupported(
96 "codec backend not built (rebuild with the matching feature flag)".to_string(),
97 ),
98 CodecError::NotYetImplemented(msg) => Self::Unsupported(msg),
99 CodecError::InvalidInput(msg) => Self::InvalidInput(msg),
100 CodecError::Io(io) => Self::Io(io),
101 CodecError::HfHub { repo, source } => {
102 Self::Backend(format!("hf-hub fetch failed for {repo}: {source}"))
103 }
104 CodecError::Candle(msg) => Self::Backend(format!("candle error: {msg}")),
105 CodecError::Other(msg) => Self::Backend(msg),
106 }
107 }
108}
109
110pub type Result<T> = std::result::Result<T, CodecError>;
112
113#[cfg(test)]
114mod tests {
115 use super::*;
116
117 #[test]
118 fn constructors_round_trip_messages() {
119 let nyi = CodecError::not_yet_implemented("foo");
120 assert!(matches!(nyi, CodecError::NotYetImplemented(ref m) if m == "foo"));
121
122 let invalid = CodecError::invalid_input("bar");
123 assert!(matches!(invalid, CodecError::InvalidInput(ref m) if m == "bar"));
124
125 let other = CodecError::other("baz");
126 assert!(matches!(other, CodecError::Other(ref m) if m == "baz"));
127 }
128
129 #[test]
130 fn engine_not_available_projects_to_unsupported() {
131 let err: AudioError = CodecError::EngineNotAvailable.into();
132 assert!(matches!(err, AudioError::Unsupported(_)));
133 }
134
135 #[test]
136 fn invalid_input_projects_to_invalid_input() {
137 let err: AudioError = CodecError::invalid_input("empty").into();
138 match err {
139 AudioError::InvalidInput(msg) => assert_eq!(msg, "empty"),
140 other => panic!("expected InvalidInput, got {other:?}"),
141 }
142 }
143}