Files
dev/src/status/status.rs

114 lines
2.8 KiB
Rust

pub type Result<T> = std::result::Result<T, Status>;
pub trait ResultExt<T> {
fn with_context<C, F>(self, context: F) -> Result<T>
where
C: Into<String>,
F: FnOnce() -> C;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Code {
InvalidArgument,
FailedPrecondition,
NotFound,
PermissionDenied,
Internal,
}
#[derive(Debug)]
pub struct Status {
code: Code,
message: String,
source: Option<Box<dyn std::error::Error + Send + Sync + 'static>>,
}
impl Status {
pub fn new(code: Code, message: impl Into<String>) -> Self {
Self {
code,
message: message.into(),
source: None,
}
}
pub fn not_found(message: impl Into<String>) -> Self {
Self::new(Code::NotFound, message)
}
pub fn invalid_argument(message: impl Into<String>) -> Self {
Self::new(Code::InvalidArgument, message)
}
pub fn failed_precondition(message: impl Into<String>) -> Self {
Self::new(Code::FailedPrecondition, message)
}
pub fn permission_denied(message: impl Into<String>) -> Self {
Self::new(Code::PermissionDenied, message)
}
pub fn internal(message: impl Into<String>) -> Self {
Self::new(Code::Internal, message)
}
pub fn with_source<E>(mut self, source: E) -> Self
where
E: std::error::Error + Send + Sync + 'static,
{
self.source = Some(Box::new(source));
self
}
pub fn with_context(self, context: impl Into<String>) -> Self {
Self::new(self.code, context).with_source(self)
}
pub fn code(&self) -> Code {
self.code
}
pub fn message(&self) -> &str {
&self.message
}
}
impl std::fmt::Display for Status {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(formatter, "{:?}: {}", self.code, self.message)
}
}
impl std::error::Error for Status {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.source
.as_deref()
.map(|source| source as &(dyn std::error::Error + 'static))
}
}
impl From<std::io::Error> for Status {
fn from(error: std::io::Error) -> Self {
let code = match error.kind() {
std::io::ErrorKind::NotFound => Code::NotFound,
std::io::ErrorKind::PermissionDenied => Code::PermissionDenied,
_ => Code::Internal,
};
Self::new(code, error.to_string()).with_source(error)
}
}
impl<T, E> ResultExt<T> for std::result::Result<T, E>
where
E: Into<Status>,
{
fn with_context<C, F>(self, context: F) -> Result<T>
where
C: Into<String>,
F: FnOnce() -> C,
{
self.map_err(|error| error.into().with_context(context()))
}
}