use thiserror::Error;
pub type Result<T> = std::result::Result<T, Error>;
#[non_exhaustive]
#[derive(Debug, Error)]
pub enum Error {
#[error("io error: {0}")]
Io(#[from] std::io::Error),
#[error("internal: {0}")]
Internal(String),
}
#[non_exhaustive]
#[derive(Debug, Error)]
pub enum ToolError {
#[error("invalid arguments: {0}")]
InvalidArguments(String),
#[error("not implemented")]
NotImplemented,
#[error("internal: {0}")]
Internal(String),
#[error("unauthorized: {0}")]
Unauthorized(String),
}
impl ToolError {
pub fn code(&self) -> i32 {
match self {
ToolError::InvalidArguments(_) => -32602,
ToolError::NotImplemented => -32601,
ToolError::Internal(_) => -32000,
ToolError::Unauthorized(_) => -32000,
}
}
pub fn symbolic(&self) -> &'static str {
match self {
ToolError::InvalidArguments(_) => "invalid_arguments",
ToolError::NotImplemented => "not_implemented",
ToolError::Internal(_) => "internal",
ToolError::Unauthorized(_) => "unauthorized",
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn invalid_arguments_maps_to_minus_32602() {
let e = ToolError::InvalidArguments("missing field".into());
assert_eq!(e.code(), -32602);
assert_eq!(e.symbolic(), "invalid_arguments");
}
#[test]
fn not_implemented_maps_to_minus_32601() {
assert_eq!(ToolError::NotImplemented.code(), -32601);
assert_eq!(ToolError::NotImplemented.symbolic(), "not_implemented");
}
#[test]
fn internal_maps_to_minus_32000() {
assert_eq!(ToolError::Internal("x".into()).code(), -32000);
assert_eq!(ToolError::Internal("x".into()).symbolic(), "internal");
}
#[test]
fn unauthorized_maps_to_minus_32000_with_symbolic() {
let e = ToolError::Unauthorized("no binding".into());
assert_eq!(e.code(), -32000);
assert_eq!(e.symbolic(), "unauthorized");
}
#[test]
fn error_io_round_trip() {
let io_err = std::io::Error::new(std::io::ErrorKind::BrokenPipe, "pipe closed");
let e: Error = io_err.into();
assert!(format!("{e}").contains("pipe closed"));
}
}