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
use ferrite_session::{
  either::*,
  prelude::*,
};

type Stream = Rec<
  ExternalChoice<
    Either<
      Rec<InternalChoice<Either<SendValue<String, Z>, S<Z>>>>,
      ReceiveValue<String, End>,
    >,
  >,
>;

fn producer() -> Session<Stream>
{
  fix_session(offer_choice! {
    Left =>
      fix_session(offer_case!(
        Left,
        send_value(
          "foo".to_string(),
          fix_session(offer_case!(
            Left,
            send_value(
              "bar".to_string(),
              fix_session(offer_case!(Right, producer()))
            )
          ))
        )))
    Right =>
      receive_value(| str | {
        println!("[producer] received string: {}", str);
        terminate()
      })
  })
}

fn consume_input() -> Session<
  ReceiveChannel<
    RecX<HList![Stream], InternalChoice<Either<SendValue<String, Z>, S<Z>>>>,
    End,
  >,
>
{
  receive_channel(|chan| {
    unfix_session(
      chan,
      case! { chan;
        Left =>
          receive_value_from(chan, move | val | {
            println!("[consumer] received value: {}", val);
            include_session(consume_input(), | consume |
              send_channel_to(consume, chan,
                wait(consume, terminate())))
          }),
        Right =>
          unfix_session(chan,
            choose!(chan, Right,
              send_value_to(chan,
                "hello".to_string(),
                wait(chan,
                  terminate()))))
      },
    )
  })
}

fn consumer() -> Session<ReceiveChannel<Stream, End>>
{
  include_session(consume_input(), |consume| {
    receive_channel(|chan| {
      unfix_session(
        chan,
        choose!(
          chan,
          Left,
          send_channel_to(consume, chan, wait(consume, terminate()))
        ),
      )
    })
  })
}

#[tokio::main]
pub async fn main()
{
  run_session(apply_channel(consumer(), producer())).await
}