shrupl/src/error.rs
2025-07-15 14:55:29 +00:00

203 lines
4.7 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use std::fmt;
use crate::sharry;
#[derive(Debug, thiserror::Error)]
pub enum Parameter {
#[error("given URI {0:?}")]
Uri(sharry::Uri),
#[error("given Alias ID {0:?}")]
AliasID(sharry::AliasID),
#[error("stored Share ID {0:?}")]
ShareID(sharry::ShareID),
#[error("stored {0:?}")]
FileID(sharry::FileID),
}
// a helper to generate all the `From<T> for Parameter` impls
macro_rules! impl_param_from {
// $typ: the source type; $var: the enumvariant name
( $( $typ:path => $var:ident ),* $(,)? ) => {
$(
impl From<$typ> for Parameter {
fn from(value: $typ) -> Self {
Self::$var(value)
}
}
)*
};
}
impl_param_from! {
sharry::Uri => Uri,
sharry::AliasID => AliasID,
sharry::ShareID => ShareID,
sharry::FileID => FileID,
}
impl Parameter {
fn is_fatal(&self) -> bool {
self.is_uri() || self.is_alias_id()
}
#[must_use]
pub fn is_uri(&self) -> bool {
matches!(self, Self::Uri(_))
}
#[must_use]
pub fn is_alias_id(&self) -> bool {
matches!(self, Self::AliasID(_))
}
#[must_use]
pub fn is_share_id(&self) -> bool {
matches!(self, Self::ShareID(_))
}
#[must_use]
pub fn is_file_id(&self) -> bool {
matches!(self, Self::FileID(_))
}
}
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error(transparent)]
StdIo(#[from] std::io::Error),
#[error("Response error: {0}")]
Response(String),
#[error("Invalid {0}")]
InvalidParameter(Parameter),
#[error("Mismatch, expected {expected:?} but got {actual:?}")]
Mismatch { expected: String, actual: String },
#[error("Unknown error: {0}")]
Unknown(String),
}
pub type Result<T> = std::result::Result<T, Error>;
// a helper to generate all the `From<T> for Error` impls
macro_rules! impl_error_from {
// $typ: the source type
( $( $typ:path ),* $(,)? ) => {
$(
// // implement for values
// impl From<$typ> for Error {
// fn from(value: $typ) -> Self {
// Self::InvalidParameter(value.into())
// }
// }
// implement for references
impl From<&$typ> for Error {
fn from(value: &$typ) -> Self {
Self::InvalidParameter(value.clone().into())
}
}
)*
};
}
impl_error_from! {
sharry::Uri,
sharry::AliasID,
sharry::ShareID,
sharry::FileID,
}
#[allow(clippy::needless_pass_by_value)]
fn into_string(val: impl ToString) -> String {
val.to_string()
}
impl Error {
pub fn res_status_check<T>(actual: T, expected: T) -> Result<()>
where
T: PartialEq + fmt::Display + Copy,
{
if actual == expected {
Ok(())
} else {
Err(Self::Response(format!(
"unexpected status: {actual} (expected {expected})"
)))
}
}
pub fn response(e: impl ToString) -> Self {
Self::Response(into_string(e))
}
pub fn mismatch<T>(expected: impl ToString, actual: impl ToString) -> Result<T> {
Err(Self::Mismatch {
expected: into_string(expected),
actual: into_string(actual),
})
}
#[must_use]
pub fn is_stdio_kind(&self, kind: std::io::ErrorKind) -> bool {
if let Self::StdIo(e) = self {
e.kind() == kind
} else {
false
}
}
pub fn is_mismatch<E, A>(&self, want_expected: E, want_actual: A) -> bool
where
E: AsRef<str>,
A: AsRef<str>,
{
if let Self::Mismatch { expected, actual } = self {
expected == want_expected.as_ref() && actual == want_actual.as_ref()
} else {
false
}
}
#[must_use]
pub fn response_contains(&self, pat: &str) -> bool {
if let Self::Response(r) = self {
r.contains(pat)
} else {
false
}
}
#[must_use]
pub fn get_invalid_param(&self) -> Option<&Parameter> {
if let Self::InvalidParameter(p) = self {
Some(p)
} else {
None
}
}
#[must_use]
pub fn is_fatal(&self) -> bool {
match self {
Self::InvalidParameter(p) => p.is_fatal(),
Self::Mismatch { .. } | Self::Unknown(_) => true,
_ => false,
}
}
}
#[macro_export]
macro_rules! error_response {
// Match a format string plus optional arguments
($fmt:expr $(, $arg:expr )* $(,)?) => {
// Expand to constructing the Error::Response variant,
// wrapping a `format!(...)` call
Error::Response(format!($fmt $(, $arg )*))
};
}