Skip to main content

behavior/
mailbox.rs

1//! A minimal mailbox driver for complete user-lane behaviors.
2
3use communication::{Consumer, Received};
4use core::ops::ControlFlow;
5
6use crate::Exit;
7use crate::actor::{Address, BirthMode, Create};
8use crate::calculus::ActionReducer;
9use crate::calculus::Behavior;
10use crate::calculus::UserEvent;
11use crate::effects::SendAlgebra;
12use crate::next::Never;
13
14pub struct Transcript<A: Address, Sends, New> {
15    pub sends: Sends,
16    pub creates: Vec<Create<A, New>>,
17    pub exit: Exit<A>,
18}
19
20impl<A: Address, Sends, New> Transcript<A, Sends, New> {
21    #[must_use]
22    pub const fn new(sends: Sends, creates: Vec<Create<A, New>>, exit: Exit<A>) -> Self {
23        Self {
24            sends,
25            creates,
26            exit,
27        }
28    }
29}
30
31/// Drive user-lane messages through a complete behavior protocol.
32///
33/// # Errors
34/// Returns the first controlled behavior failure.
35pub async fn run<B, C, A, Sends, Br>(
36    mut behavior: B,
37    mut mailbox: Consumer<C, B::Msg>,
38    from: A,
39) -> Result<Transcript<A, Sends, Br::Child>, B::Error>
40where
41    A: Address,
42    Sends: SendAlgebra,
43    Br: BirthMode,
44    B: Behavior<Addr = A, Ph = Never, Sends = Sends, Birth = Br>,
45{
46    let mut fold = ActionReducer::new();
47    if let ControlFlow::Break(exit) = fold.push(behavior.init()?) {
48        let effects = fold.finish(Some(exit)).effects;
49        return Ok(Transcript::new(effects.sends, effects.creates, exit));
50    }
51    while let Some(received) = mailbox.recv().await {
52        let Received::User(message) = received else {
53            continue;
54        };
55        if let ControlFlow::Break(exit) =
56            fold.push(behavior.transition(B::Event::user(from, message))?)
57        {
58            let effects = fold.finish(Some(exit)).effects;
59            return Ok(Transcript::new(effects.sends, effects.creates, exit));
60        }
61    }
62    let effects = fold.finish(None).effects;
63    Ok(Transcript::new(
64        effects.sends,
65        effects.creates,
66        Exit::Collected,
67    ))
68}