use crate::{
iex_result::CallWithMarker,
imp::{IexResult, Marker},
Outcome,
};
use anyhow::{Error, Result};
use std::convert::Infallible;
use std::fmt::Display;
use std::marker::PhantomData;
pub trait Context<T, E> {
type ContextOutcome<C>: Outcome<Output = T, Error = Error>
where
Result<(), E>: anyhow::Context<(), E>,
C: Display + Send + Sync + 'static;
type WithContextOutcome<C, F>: Outcome<Output = T, Error = Error>
where
Result<(), E>: anyhow::Context<(), E>,
C: Display + Send + Sync + 'static,
F: FnOnce() -> C;
fn context<C>(self, context: C) -> Self::ContextOutcome<C>
where
Result<(), E>: anyhow::Context<(), E>,
C: Display + Send + Sync + 'static;
fn with_context<C, F>(self, f: F) -> Self::WithContextOutcome<C, F>
where
Result<(), E>: anyhow::Context<(), E>,
C: Display + Send + Sync + 'static,
F: FnOnce() -> C;
}
impl<T, E> Context<T, E> for Result<T, E> {
type ContextOutcome<C> = Result<T>
where
Result<(), E>: anyhow::Context<(), E>,
C: Display + Send + Sync + 'static;
type WithContextOutcome<C, F> = Result<T>
where
Result<(), E>: anyhow::Context<(), E>,
C: Display + Send + Sync + 'static,
F: FnOnce() -> C;
fn context<C>(self, context: C) -> Result<T>
where
Result<(), E>: anyhow::Context<(), E>,
C: Display + Send + Sync + 'static,
{
self.map_err(|e| anyhow::Context::context(Err(e), context).unwrap_err())
}
fn with_context<C, F>(self, f: F) -> Result<T>
where
Result<(), E>: anyhow::Context<(), E>,
C: Display + Send + Sync + 'static,
F: FnOnce() -> C,
{
self.map_err(|e| anyhow::Context::with_context(Err(e), f).unwrap_err())
}
}
impl<T, E, Func: CallWithMarker<T, E>> Context<T, E> for IexResult<T, E, Func> {
type ContextOutcome<C> = IexResult<T, Error, GenericContext<Self, C>>
where
Result<(), E>: anyhow::Context<(), E>,
C: Display + Send + Sync + 'static;
type WithContextOutcome<C, F> = IexResult<T, Error, GenericWithContext<Self, C, F>>
where
Result<(), E>: anyhow::Context<(), E>,
C: Display + Send + Sync + 'static,
F: FnOnce() -> C;
fn context<C>(self, context: C) -> Self::ContextOutcome<C>
where
Result<(), E>: anyhow::Context<(), E>,
C: Display + Send + Sync + 'static,
{
IexResult(
GenericContext {
outcome: self,
context,
},
PhantomData,
)
}
fn with_context<C, F>(self, f: F) -> Self::WithContextOutcome<C, F>
where
Result<(), E>: anyhow::Context<(), E>,
C: Display + Send + Sync + 'static,
F: FnOnce() -> C,
{
IexResult(GenericWithContext { outcome: self, f }, PhantomData)
}
}
pub struct GenericContext<R, C> {
outcome: R,
context: C,
}
impl<R: Outcome, C> CallWithMarker<R::Output, Error> for GenericContext<R, C>
where
Result<(), R::Error>: anyhow::Context<(), R::Error>,
C: Display + Send + Sync + 'static,
{
fn call_with_marker(self, marker: Marker<Error>) -> R::Output {
self.outcome
.map_err(|e| anyhow::Context::context(Err(e), self.context).unwrap_err())
.get_value_or_panic(marker)
}
}
pub struct GenericWithContext<R, C, F: FnOnce() -> C> {
outcome: R,
f: F,
}
impl<R: Outcome, C, F: FnOnce() -> C> CallWithMarker<R::Output, Error>
for GenericWithContext<R, C, F>
where
Result<(), R::Error>: anyhow::Context<(), R::Error>,
C: Display + Send + Sync + 'static,
{
fn call_with_marker(self, marker: Marker<Error>) -> R::Output {
self.outcome
.map_err(|e| anyhow::Context::context(Err(e), (self.f)()).unwrap_err())
.get_value_or_panic(marker)
}
}
impl<T> Context<T, Infallible> for Option<T> {
type ContextOutcome<C> = Result<T>
where
C: Display + Send + Sync + 'static;
type WithContextOutcome<C, F> = Result<T>
where
C: Display + Send + Sync + 'static,
F: FnOnce() -> C;
fn context<C>(self, context: C) -> Result<T>
where
C: Display + Send + Sync + 'static,
{
anyhow::Context::context(self, context)
}
fn with_context<C, F>(self, f: F) -> Result<T>
where
C: Display + Send + Sync + 'static,
F: FnOnce() -> C,
{
anyhow::Context::with_context(self, f)
}
}