use thiserror::Error;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ModelPath(String);
impl ModelPath {
pub fn new(s: &str) -> Result<Self, GigasttError> {
if s.is_empty() {
return Err(GigasttError::InvalidAudio {
reason: "empty model path".into(),
});
}
Ok(ModelPath(s.to_string()))
}
pub fn as_str(&self) -> &str {
&self.0
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Reason(String);
impl Reason {
pub fn new(s: &str) -> Result<Self, GigasttError> {
if s.is_empty() {
return Err(GigasttError::InvalidAudio {
reason: "empty error reason".into(),
});
}
Ok(Reason(s.to_string()))
}
pub fn as_str(&self) -> &str {
&self.0
}
}
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum GigasttError {
#[error("model load error at {path}")]
ModelLoad {
path: String,
#[source]
source: Option<Box<dyn std::error::Error + Send + Sync>>,
},
#[error("inference failed")]
Inference {
#[source]
source: Box<dyn std::error::Error + Send + Sync>,
},
#[error("invalid audio: {reason}")]
InvalidAudio {
reason: String,
},
#[error(transparent)]
Io(#[from] std::io::Error),
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_model_path_rejects_empty() {
assert!(ModelPath::new("").is_err());
}
#[test]
fn test_model_path_accepts_valid() {
let p = ModelPath::new("encoder.onnx").unwrap();
assert_eq!(p.as_str(), "encoder.onnx");
}
#[test]
fn test_reason_rejects_empty() {
assert!(Reason::new("").is_err());
}
#[test]
fn test_reason_accepts_valid() {
let r = Reason::new("too long").unwrap();
assert_eq!(r.as_str(), "too long");
}
#[test]
fn test_display_model_load() {
let e = GigasttError::ModelLoad {
path: "encoder.onnx".into(),
source: Some(Box::new(std::io::Error::new(
std::io::ErrorKind::Other,
"missing weights",
))),
};
assert!(e.to_string().contains("encoder.onnx"));
}
#[test]
fn test_display_inference() {
let e = GigasttError::Inference {
source: Box::new(std::io::Error::new(
std::io::ErrorKind::Other,
"decoder failed",
)),
};
assert_eq!(e.to_string(), "inference failed");
}
#[test]
fn test_display_invalid_audio() {
let e = GigasttError::InvalidAudio {
reason: "too long".into(),
};
assert_eq!(e.to_string(), "invalid audio: too long");
}
#[test]
fn test_display_io() {
let e = GigasttError::Io(std::io::Error::new(std::io::ErrorKind::NotFound, "gone"));
assert!(e.to_string().contains("gone"));
}
#[test]
fn test_from_io_error() {
let io_err = std::io::Error::new(std::io::ErrorKind::PermissionDenied, "denied");
let e: GigasttError = io_err.into();
assert!(matches!(e, GigasttError::Io(_)));
}
#[test]
fn test_error_source_io() {
let e = GigasttError::Io(std::io::Error::new(std::io::ErrorKind::NotFound, "x"));
assert!(std::error::Error::source(&e).is_none());
}
#[test]
fn test_into_anyhow() {
fn returns_anyhow() -> anyhow::Result<()> {
Err(GigasttError::Inference {
source: Box::new(std::io::Error::new(std::io::ErrorKind::Other, "test")),
})?;
Ok(())
}
assert!(returns_anyhow().is_err());
}
}