shrupl/src/error.rs

167 lines
4 KiB
Rust
Raw Normal View History

use std::fmt;
2025-06-25 23:15:33 +00:00
use crate::sharry;
#[derive(Debug, thiserror::Error)]
pub enum Parameter {
#[error("given URI {0:?}")]
2025-07-01 15:20:07 +00:00
Uri(sharry::Uri),
#[error("given Alias ID {0:?}")]
2025-06-27 01:47:38 +00:00
AliasID(sharry::AliasID),
#[error("stored Share ID {0:?}")]
2025-06-27 01:47:38 +00:00
ShareID(sharry::ShareID),
2025-06-25 23:15:33 +00:00
#[error("stored {0:?}")]
FileID(sharry::FileID),
}
2025-07-01 15:20:07 +00:00
// 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 {
matches!(self, Self::Uri(_) | Self::AliasID(_))
}
}
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error(transparent)]
StdIo(#[from] std::io::Error),
2025-06-26 09:56:29 +00:00
#[error("Response error: {0}")]
Response(String),
#[error("Invalid {0}")]
InvalidParameter(Parameter),
2025-06-26 09:56:29 +00:00
#[error("Mismatch, expected {expected:?} but got {actual:?}")]
Mismatch { expected: String, actual: String },
#[error("Unknown error: {0}")]
Unknown(String),
}
2025-07-06 00:01:46 +00:00
pub type Result<T> = std::result::Result<T, Error>;
2025-07-01 15:20:07 +00:00
// a helper to generate all the `From<T> for Error` impls
macro_rules! impl_error_from {
// $typ: the source type
( $( $typ:path ),* $(,)? ) => {
2025-07-01 15:20:07 +00:00
$(
// // 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,
2025-07-01 15:20:07 +00:00
}
#[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))
}
2025-07-06 00:01:46 +00:00
pub fn mismatch<T>(expected: impl ToString, actual: impl ToString) -> Result<T> {
Err(Self::Mismatch {
2025-06-26 09:56:29 +00:00
expected: into_string(expected),
actual: into_string(actual),
2025-07-06 00:01:46 +00:00
})
}
2025-07-03 19:13:54 +00:00
pub fn is_mismatch<E, A>(&self, want_expected: E, want_actual: A) -> bool
where
2025-07-03 19:13:54 +00:00
E: AsRef<str>,
A: AsRef<str>,
{
matches!(
self,
Self::Mismatch { expected, actual }
2025-07-03 19:13:54 +00:00
if expected == want_expected.as_ref()
&& actual == want_actual.as_ref()
)
}
2025-07-01 15:24:26 +00:00
#[must_use]
2025-07-01 15:20:07 +00:00
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(),
2025-06-26 10:13:23 +00:00
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 )*))
};
}