1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
//! Traits for assembling and disassembling items.
use fehler::throws;

/// Describes a failure to assemble a composite from a sequence of parts.
#[derive(Debug, PartialEq)]
pub enum AssembleFailure<E> {
    /// There were not enough parts.
    Incomplete,
    /// There was an error with the parts.
    Error(E),
}

/// Converts an `E` into an `AssembleFailure`.
impl<E> From<E> for AssembleFailure<E> {
    #[inline]
    fn from(error: E) -> Self {
        Self::Error(error)
    }
}

/// Specifies the assembly of `Self` from a sequence of `P`s.
pub trait AssembleFrom<P>
where
    Self: Sized,
{
    /// Describes an error with the parts.
    ///
    /// This SHALL describe all cases that prevent a successful assembly other than the case where more parts are needed.
    type Error;

    /// Assembles `parts` into a `Self`.
    ///
    /// If assembly is successful, all items used in the assembly SHALL be removed from `parts`.
    ///
    /// # Errors
    ///
    /// If assembly fails, the cause of the failure SHALL be thrown and `parts` SHALL NOT be modified.
    #[throws(AssembleFailure<Self::Error>)]
    fn assemble_from(parts: &mut Vec<P>) -> Self;
}

/// Specifies the assembly of `C` from a sequence of `Self`s.
pub trait AssembleInto<C>
where
    Self: Sized,
{
    /// Describes an error with the parts.
    ///
    /// This SHALL describe all cases that prevent a successful assembly other than the case where more parts are needed.
    type Error;

    /// Assembles `parts` into a `C`.
    ///
    /// If assembly is successful, all items used in the assembly SHALL be removed from `parts`.
    ///
    /// # Errors
    ///
    /// If assembly fails, the cause of the failure SHALL be thrown and `parts` SHALL NOT be modified.
    #[throws(AssembleFailure<Self::Error>)]
    fn assemble_into(parts: &mut Vec<Self>) -> C;
}

/// For every `C` that implements `AssembleFrom<P>`, `P` SHALL implement `AssembleInto<S>`.
impl<P, C> AssembleInto<C> for P
where
    C: AssembleFrom<P>,
{
    type Error = <C as AssembleFrom<Self>>::Error;

    #[inline]
    #[throws(AssembleFailure<Self::Error>)]
    fn assemble_into(parts: &mut Vec<Self>) -> C {
        C::assemble_from(parts)?
    }
}

/// Disassembles a `C` into a sequence of `Self`s.
pub trait DisassembleFrom<C>
where
    Self: Sized,
{
    /// Describes an error that prevents disassembly.
    type Error;

    /// Disassembles `composite` into a sequence of `Self`s.
    ///
    /// # Errors
    ///
    /// If disassembly fails, the cause of the failure SHALL be thrown.
    #[throws(Self::Error)]
    fn disassemble_from(composite: C) -> Vec<Self>;
}

/// Disassembles `Self` into a sequence of `P`s.
pub trait DisassembleInto<P> {
    /// Describes an error that prevents disassembly.
    type Error;

    /// Disassembles `self` into a sequence of parts.
    ///
    /// # Errors
    ///
    /// If disassembly fails, the cause of the failure SHALL be thrown.
    #[throws(Self::Error)]
    fn disassemble_into(self) -> Vec<P>;
}

/// For every `P` that implements `DisassembleFrom<C>`, `C` SHALL implement `DisassembleInto<P>`.
impl<P, C> DisassembleInto<P> for C
where
    P: DisassembleFrom<C>,
{
    type Error = <P as DisassembleFrom<Self>>::Error;

    #[inline]
    #[throws(Self::Error)]
    fn disassemble_into(self) -> Vec<P> {
        P::disassemble_from(self)?
    }
}