pipecircuit 0.0.23

Correct. Robust. Fast. Portable. Pick four.
Documentation
/// The already-decided destinations of one semantic emission.
#[derive(Debug, Eq, PartialEq)]
#[must_use = "every destination must be conducted or explicitly settled"]
pub enum Route<Destination> {
    None,
    One(Destination),
    Two([Destination; 2]),
    Three([Destination; 3]),
    Four([Destination; 4]),
}
impl<Destination> Route<Destination> {
    pub fn map<Mapped>(self, mut map: impl FnMut(Destination) -> Mapped) -> Route<Mapped> {
        match self {
            Self::None => Route::None,
            Self::One(value) => Route::One(map(value)),
            Self::Two(values) => Route::Two(values.map(map)),
            Self::Three(values) => Route::Three(values.map(map)),
            Self::Four(values) => Route::Four(values.map(map)),
        }
    }
    pub fn discard(self) {}
    pub const fn none() -> Self {
        Self::None
    }
    pub const fn one(destination: Destination) -> Self {
        Self::One(destination)
    }
    pub fn fanout(destinations: impl Into<Self>) -> Self {
        destinations.into()
    }
    pub const fn len(&self) -> usize {
        match self {
            Self::None => 0,
            Self::One(_) => 1,
            Self::Two(_) => 2,
            Self::Three(_) => 3,
            Self::Four(_) => 4,
        }
    }
    pub const fn is_empty(&self) -> bool {
        matches!(self, Self::None)
    }
    pub fn into_single(self) -> Result<Destination, Self> {
        match self {
            Self::One(destination) => Ok(destination),
            other @ (Self::None | Self::Two(_) | Self::Three(_) | Self::Four(_)) => Err(other),
        }
    }
}
impl<Destination> From<(Destination, Destination)> for Route<Destination> {
    fn from((first, second): (Destination, Destination)) -> Self {
        Self::Two([first, second])
    }
}
impl<Destination> From<(Destination, Destination, Destination)> for Route<Destination> {
    fn from((first, second, third): (Destination, Destination, Destination)) -> Self {
        Self::Three([first, second, third])
    }
}
impl<Destination> From<(Destination, Destination, Destination, Destination)>
    for Route<Destination>
{
    fn from(
        (first, second, third, fourth): (Destination, Destination, Destination, Destination),
    ) -> Self {
        Self::Four([first, second, third, fourth])
    }
}

impl<Destination> From<(Destination, (Destination, Destination))> for Route<Destination> {
    fn from((first, (second, third)): (Destination, (Destination, Destination))) -> Self {
        Self::fanout((first, second, third))
    }
}
impl<Destination> From<((Destination, Destination), Destination)> for Route<Destination> {
    fn from(((first, second), third): ((Destination, Destination), Destination)) -> Self {
        Self::fanout((first, second, third))
    }
}
impl<Destination> From<((Destination, Destination), (Destination, Destination))>
    for Route<Destination>
{
    fn from(
        ((first, second), (third, fourth)): (
            (Destination, Destination),
            (Destination, Destination),
        ),
    ) -> Self {
        Self::fanout((first, second, third, fourth))
    }
}
impl<Destination> From<(Destination, (Destination, (Destination, Destination)))>
    for Route<Destination>
{
    fn from(
        (first, (second, (third, fourth))): (
            Destination,
            (Destination, (Destination, Destination)),
        ),
    ) -> Self {
        Self::fanout((first, second, third, fourth))
    }
}
impl<Destination> From<(((Destination, Destination), Destination), Destination)>
    for Route<Destination>
{
    fn from(
        (((first, second), third), fourth): (
            ((Destination, Destination), Destination),
            Destination,
        ),
    ) -> Self {
        Self::fanout((first, second, third, fourth))
    }
}
impl<Destination> From<((Destination, (Destination, Destination)), Destination)>
    for Route<Destination>
{
    fn from(
        ((first, (second, third)), fourth): (
            (Destination, (Destination, Destination)),
            Destination,
        ),
    ) -> Self {
        Self::fanout((first, second, third, fourth))
    }
}
impl<Destination> From<(Destination, ((Destination, Destination), Destination))>
    for Route<Destination>
{
    fn from(
        (first, ((second, third), fourth)): (
            Destination,
            ((Destination, Destination), Destination),
        ),
    ) -> Self {
        Self::fanout((first, second, third, fourth))
    }
}

/// Bounded siblings retained only within one synchronous conduction scope.
/// Capacity counts waiting destinations, excluding the active destination.
#[derive(Debug)]
pub struct PendingRoutes<Destination, const CAPACITY: usize> {
    slots: [Option<Destination>; CAPACITY],
    length: usize,
}
impl<Destination, const CAPACITY: usize> Default for PendingRoutes<Destination, CAPACITY> {
    fn default() -> Self {
        Self::new()
    }
}
impl<Destination, const CAPACITY: usize> PendingRoutes<Destination, CAPACITY> {
    pub fn discard(self) {}
    pub const fn new() -> Self {
        Self {
            slots: [const { None }; CAPACITY],
            length: 0,
        }
    }
    pub const fn len(&self) -> usize {
        self.length
    }
    pub const fn is_empty(&self) -> bool {
        self.length == 0
    }
    pub const fn capacity(&self) -> usize {
        CAPACITY
    }
    pub fn pop(&mut self) -> Option<Destination> {
        let index = self.length.checked_sub(1)?;
        self.slots.get_mut(index).and_then(|slot| {
            self.length = index;
            slot.take()
        })
    }
    pub fn admit(
        &mut self,
        route: Route<Destination>,
    ) -> Result<Option<Destination>, Route<Destination>> {
        let required = match &route {
            Route::None | Route::One(_) => 0,
            Route::Two(_) => 1,
            Route::Three(_) => 2,
            Route::Four(_) => 3,
        };
        let Some(new_length) = self
            .length
            .checked_add(required)
            .filter(|length| *length <= CAPACITY)
        else {
            return Err(route);
        };
        let (first, siblings) = match route {
            Route::None => return Ok(None),
            Route::One(destination) => return Ok(Some(destination)),
            Route::Two([first, second]) => (first, [Some(second), None, None]),
            Route::Three([first, second, third]) => (first, [Some(third), Some(second), None]),
            Route::Four([first, second, third, fourth]) => {
                (first, [Some(fourth), Some(third), Some(second)])
            }
        };
        for (slot, sibling) in self
            .slots
            .iter_mut()
            .skip(self.length)
            .zip(siblings.into_iter().flatten())
        {
            *slot = Some(sibling);
        }
        self.length = new_length;
        Ok(Some(first))
    }
}

/// Undispatched siblings remain in the caller's PendingRoutes on every exit.
/// A refused fanout is returned whole, before any of its children were sent.
#[derive(Eq, PartialEq)]
#[must_use = "settle the rejected route and retained siblings"]
pub enum FlowFailure<Failure, Destination> {
    Dispatch(Failure),
    Capacity {
        rejected: Route<Destination>,
        maximum_pending: usize,
    },
}
impl<Failure: core::fmt::Debug, Destination> core::fmt::Debug
    for FlowFailure<Failure, Destination>
{
    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        match self {
            Self::Dispatch(failure) => formatter.debug_tuple("Dispatch").field(failure).finish(),
            Self::Capacity {
                rejected,
                maximum_pending,
            } => formatter
                .debug_struct("Capacity")
                .field("destinations", &rejected.len())
                .field("maximum_pending", maximum_pending)
                .finish(),
        }
    }
}

#[cfg(test)]
mod tests;

#[cfg(kani)]
mod proofs;