#[cfg(doc)]
use crate::{Agent, Consumer, Producer};
use {
alloc::string::{String, ToString},
core::{
convert::TryFrom,
fmt::{self, Debug, Display, Formatter},
marker::PhantomData,
},
fehler::{throw, throws},
never::Never,
};
pub trait Flaws {
type Insufficiency;
type Defect;
}
pub trait Blame<T> {
fn blame(self) -> T;
}
pub trait TryBlame<T> {
type Error;
#[throws(Self::Error)]
fn try_blame(self) -> T;
}
#[non_exhaustive]
pub enum Fault<F>
where
F: Flaws,
{
Insufficiency(F::Insufficiency),
Defect(F::Defect),
}
impl<F> Fault<F>
where
F: Flaws,
{
fn is_defect(&self) -> bool {
matches!(*self, Self::Defect(_))
}
fn map_defect<M, W>(self, mut m: M) -> Fault<W>
where
M: FnMut(F::Defect) -> W::Defect,
W: Flaws<Insufficiency = F::Insufficiency>,
{
match self {
Self::Insufficiency(insufficiency) => Fault::Insufficiency(insufficiency),
Self::Defect(defect) => Fault::Defect(m(defect)),
}
}
}
impl<F, W> Blame<Fault<W>> for Fault<F>
where
F: Flaws,
W: Flaws,
W::Insufficiency: From<F::Insufficiency>,
W::Defect: From<F::Defect>,
{
fn blame(self) -> Fault<W> {
match self {
Fault::Insufficiency(insufficiency) => {
Fault::Insufficiency(W::Insufficiency::from(insufficiency))
}
Fault::Defect(defect) => Fault::Defect(W::Defect::from(defect)),
}
}
}
impl<F> Clone for Fault<F>
where
F: Flaws,
F::Insufficiency: Clone,
F::Defect: Clone,
{
fn clone(&self) -> Self {
match *self {
Self::Insufficiency(ref insufficiency) => Self::Insufficiency(insufficiency.clone()),
Self::Defect(ref defect) => Self::Defect(defect.clone()),
}
}
}
impl<F> Copy for Fault<F>
where
F: Flaws,
F::Insufficiency: Copy,
F::Defect: Copy,
{
}
impl<F> Debug for Fault<F>
where
F: Flaws,
F::Insufficiency: Debug,
F::Defect: Debug,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match *self {
Self::Insufficiency(ref insufficiency) => {
write!(f, "Fault::Insufficiency({:?})", insufficiency)
}
Self::Defect(ref defect) => write!(f, "Fault::Defect({:?})", defect),
}
}
}
impl<F> Display for Fault<F>
where
F: Flaws,
F::Insufficiency: Display,
F::Defect: Display,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match *self {
Self::Insufficiency(ref insufficiency) => write!(f, "insufficient {}", insufficiency),
Self::Defect(ref defect) => write!(f, "{}", defect),
}
}
}
impl<F> PartialEq for Fault<F>
where
F: Flaws,
F::Insufficiency: PartialEq,
F::Defect: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
match *self {
Fault::Insufficiency(ref insufficiency) => {
if let Fault::Insufficiency(ref other_insufficiency) = *other {
insufficiency == other_insufficiency
} else {
false
}
}
Fault::Defect(ref defect) => {
if let Fault::Defect(ref other_defect) = *other {
defect == other_defect
} else {
false
}
}
}
}
}
impl<F, W> TryBlame<Fault<W>> for Fault<F>
where
F: Flaws,
W: Flaws,
W::Insufficiency: TryFrom<F::Insufficiency>,
W::Defect: TryFrom<F::Defect>,
{
type Error = FaultConversionError<W, F>;
#[throws(Self::Error)]
fn try_blame(self) -> Fault<W> {
match self {
Fault::Insufficiency(insufficiency) => Fault::Insufficiency(
W::Insufficiency::try_from(insufficiency)
.map_err(FaultConversionError::Insufficiency)?,
),
Fault::Defect(defect) => {
Fault::Defect(W::Defect::try_from(defect).map_err(FaultConversionError::Defect)?)
}
}
}
}
pub struct Failure<F: Flaws> {
agent_description: String,
fault: Fault<F>,
}
impl<F> Failure<F>
where
F: Flaws,
{
pub(crate) fn new<A>(agent: &A, fault: Fault<F>) -> Self
where
A: Display,
{
Self {
agent_description: agent.to_string(),
fault,
}
}
pub fn is_defect(&self) -> bool {
self.fault.is_defect()
}
pub fn map_defect<M, W>(self, m: M) -> Failure<W>
where
M: FnMut(F::Defect) -> W::Defect,
W: Flaws<Insufficiency = F::Insufficiency>,
{
Failure {
agent_description: self.agent_description,
fault: self.fault.map_defect(m),
}
}
}
impl<F, W> Blame<Failure<W>> for Failure<F>
where
F: Flaws,
W: Flaws,
W::Insufficiency: From<F::Insufficiency>,
W::Defect: From<F::Defect>,
{
fn blame(self) -> Failure<W> {
Failure {
agent_description: self.agent_description,
fault: self.fault.blame(),
}
}
}
impl<F: Flaws> Debug for Failure<F>
where
F::Insufficiency: Debug,
F::Defect: Debug,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("Failure")
.field("agent_description", &self.agent_description)
.field("fault", &self.fault)
.finish()
}
}
impl<F: Flaws> Display for Failure<F>
where
F::Insufficiency: Display,
F::Defect: Display,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}: {}", self.agent_description, self.fault)
}
}
#[cfg(feature = "std")]
#[cfg_attr(feature = "unstable-doc-cfg", doc(cfg(feature = "std")))]
impl<F: Flaws> std::error::Error for Failure<F>
where
F::Insufficiency: Debug + Display,
F::Defect: Debug + Display,
{
}
impl<F: Flaws> PartialEq for Failure<F>
where
F::Insufficiency: PartialEq,
F::Defect: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.agent_description == other.agent_description && self.fault == other.fault
}
}
impl<F: Flaws, W: Flaws> TryBlame<Failure<W>> for Failure<F>
where
W::Insufficiency: TryFrom<F::Insufficiency>,
W::Defect: TryFrom<F::Defect>,
{
type Error = FailureConversionError<W, F>;
#[throws(Self::Error)]
fn try_blame(self) -> Failure<W> {
match self.fault.try_blame() {
Ok(fault) => Failure {
agent_description: self.agent_description,
fault,
},
Err(error) => throw!(FailureConversionError {
error,
agent_description: self.agent_description
}),
}
}
}
pub struct Recall<F: Flaws, G> {
good: G,
failure: Failure<F>,
}
impl<F: Flaws, G> Recall<F, G> {
pub(crate) fn new(failure: Failure<F>, good: G) -> Self {
Self { good, failure }
}
}
impl<F: Flaws, G, W: Flaws, T> Blame<Recall<W, T>> for Recall<F, G>
where
T: From<G>,
W::Insufficiency: From<F::Insufficiency>,
W::Defect: From<F::Defect>,
{
fn blame(self) -> Recall<W, T> {
Recall::new(self.failure.blame(), T::from(self.good))
}
}
impl<F: Flaws, G: Debug> Debug for Recall<F, G>
where
F::Insufficiency: Debug,
F::Defect: Debug,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("Recall")
.field("good", &self.good)
.field("failure", &self.failure)
.finish()
}
}
impl<F: Flaws, G> Display for Recall<F, G>
where
F::Insufficiency: Display,
F::Defect: Display,
G: Display,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "`{}` caused recall of good {}", self.failure, self.good)
}
}
#[cfg(feature = "std")]
#[cfg_attr(feature = "unstable-doc-cfg", doc(cfg(feature = "std")))]
impl<F: Flaws, G> std::error::Error for Recall<F, G>
where
F::Insufficiency: Debug + Display,
F::Defect: Debug + Display,
G: Debug + Display,
{
}
impl<F: Flaws, G> PartialEq for Recall<F, G>
where
F::Insufficiency: PartialEq,
F::Defect: PartialEq,
G: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.failure == other.failure && self.good == other.good
}
}
impl<F: Flaws, G, W: Flaws, T> TryBlame<Recall<W, T>> for Recall<F, G>
where
W::Insufficiency: TryFrom<F::Insufficiency>,
W::Defect: TryFrom<F::Defect>,
T: From<G>,
{
type Error = RecallConversionError<W, F, G>;
#[throws(Self::Error)]
fn try_blame(self) -> Recall<W, T> {
match self.failure.try_blame() {
Ok(failure) => Recall::new(failure, T::from(self.good)),
Err(error) => throw!(RecallConversionError {
error,
good: self.good,
}),
}
}
}
#[non_exhaustive]
pub enum Blockage<C, P, G>
where
C: Flaws,
P: Flaws,
{
Consumption(Failure<C>),
Production(Recall<P, G>),
}
impl<C, P, G> Debug for Blockage<C, P, G>
where
C: Flaws,
C::Insufficiency: Debug,
C::Defect: Debug,
P: Flaws,
P::Insufficiency: Debug,
P::Defect: Debug,
G: Debug,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match *self {
Self::Consumption(ref failure) => {
write!(f, "Blockage::Consumption({:?})", failure)
}
Self::Production(ref recall) => write!(f, "Blockage::Production({:?})", recall),
}
}
}
impl<C, P, G> From<Failure<C>> for Blockage<C, P, G>
where
C: Flaws,
P: Flaws,
{
fn from(failure: Failure<C>) -> Self {
Self::Consumption(failure)
}
}
impl<C, P, G> From<Recall<P, G>> for Blockage<C, P, G>
where
C: Flaws,
P: Flaws,
{
fn from(recall: Recall<P, G>) -> Self {
Self::Production(recall)
}
}
impl<C, P, G> PartialEq for Blockage<C, P, G>
where
C: Flaws,
C::Insufficiency: PartialEq,
C::Defect: PartialEq,
P: Flaws,
P::Insufficiency: PartialEq,
P::Defect: PartialEq,
G: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
match *self {
Self::Consumption(ref my_failure) => {
if let Blockage::Consumption(ref their_failure) = *other {
my_failure == their_failure
} else {
false
}
}
Self::Production(ref my_recall) => {
if let Blockage::Production(ref their_recall) = *other {
my_recall == their_recall
} else {
false
}
}
}
}
}
#[non_exhaustive]
pub enum FaultConversionError<F: Flaws, W: Flaws>
where
F::Insufficiency: TryFrom<W::Insufficiency>,
F::Defect: TryFrom<W::Defect>,
{
Insufficiency(<F::Insufficiency as TryFrom<W::Insufficiency>>::Error),
Defect(<F::Defect as TryFrom<W::Defect>>::Error),
}
impl<F: Flaws, W: Flaws> Debug for FaultConversionError<F, W>
where
F::Insufficiency: TryFrom<W::Insufficiency>,
<F::Insufficiency as TryFrom<W::Insufficiency>>::Error: Debug,
F::Defect: TryFrom<W::Defect>,
<F::Defect as TryFrom<W::Defect>>::Error: Debug,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match *self {
Self::Insufficiency(ref insufficiency_error) => {
write!(f, "FaultConversionError({:?})", insufficiency_error)
}
Self::Defect(ref defect_error) => write!(f, "FaultConversionError({:?})", defect_error),
}
}
}
impl<F: Flaws, W: Flaws> Display for FaultConversionError<F, W>
where
F::Insufficiency: TryFrom<W::Insufficiency>,
<F::Insufficiency as TryFrom<W::Insufficiency>>::Error: Display,
F::Defect: TryFrom<W::Defect>,
<F::Defect as TryFrom<W::Defect>>::Error: Display,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match *self {
Self::Insufficiency(ref insufficiency_error) => {
write!(f, "insufficiency conversion - {}", insufficiency_error)
}
Self::Defect(ref defect_error) => {
write!(f, "defect conversion - {}", defect_error)
}
}
}
}
#[cfg(feature = "std")]
#[cfg_attr(feature = "unstable-doc-cfg", doc(cfg(feature = "std")))]
impl<F: Flaws, W: Flaws> std::error::Error for FaultConversionError<F, W>
where
F::Insufficiency: TryFrom<W::Insufficiency>,
<F::Insufficiency as TryFrom<W::Insufficiency>>::Error: Debug + Display,
F::Defect: TryFrom<W::Defect>,
<F::Defect as TryFrom<W::Defect>>::Error: Debug + Display,
{
}
pub struct FailureConversionError<F: Flaws, W: Flaws>
where
F::Insufficiency: TryFrom<W::Insufficiency>,
F::Defect: TryFrom<W::Defect>,
{
error: FaultConversionError<F, W>,
agent_description: String,
}
impl<F: Flaws, W: Flaws> Debug for FailureConversionError<F, W>
where
F::Insufficiency: TryFrom<W::Insufficiency>,
<F::Insufficiency as TryFrom<W::Insufficiency>>::Error: Debug,
F::Defect: TryFrom<W::Defect>,
<F::Defect as TryFrom<W::Defect>>::Error: Debug,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("FailureConversionError")
.field("error", &self.error)
.field("agent_description", &self.agent_description)
.finish()
}
}
impl<F: Flaws, W: Flaws> Display for FailureConversionError<F, W>
where
F::Insufficiency: TryFrom<W::Insufficiency>,
<F::Insufficiency as TryFrom<W::Insufficiency>>::Error: Display,
F::Defect: TryFrom<W::Defect>,
<F::Defect as TryFrom<W::Defect>>::Error: Display,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "in `{}`: {}", self.agent_description, self.error)
}
}
#[cfg(feature = "std")]
#[cfg_attr(feature = "unstable-doc-cfg", doc(cfg(feature = "std")))]
impl<F: Flaws, W: Flaws> std::error::Error for FailureConversionError<F, W>
where
F::Insufficiency: TryFrom<W::Insufficiency>,
<F::Insufficiency as TryFrom<W::Insufficiency>>::Error: Debug + Display,
F::Defect: TryFrom<W::Defect>,
<F::Defect as TryFrom<W::Defect>>::Error: Debug + Display,
{
}
pub struct RecallConversionError<F: Flaws, W: Flaws, G>
where
F::Insufficiency: TryFrom<W::Insufficiency>,
F::Defect: TryFrom<W::Defect>,
{
error: FailureConversionError<F, W>,
good: G,
}
impl<F: Flaws, W: Flaws, G> RecallConversionError<F, W, G>
where
F::Insufficiency: TryFrom<W::Insufficiency>,
F::Defect: TryFrom<W::Defect>,
{
pub fn into_good(self) -> G {
self.good
}
}
impl<F: Flaws, W: Flaws, G: Debug> Debug for RecallConversionError<F, W, G>
where
F::Insufficiency: TryFrom<W::Insufficiency>,
<F::Insufficiency as TryFrom<W::Insufficiency>>::Error: Debug,
F::Defect: TryFrom<W::Defect>,
<F::Defect as TryFrom<W::Defect>>::Error: Debug,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("RecallConversionError")
.field("good", &self.good)
.field("error", &self.error)
.finish()
}
}
impl<F: Flaws, W: Flaws, G> Display for RecallConversionError<F, W, G>
where
F::Insufficiency: TryFrom<W::Insufficiency>,
<F::Insufficiency as TryFrom<W::Insufficiency>>::Error: Display,
F::Defect: TryFrom<W::Defect>,
<F::Defect as TryFrom<W::Defect>>::Error: Display,
G: Display,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(
f,
"{} while converting recall with good {}",
self.error, self.good
)
}
}
#[cfg(feature = "std")]
#[cfg_attr(feature = "unstable-doc-cfg", doc(cfg(feature = "std")))]
impl<F: Flaws, W: Flaws, G> std::error::Error for RecallConversionError<F, W, G>
where
F::Insufficiency: TryFrom<W::Insufficiency>,
<F::Insufficiency as TryFrom<W::Insufficiency>>::Error: Debug + Display,
F::Defect: TryFrom<W::Defect>,
<F::Defect as TryFrom<W::Defect>>::Error: Debug + Display,
G: Debug + Display,
{
}
pub type Flawless = Never;
#[derive(Clone, Copy, Debug, Default, PartialEq)]
#[non_exhaustive]
pub struct FullStock;
impl Display for FullStock {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "stock")
}
}
impl Flaws for FullStock {
type Insufficiency = Self;
type Defect = Flawless;
}
#[derive(Clone, Copy, Debug, Default, PartialEq)]
#[non_exhaustive]
pub struct EmptyStock;
impl Display for EmptyStock {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "goods")
}
}
impl Flaws for EmptyStock {
type Insufficiency = Self;
type Defect = Flawless;
}
#[derive(Debug)]
pub struct ProductionFlaws<D> {
defect: PhantomData<D>,
}
impl<D> Flaws for ProductionFlaws<D> {
type Insufficiency = FullStock;
type Defect = D;
}
#[derive(Debug)]
pub struct ConsumptionFlaws<D> {
defect: PhantomData<D>,
}
impl<D> Flaws for ConsumptionFlaws<D> {
type Insufficiency = EmptyStock;
type Defect = D;
}
impl Flaws for Flawless {
type Insufficiency = Self;
type Defect = Self;
}
impl TryFrom<EmptyStock> for Flawless {
type Error = ();
fn try_from(_: EmptyStock) -> Result<Self, Self::Error> {
Err(())
}
}
impl TryFrom<FullStock> for Flawless {
type Error = ();
fn try_from(_: FullStock) -> Result<Self, Self::Error> {
Err(())
}
}