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
//! This module contains the functions and macros
//! for receiving
//! a choice for binary sessions.

use crate::binary::cancel::cancel;
use crate::binary::recv::recv;
use crate::binary::struct_trait::{end::End, recv::Recv, session::Session};

use either::Either;

use std::error::Error;

/// Offer a choice between two sessions `S1` and `S1`.
/// Implemented using `Recv` and `Either`.
pub type Offer<S1, S2> = Recv<Either<S1, S2>, End>;

/// Offer a choice between two sessions `S1` and `S2`.
pub fn offer_either<'a, S1, S2, F, G, R>(
    s: Offer<S1, S2>,
    f: F,
    g: G,
) -> Result<R, Box<dyn Error + 'a>>
where
    S1: Session,
    S2: Session,
    F: FnOnce(S1) -> Result<R, Box<dyn Error + 'a>>,
    G: FnOnce(S2) -> Result<R, Box<dyn Error + 'a>>,
{
    let (e, s) = recv(s)?;
    cancel(s);
    e.either(f, g)
}

/// Offer a choice between many different sessions wrapped
/// in an `enum`
#[macro_export]
macro_rules! offer {
    ($session: expr, { $( $pat: pat => $result: expr , )+ }) => {
        (move || -> Result<_, _> {
            let (l, s) = mpstthree::binary::recv::recv($session)?;
            mpstthree::binary::cancel::cancel(s);
            match l {
                $(
                    $pat => $result,
                )+
                _ => panic!("Unexpected payload") ,
            }
        })()
    };
}