use core::cell::UnsafeCell;
use core::error::Error;
use core::fmt;
use core::marker::PhantomData;
use super::{ContextError, ErrorMarker};
mod sealed {
pub trait Sealed {}
impl Sealed for super::Ignore {}
impl<E> Sealed for super::Capture<E> {}
impl<E> Sealed for super::Emit<E> {}
}
pub trait ErrorMode<A>: self::sealed::Sealed {
#[doc(hidden)]
type Error;
#[doc(hidden)]
fn clear(&self);
#[doc(hidden)]
fn message<T>(&self, alloc: A, message: T) -> Self::Error
where
T: fmt::Display;
#[doc(hidden)]
fn custom<T>(&self, alloc: A, error: T) -> Self::Error
where
T: 'static + Send + Sync + Error;
}
#[non_exhaustive]
pub struct Ignore;
impl<A> ErrorMode<A> for Ignore {
type Error = ErrorMarker;
#[inline]
fn clear(&self) {}
#[inline]
fn message<T>(&self, alloc: A, message: T) -> Self::Error
where
T: fmt::Display,
{
_ = alloc;
_ = message;
ErrorMarker
}
#[inline]
fn custom<T>(&self, alloc: A, error: T) -> Self::Error
where
T: 'static + Send + Sync + Error,
{
_ = alloc;
_ = error;
ErrorMarker
}
}
pub struct Emit<E> {
_marker: PhantomData<E>,
}
impl<E> Emit<E> {
#[inline]
pub(super) fn new() -> Self {
Self {
_marker: PhantomData,
}
}
}
impl<E, A> ErrorMode<A> for Emit<E>
where
E: ContextError<A>,
{
type Error = E;
#[inline]
fn clear(&self) {}
#[inline]
fn message<T>(&self, alloc: A, message: T) -> Self::Error
where
T: fmt::Display,
{
E::message(alloc, message)
}
#[inline]
fn custom<T>(&self, alloc: A, error: T) -> Self::Error
where
T: 'static + Send + Sync + Error,
{
E::custom(alloc, error)
}
}
pub struct Capture<E> {
error: UnsafeCell<Option<E>>,
}
impl<E> Capture<E> {
#[inline]
pub(super) fn new() -> Self {
Self {
error: UnsafeCell::new(None),
}
}
}
impl<E> Capture<E> {
#[inline]
pub(super) fn unwrap(&self) -> E {
unsafe {
match (*self.error.get()).take() {
Some(error) => error,
None => panic!("no error captured"),
}
}
}
#[inline]
pub(super) fn result(&self) -> Result<(), E> {
unsafe {
match (*self.error.get()).take() {
Some(error) => Err(error),
None => Ok(()),
}
}
}
}
impl<E, A> ErrorMode<A> for Capture<E>
where
E: ContextError<A>,
{
type Error = ErrorMarker;
#[inline]
fn clear(&self) {
unsafe {
(*self.error.get()) = None;
}
}
#[inline]
fn message<T>(&self, alloc: A, message: T) -> Self::Error
where
T: fmt::Display,
{
unsafe {
(*self.error.get()) = Some(E::message(alloc, message));
}
ErrorMarker
}
#[inline]
fn custom<T>(&self, alloc: A, error: T) -> Self::Error
where
T: 'static + Send + Sync + Error,
{
unsafe {
(*self.error.get()) = Some(E::custom(alloc, error));
}
ErrorMarker
}
}