use serde_json::{Value, json};
use thiserror::Error;
use crate::Permissions;
#[derive(Debug, Clone, PartialEq, Eq, Error)]
#[error("permission denied: requires {required:?}, granted {granted:?}")]
#[non_exhaustive]
pub struct PermissionDenied {
pub required: Permissions,
pub granted: Permissions,
}
impl PermissionDenied {
pub fn new(required: Permissions, granted: Permissions) -> Self {
Self { required, granted }
}
}
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum ToolError {
#[error(transparent)]
PermissionDenied(#[from] PermissionDenied),
#[error("invalid argument: {0}")]
InvalidArgument(String),
#[error("internal: {0}")]
Internal(String),
}
pub const ERROR_CODE_PERMISSION_DENIED: i32 = -32001;
impl ToolError {
pub fn json_rpc_code(&self) -> i32 {
match self {
ToolError::PermissionDenied(_) => ERROR_CODE_PERMISSION_DENIED,
ToolError::InvalidArgument(_) => -32602,
ToolError::Internal(_) => -32603,
}
}
pub fn json_rpc_data(&self) -> Value {
match self {
ToolError::PermissionDenied(pd) => json!({
"kind": "permission_denied",
"required": pd.required.bits(),
"granted": pd.granted.bits(),
}),
ToolError::InvalidArgument(msg) => json!({
"kind": "invalid_argument",
"message": msg,
}),
ToolError::Internal(msg) => json!({
"kind": "internal",
"message": msg,
}),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn permission_denied_json_rpc_data_carries_kind_and_bits() {
let err = ToolError::PermissionDenied(PermissionDenied {
required: Permissions::WRITE,
granted: Permissions::READ,
});
assert_eq!(err.json_rpc_code(), ERROR_CODE_PERMISSION_DENIED);
let data = err.json_rpc_data();
assert_eq!(data["kind"], "permission_denied");
assert_eq!(data["required"], Permissions::WRITE.bits());
assert_eq!(data["granted"], Permissions::READ.bits());
}
}