2025-06-25 16:48:00 +00:00
|
|
|
|
use std::fmt;
|
|
|
|
|
|
|
2025-06-25 23:15:33 +00:00
|
|
|
|
use crate::sharry;
|
|
|
|
|
|
|
2025-06-25 16:48:00 +00:00
|
|
|
|
#[derive(Debug, thiserror::Error)]
|
|
|
|
|
|
pub enum Parameter {
|
|
|
|
|
|
#[error("given URI {0:?}")]
|
2025-07-01 15:20:07 +00:00
|
|
|
|
Uri(sharry::Uri),
|
2025-06-25 16:48:00 +00:00
|
|
|
|
|
|
|
|
|
|
#[error("given Alias ID {0:?}")]
|
2025-06-27 01:47:38 +00:00
|
|
|
|
AliasID(sharry::AliasID),
|
2025-06-25 16:48:00 +00:00
|
|
|
|
|
|
|
|
|
|
#[error("stored Share ID {0:?}")]
|
2025-06-27 01:47:38 +00:00
|
|
|
|
ShareID(sharry::ShareID),
|
2025-06-25 16:48:00 +00:00
|
|
|
|
|
2025-06-25 23:15:33 +00:00
|
|
|
|
#[error("stored {0:?}")]
|
|
|
|
|
|
FileID(sharry::FileID),
|
2025-06-25 16:48:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
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 enum‐variant 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,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-06-25 16:48:00 +00:00
|
|
|
|
impl Parameter {
|
|
|
|
|
|
fn is_fatal(&self) -> bool {
|
2025-07-15 14:54:27 +00:00
|
|
|
|
self.is_uri() || self.is_alias_id()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-15 14:55:29 +00:00
|
|
|
|
#[must_use]
|
2025-07-15 14:54:27 +00:00
|
|
|
|
pub fn is_uri(&self) -> bool {
|
|
|
|
|
|
matches!(self, Self::Uri(_))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-15 14:55:29 +00:00
|
|
|
|
#[must_use]
|
2025-07-15 14:54:27 +00:00
|
|
|
|
pub fn is_alias_id(&self) -> bool {
|
|
|
|
|
|
matches!(self, Self::AliasID(_))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-15 14:55:29 +00:00
|
|
|
|
#[must_use]
|
2025-07-15 14:54:27 +00:00
|
|
|
|
pub fn is_share_id(&self) -> bool {
|
|
|
|
|
|
matches!(self, Self::ShareID(_))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-15 14:55:29 +00:00
|
|
|
|
#[must_use]
|
2025-07-15 14:54:27 +00:00
|
|
|
|
pub fn is_file_id(&self) -> bool {
|
|
|
|
|
|
matches!(self, Self::FileID(_))
|
2025-06-25 16:48:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[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}")]
|
2025-06-25 16:48:00 +00:00
|
|
|
|
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 },
|
|
|
|
|
|
|
2025-06-25 16:48:00 +00:00
|
|
|
|
#[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 {
|
2025-07-01 18:51:49 +00:00
|
|
|
|
// $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! {
|
2025-07-01 18:51:49 +00:00
|
|
|
|
sharry::Uri,
|
|
|
|
|
|
sharry::AliasID,
|
|
|
|
|
|
sharry::ShareID,
|
|
|
|
|
|
sharry::FileID,
|
2025-07-01 15:20:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-06-25 16:48:00 +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-06-25 16:48:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-15 14:55:29 +00:00
|
|
|
|
#[must_use]
|
2025-07-15 14:54:27 +00:00
|
|
|
|
pub fn is_stdio_kind(&self, kind: std::io::ErrorKind) -> bool {
|
|
|
|
|
|
if let Self::StdIo(e) = self {
|
|
|
|
|
|
e.kind() == kind
|
|
|
|
|
|
} else {
|
|
|
|
|
|
false
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-03 19:13:54 +00:00
|
|
|
|
pub fn is_mismatch<E, A>(&self, want_expected: E, want_actual: A) -> bool
|
2025-07-03 17:20:56 +00:00
|
|
|
|
where
|
2025-07-03 19:13:54 +00:00
|
|
|
|
E: AsRef<str>,
|
|
|
|
|
|
A: AsRef<str>,
|
2025-07-03 17:20:56 +00:00
|
|
|
|
{
|
2025-07-15 14:54:27 +00:00
|
|
|
|
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
|
|
|
|
|
|
}
|
2025-07-03 17:20:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
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
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-06-25 16:48:00 +00:00
|
|
|
|
#[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,
|
2025-06-25 16:48:00 +00:00
|
|
|
|
_ => false,
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-07-08 21:41:38 +00:00
|
|
|
|
|
|
|
|
|
|
#[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 )*))
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|