pipecircuit 0.0.23

Correct. Robust. Fast. Portable. Pick four.
Documentation
use super::*;
use crate::{CircuitFlowOutcome, CircuitSendOutcome, Switchboard, flow};
use core::convert::Infallible;

struct Board;
impl Switchboard for Board {
    type From<'message> = u8;
    type To<'message> = u8;
    fn route<'message>(&mut self, emission: Self::From<'message>) -> Route<Self::To<'message>> {
        match emission {
            0 => Route::fanout((1, 2, 3)),
            4 => Route::fanout((5, 6)),
            7 => Route::one(8),
            _ => Route::none(),
        }
    }
}
#[test]
fn routes_have_exact_static_arity_and_single_extraction_preserves_rejection() {
    let none = Route::<u8>::none();
    assert!(none.is_empty());
    assert_eq!(none.len(), 0);
    assert_eq!(none.into_single(), Err(Route::None));
    assert_eq!(Route::one(1).into_single(), Ok(1));
    let two = Route::fanout((1, 2));
    assert_eq!(two.len(), 2);
    assert!(!two.is_empty());
    assert_eq!(two.into_single(), Err(Route::Two([1, 2])));
    assert_eq!(Route::fanout((1, 2, 3)).len(), 3);
    assert_eq!(Route::fanout((1, 2, 3, 4)).len(), 4);
    assert_eq!(
        Route::fanout((1, 2, 3)).into_single(),
        Err(Route::Three([1, 2, 3]))
    );
    assert_eq!(
        Route::fanout((1, 2, 3, 4)).into_single(),
        Err(Route::Four([1, 2, 3, 4]))
    );
}
#[test]
fn exact_capacity_admits_whole_fanout_and_drains_in_declared_order() {
    let mut pending = PendingRoutes::<_, 3>::default();
    assert_eq!(pending.capacity(), 3);
    assert_eq!(pending.admit(Route::fanout((1, 2, 3, 4))), Ok(Some(1)));
    assert_eq!(pending.len(), 3);
    assert!(!pending.is_empty());
    assert_eq!(pending.pop(), Some(2));
    assert_eq!(pending.pop(), Some(3));
    assert_eq!(pending.pop(), Some(4));
    assert_eq!(pending.pop(), None);
    assert_eq!(pending.len(), 0);
    assert!(pending.is_empty());
}
#[test]
fn nested_fanout_completes_each_immediate_chain_before_its_siblings()
-> Result<(), alloc::string::String> {
    let mut pending = PendingRoutes::<_, 3>::new();
    let mut trace = alloc::vec::Vec::new();
    let result = flow(&mut Board, 0, &mut pending, |destination| {
        trace.push(destination);
        Ok::<_, Infallible>(match destination {
            1 => CircuitSendOutcome::Immediate { from: 4 },
            5 => CircuitSendOutcome::Immediate { from: 7 },
            8 => CircuitSendOutcome::Immediate { from: 9 },
            _ => CircuitSendOutcome::<_, Infallible>::Submitted,
        })
    })
    .map_err(|failure| alloc::format!("{failure:?}"))?;
    assert_eq!(result, CircuitFlowOutcome::Submitted);
    assert_eq!(trace, [1, 5, 8, 6, 2, 3]);
    assert!(pending.is_empty());
    Ok(())
}
#[test]
fn capacity_refuses_new_children_without_losing_existing_siblings() -> Result<(), &'static str> {
    let mut pending = PendingRoutes::<_, 2>::new();
    let mut trace = alloc::vec::Vec::new();
    let result = flow(&mut Board, 0, &mut pending, |destination| {
        trace.push(destination);
        Ok::<_, Infallible>(CircuitSendOutcome::<_, Infallible>::Immediate { from: 4 })
    });
    let Err(FlowFailure::Capacity {
        rejected,
        maximum_pending,
    }) = result
    else {
        return Err("expected capacity refusal");
    };
    assert_eq!(rejected, Route::fanout((5, 6)));
    assert_eq!(maximum_pending, 2);
    assert_eq!(trace, [1]);
    assert_eq!(pending.pop(), Some(2));
    assert_eq!(pending.pop(), Some(3));
    assert!(pending.is_empty());
    Ok(())
}
#[test]
fn zero_capacity_still_conducts_single_destinations_and_finished_branches()
-> Result<(), alloc::string::String> {
    let mut pending = PendingRoutes::<_, 0>::new();
    let mut trace = alloc::vec::Vec::new();
    let outcome = flow(&mut Board, 7, &mut pending, |destination| {
        trace.push(destination);
        Ok::<_, Infallible>(CircuitSendOutcome::<_, Infallible>::Submitted)
    })
    .map_err(|failure| alloc::format!("{failure:?}"))?;
    assert_eq!(outcome, CircuitFlowOutcome::Submitted);
    assert_eq!(trace, [8]);
    let result = pending.admit(Route::fanout((1, 2)));
    assert_eq!(result, Err(Route::fanout((1, 2))));
    Ok(())
}
#[test]
fn dispatch_failure_and_termination_leave_unissued_siblings_owned_by_caller() {
    let mut pending = PendingRoutes::<_, 2>::new();
    let result = flow(&mut Board, 0, &mut pending, |destination| {
        Err::<CircuitSendOutcome<u8, ()>, _>(destination)
    });
    assert!(matches!(result, Err(FlowFailure::Dispatch(1))));
    assert_eq!(pending.pop(), Some(2));
    assert_eq!(pending.pop(), Some(3));
    let result = flow(&mut Board, 0, &mut pending, |destination| {
        Ok::<_, Infallible>(CircuitSendOutcome::Completed {
            completion: destination,
        })
    });
    assert!(matches!(
        result,
        Ok(CircuitFlowOutcome::Completed { completion: 1 })
    ));
    assert_eq!(pending.pop(), Some(2));
    assert_eq!(pending.pop(), Some(3));
}
#[test]
fn refusal_is_routed_before_a_healthy_sibling_without_replaying_accepted_work()
-> Result<(), alloc::string::String> {
    let mut pending = PendingRoutes::<_, 2>::new();
    let mut trace = alloc::vec::Vec::new();
    let result = flow(&mut Board, 0, &mut pending, |destination| {
        trace.push(destination);
        Ok::<_, Infallible>(match destination {
            1 => CircuitSendOutcome::Immediate { from: 7 },
            _ => CircuitSendOutcome::<_, Infallible>::Submitted,
        })
    })
    .map_err(|failure| alloc::format!("{failure:?}"))?;
    assert_eq!(result, CircuitFlowOutcome::Submitted);
    assert_eq!(trace, [1, 8, 2, 3]);
    Ok(())
}
#[test]
fn lending_and_non_send_destinations_need_no_copy_or_thread_capability()
-> Result<(), alloc::string::String> {
    struct Lending;
    impl Switchboard for Lending {
        type From<'message> = (&'message str, alloc::rc::Rc<()>);
        type To<'message> = (&'message str, Option<alloc::rc::Rc<()>>);
        fn route<'message>(
            &mut self,
            (text, owner): Self::From<'message>,
        ) -> Route<Self::To<'message>> {
            Route::fanout(((text, Some(owner)), (text, None)))
        }
    }
    let text = alloc::string::String::from("borrowed");
    let owner = alloc::rc::Rc::new(());
    let pointer = alloc::rc::Rc::as_ptr(&owner);
    let mut seen = alloc::vec::Vec::new();
    let mut pending = PendingRoutes::<_, 1>::new();
    let outcome = flow(
        &mut Lending,
        (&text, owner),
        &mut pending,
        |(borrowed, owner)| {
            assert_eq!(borrowed.as_ptr(), text.as_ptr());
            seen.push(owner.map(|owner| alloc::rc::Rc::as_ptr(&owner)));
            Ok::<_, Infallible>(CircuitSendOutcome::<_, Infallible>::Submitted)
        },
    )
    .map_err(|failure| alloc::format!("{failure:?}"))?;
    assert_eq!(outcome, CircuitFlowOutcome::Submitted);
    assert_eq!(seen, [Some(pointer), None]);
    Ok(())
}
#[test]
fn failure_debug_does_not_require_payload_debug_or_expose_credentials() {
    struct Secret;
    let failure = FlowFailure::<u8, _>::Capacity {
        rejected: Route::one(Secret),
        maximum_pending: 0,
    };
    assert_eq!(
        alloc::format!("{failure:?}"),
        "Capacity { destinations: 1, maximum_pending: 0 }"
    );
    assert_eq!(
        alloc::format!("{:?}", FlowFailure::<_, Secret>::Dispatch(4)),
        "Dispatch(4)"
    );
}

#[test]
fn arbitrary_bounded_routes_preserve_the_depth_first_stack_model()
-> Result<(), alloc::string::String> {
    use proptest::{prelude::*, test_runner::TestRunner};
    let mut runner = TestRunner::default();
    runner
        .run(
            &proptest::collection::vec((0_u8..=4, any::<u16>()), 0..100),
            |steps| {
                let mut pending = PendingRoutes::<_, 7>::new();
                let mut model = alloc::vec::Vec::new();
                for (width, value) in steps {
                    let children = [
                        value,
                        value.rotate_left(1),
                        value.rotate_left(2),
                        value.rotate_left(3),
                    ];
                    let route = match (width, children) {
                        (0, _) => Route::none(),
                        (1, [a, ..]) => Route::one(a),
                        (2, [a, b, ..]) => Route::fanout((a, b)),
                        (3, [a, b, c, ..]) => Route::fanout((a, b, c)),
                        (_, [a, b, c, d]) => Route::fanout((a, b, c, d)),
                    };
                    let siblings = width.checked_sub(1).map_or(0, usize::from);
                    let [a, b, c, d] = children;
                    if model
                        .iter()
                        .chain(core::iter::repeat_n(&value, siblings))
                        .count()
                        > 7
                    {
                        prop_assert_eq!(
                            pending.admit(route).map(|_| ()),
                            Err(match width {
                                2 => Route::fanout((a, b)),
                                3 => Route::fanout((a, b, c)),
                                _ => Route::fanout((a, b, c, d)),
                            })
                        );
                    } else {
                        let expected = if width == 0 { None } else { Some(value) };
                        prop_assert_eq!(pending.admit(route), Ok(expected));
                        model.extend(children.into_iter().take(usize::from(width)).skip(1).rev());
                    }
                    prop_assert_eq!(pending.len(), model.len());
                    prop_assert_eq!(pending.pop(), model.pop());
                }
                while let Some(expected) = model.pop() {
                    prop_assert_eq!(pending.pop(), Some(expected));
                }
                prop_assert!(pending.is_empty());
                Ok(())
            },
        )
        .map_err(|failure| alloc::format!("{failure}"))
}

#[test]
fn mapping_preserves_order_cardinality_and_owned_values() {
    for route in [
        Route::none(),
        Route::one(1),
        Route::fanout((1, 2)),
        Route::fanout((1, 2, 3)),
        Route::fanout((1, 2, 3, 4)),
    ] {
        let count = route.len();
        let mut seen = alloc::vec::Vec::new();
        let mapped = route.map(|value| {
            seen.push(value);
            alloc::boxed::Box::new(value)
        });
        assert_eq!(mapped.len(), count);
        assert_eq!(seen, (1..=count).collect::<alloc::vec::Vec<_>>());
        mapped.discard();
    }
    PendingRoutes::<u8, 0>::new().discard();
}

#[test]
fn nested_tuple_forms_keep_left_to_right_order_without_an_intermediate_container() {
    let three = Route::Three([1u8, 2, 3]);
    assert_eq!(Route::fanout((1, (2, 3))), three);
    assert_eq!(Route::fanout(((1, 2), 3)), three);
    let four = Route::Four([1u8, 2, 3, 4]);
    assert_eq!(Route::fanout(((1, 2), (3, 4))), four);
    assert_eq!(Route::fanout((1, (2, (3, 4)))), four);
    assert_eq!(Route::fanout((((1, 2), 3), 4)), four);
    assert_eq!(Route::fanout(((1, (2, 3)), 4)), four);
    assert_eq!(Route::fanout((1, ((2, 3), 4))), four);
}