Domani connects your domain to whatever you want to host on it, all with no account needed
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
domani/src/error/unexpected.rs

157 lines
4.3 KiB

use std::fmt::Write;
use std::{error, fmt, result};
#[derive(Debug, Clone, PartialEq)]
/// Error is a String which implements the Error trait. It is intended to be used in
/// situations where the caller is being given an error they can't really handle, except to pass it
/// along or log it.
///
/// The error is intended to also implement Send + Sync + Clone, such that it is easy to use in
/// async situations.
pub struct Error(String);
pub type Result<T> = result::Result<T, Error>;
impl Error {
fn from_displays<D1, D2, D3>(prefix: Option<D1>, body: &D2, source: Option<D3>) -> Error
where
D1: fmt::Display,
D2: fmt::Display + ?Sized,
D3: fmt::Display,
{
let mut w = String::new();
if let Some(prefix) = prefix {
write!(w, "{prefix}: ").expect("error writing prefix");
}
write!(w, "{body}").expect("error formatting body");
if let Some(source) = source {
write!(w, " [{source}]").expect("error formatting source");
}
Error(w.to_string())
}
fn from_err<E, D>(prefix: Option<D>, e: E) -> Error
where
E: error::Error,
D: fmt::Display,
{
return Error::from_displays(prefix, &e, e.source());
}
pub fn from<S>(s: S) -> Error
where
S: AsRef<str>,
{
Error::from_displays(None::<String>, s.as_ref(), None::<String>)
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl error::Error for Error {}
pub trait Mappable<T> {
/// or_unexpected returns an Err(Error) wrapping self's Err, or the Ok value of self.
fn or_unexpected(self) -> Result<T>;
/// or_unexpected_while is like or_unexpected, but will prefix the error message. The prefix
/// should be worded as if it started with the word "while", e.g.: `opening file {path}`.
fn or_unexpected_while<D: fmt::Display>(self, prefix: D) -> Result<T>;
/// map_unexpected_while is like or_unexpected_while, but uses a closure to produce the error
/// prefix.
fn map_unexpected_while<F, D>(self, f: F) -> Result<T>
where
F: FnOnce() -> D,
D: fmt::Display;
}
fn map_unexpected_maybe_while<T, E, F, D>(
res: result::Result<T, E>,
prefix_fn: Option<F>,
) -> Result<T>
where
E: error::Error,
F: FnOnce() -> D,
D: std::fmt::Display,
{
match res {
Ok(res) => Ok(res),
Err(err) => Err(Error::from_err(prefix_fn.map(|prefix_fn| prefix_fn()), err)),
}
}
impl<T, E: error::Error> Mappable<T> for result::Result<T, E> {
fn or_unexpected(self) -> Result<T> {
let no_fn = None::<Box<dyn FnOnce() -> Box<dyn fmt::Display>>>; // lol, good job rust
map_unexpected_maybe_while(self, no_fn)
}
fn or_unexpected_while<D: fmt::Display>(self, prefix: D) -> Result<T> {
map_unexpected_maybe_while(self, Some(|| prefix))
}
fn map_unexpected_while<F, D>(self, f: F) -> Result<T>
where
F: FnOnce() -> D,
D: fmt::Display,
{
map_unexpected_maybe_while(self, Some(f))
}
}
#[derive(thiserror::Error, Debug)]
enum OptionError {
#[error("required but not given")]
None,
}
impl<T> Mappable<T> for Option<T> {
fn or_unexpected(self) -> Result<T> {
self.ok_or(OptionError::None).or_unexpected()
}
fn or_unexpected_while<D: fmt::Display>(self, prefix: D) -> Result<T> {
self.ok_or(OptionError::None).or_unexpected_while(prefix)
}
fn map_unexpected_while<F, D>(self, f: F) -> Result<T>
where
F: FnOnce() -> D,
D: fmt::Display,
{
self.ok_or(OptionError::None).map_unexpected_while(f)
}
}
pub trait Intoable {
fn into_unexpected(self) -> Error;
/// into_unexpected_while is like to_unexpected, but will prefix the Error error. The
/// prefix should be worded as if it started with the word "while", e.g.: `opening file
/// {path}`.
fn into_unexpected_while<D>(self, prefix: D) -> Error
where
D: fmt::Display;
}
impl<E: error::Error> Intoable for E {
fn into_unexpected(self) -> Error {
Error::from_err(None::<String>, self)
}
fn into_unexpected_while<D>(self, prefix: D) -> Error
where
D: fmt::Display,
{
Error::from_err(Some(prefix), self)
}
}