#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Error {
code: Code,
message: String,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum Code {
Ok = 0,
Cancelled = 1,
Unknown = 2,
InvalidArgument = 3,
DeadlineExceeded = 4,
NotFound = 5,
AlreadyExists = 6,
PermissionDenied = 7,
ResourceExhausted = 8,
FailedPrecondition = 9,
Aborted = 10,
OutOfRange = 11,
Unimplemented = 12,
Internal = 13,
Unavailable = 14,
DataLoss = 15,
Unauthenticated = 16,
}
impl Code {
pub fn description(&self) -> &'static str {
match self {
Code::Ok => "The operation completed successfully",
Code::Cancelled => "The operation was cancelled",
Code::Unknown => "Unknown error",
Code::InvalidArgument => "Client specified an invalid argument",
Code::DeadlineExceeded => "Deadline expired before operation could complete",
Code::NotFound => "Some requested entity was not found",
Code::AlreadyExists => "Some entity that we attempted to create already exists",
Code::PermissionDenied => {
"The caller does not have permission to execute the specified operation"
}
Code::ResourceExhausted => "Some resource has been exhausted",
Code::FailedPrecondition => {
"The system is not in a state required for the operation's execution"
}
Code::Aborted => "The operation was aborted",
Code::OutOfRange => "Operation was attempted past the valid range",
Code::Unimplemented => "Operation is not implemented or not supported",
Code::Internal => "Internal error",
Code::Unavailable => "The service is currently unavailable",
Code::DataLoss => "Unrecoverable data loss or corruption",
Code::Unauthenticated => "The request does not have valid authentication credentials",
}
}
}
impl std::fmt::Display for Code {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(self.description(), f)
}
}
impl Error {
pub fn new(code: Code, message: impl Into<String>) -> Self {
Self {
code,
message: message.into(),
}
}
pub fn ok(message: impl Into<String>) -> Self {
Self::new(Code::Ok, message)
}
pub fn cancelled(message: impl Into<String>) -> Self {
Self::new(Code::Cancelled, message)
}
pub fn unknown(message: impl Into<String>) -> Self {
Self::new(Code::Unknown, message)
}
pub fn invalid_argument(message: impl Into<String>) -> Self {
Self::new(Code::InvalidArgument, message)
}
pub fn deadline_exceeded(message: impl Into<String>) -> Self {
Self::new(Code::DeadlineExceeded, message)
}
pub fn not_found(message: impl Into<String>) -> Self {
Self::new(Code::NotFound, message)
}
pub fn already_exists(message: impl Into<String>) -> Self {
Self::new(Code::AlreadyExists, message)
}
pub fn permission_denied(message: impl Into<String>) -> Self {
Self::new(Code::PermissionDenied, message)
}
pub fn resource_exhausted(message: impl Into<String>) -> Self {
Self::new(Code::ResourceExhausted, message)
}
pub fn failed_precondition(message: impl Into<String>) -> Self {
Self::new(Code::FailedPrecondition, message)
}
pub fn aborted(message: impl Into<String>) -> Self {
Self::new(Code::Aborted, message)
}
pub fn out_of_range(message: impl Into<String>) -> Self {
Self::new(Code::OutOfRange, message)
}
pub fn unimplemented(message: impl Into<String>) -> Self {
Self::new(Code::Unimplemented, message)
}
pub fn internal(message: impl Into<String>) -> Self {
Self::new(Code::Internal, message)
}
pub fn unavailable(message: impl Into<String>) -> Self {
Self::new(Code::Unavailable, message)
}
pub fn data_loss(message: impl Into<String>) -> Self {
Self::new(Code::DataLoss, message)
}
pub fn unauthenticated(message: impl Into<String>) -> Self {
Self::new(Code::Unauthenticated, message)
}
pub fn code(&self) -> Code {
self.code
}
pub fn message(&self) -> &str {
&self.message
}
pub(crate) fn from_std_error_generic(
err: impl Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
) -> Self {
Self::from_std_error(err.into())
}
pub fn from_std_error(err: Box<dyn std::error::Error + Send + Sync + 'static>) -> Self {
Self::try_from_std_error(err)
.unwrap_or_else(|err| Self::new(Code::Unknown, err.to_string()))
}
pub fn try_from_std_error(
err: Box<dyn std::error::Error + Send + Sync + 'static>,
) -> Result<Self, Box<dyn std::error::Error + Send + Sync + 'static>> {
let err = match err.downcast::<Error>() {
Ok(error) => return Ok(*error),
Err(err) => err,
};
if let Some(error) = Self::find_in_source_chain(&*err) {
return Ok(error);
}
Err(err)
}
fn find_in_source_chain(err: &(dyn std::error::Error + 'static)) -> Option<Self> {
use crate::types::InvalidMapKeyType;
let mut source = Some(err);
while let Some(err) = source {
if let Some(error) = err.downcast_ref::<Error>() {
return Some((*error).clone());
}
if let Some(invalid_mapkey_type) = err.downcast_ref::<InvalidMapKeyType>() {
return Some(Self::invalid_argument(invalid_mapkey_type.0.to_string()));
}
source = err.source();
}
None
}
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "code: {:?}, message: {:?}", self.code(), self.message(),)
}
}
impl std::error::Error for Error {}
pub trait IntoError {
fn into_error(self) -> Error;
}
impl<E: std::error::Error + Send + Sync + 'static> IntoError for E {
fn into_error(self) -> Error {
Error::from_std_error_generic(Box::new(self))
}
}
impl From<&crate::ffi::Status> for Error {
fn from(value: &crate::ffi::Status) -> Self {
use crate::ffi::StatusCode;
match value.code() {
StatusCode::Ok => Error::ok(value.message().to_string_lossy()),
StatusCode::Cancelled => Error::cancelled(value.message().to_string_lossy()),
StatusCode::Unknown => Error::unknown(value.message().to_string_lossy()),
StatusCode::InvalidArgument => {
Error::invalid_argument(value.message().to_string_lossy())
}
StatusCode::DeadlineExceeded => {
Error::deadline_exceeded(value.message().to_string_lossy())
}
StatusCode::NotFound => Error::not_found(value.message().to_string_lossy()),
StatusCode::AlreadyExists => {
Error::already_exists(value.message().to_string_lossy())
}
StatusCode::PermissionDenied => {
Error::permission_denied(value.message().to_string_lossy())
}
StatusCode::ResourceExhausted => {
Error::resource_exhausted(value.message().to_string_lossy())
}
StatusCode::FailedPrecondition => {
Error::failed_precondition(value.message().to_string_lossy())
}
StatusCode::Aborted => Error::aborted(value.message().to_string_lossy()),
StatusCode::OutOfRange => Error::out_of_range(value.message().to_string_lossy()),
StatusCode::Unimplemented => {
Error::unimplemented(value.message().to_string_lossy())
}
StatusCode::Internal => Error::internal(value.message().to_string_lossy()),
StatusCode::Unavailable => Error::unavailable(value.message().to_string_lossy()),
StatusCode::DataLoss => Error::data_loss(value.message().to_string_lossy()),
StatusCode::Unauthenticated => {
Error::unauthenticated(value.message().to_string_lossy())
}
}
}
}
impl From<crate::ffi::Status> for Error {
fn from(value: crate::ffi::Status) -> Self {
Self::from(&value)
}
}
impl From<&Error> for crate::ffi::Status {
fn from(value: &Error) -> Self {
use crate::ffi::Status;
match value.code() {
Code::Ok => Status::ok(),
Code::Cancelled => Status::cancelled(value.message()),
Code::Unknown => Status::unknown(value.message()),
Code::InvalidArgument => Status::invalid_argument(value.message()),
Code::DeadlineExceeded => Status::deadline_exceeded(value.message()),
Code::NotFound => Status::not_found(value.message()),
Code::AlreadyExists => Status::already_exists(value.message()),
Code::PermissionDenied => Status::permission_denied(value.message()),
Code::ResourceExhausted => Status::resource_exhausted(value.message()),
Code::FailedPrecondition => Status::failed_precondition(value.message()),
Code::Aborted => Status::aborted(value.message()),
Code::OutOfRange => Status::out_of_range(value.message()),
Code::Unimplemented => Status::unimplemented(value.message()),
Code::Internal => Status::internal(value.message()),
Code::Unavailable => Status::unavailable(value.message()),
Code::DataLoss => Status::data_loss(value.message()),
Code::Unauthenticated => Status::unauthenticated(value.message()),
}
}
}
impl From<Error> for crate::ffi::Status {
fn from(value: Error) -> Self {
Self::from(&value)
}
}