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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
use super::*;
pub enum RaceResult<'a, I, O, A, B> {
Left {
value: A,
remaining: Coroutine<'a, I, O, B>,
},
Right {
value: B,
remaining: Coroutine<'a, I, O, A>,
},
}
pub fn race<'a, I, O, A, B>(
a: Coroutine<'a, I, O, A>,
b: Coroutine<'a, I, O, B>,
) -> Coroutine<'a, I, O, RaceResult<'a, I, O, A, B>>
where
I: Clone,
{
let sr1 = run_step(a);
let sr2 = run_step(b);
match (sr1, sr2) {
(StepResult::Done(value), StepResult::Done(b)) => {
let ret = RaceResult::Left {
value,
remaining: result(b),
};
result(ret)
}
(StepResult::Done(value), StepResult::Yield { output, next }) => {
let remaining = *next;
let race = RaceResult::Left { value, remaining };
right(send(output), result(race))
}
(StepResult::Done(value), StepResult::Next(next)) => {
let remaining = suspend(next);
result(RaceResult::Left { value, remaining })
}
(StepResult::Yield { output, next }, StepResult::Done(value)) => {
let remaining = *next;
let race = RaceResult::Right { value, remaining };
right(send(output), result(race))
}
(
StepResult::Yield {
output: a,
next: na,
},
StepResult::Yield {
output: b,
next: nb,
},
) => {
let send = tuple(send(a), send(b));
let next = race(*na, *nb);
right(send, next)
}
(StepResult::Yield { output, next: a }, StepResult::Next(b)) => {
let send = send(output);
let next = race(*a, suspend(b));
right(send, next)
}
(StepResult::Next(a), StepResult::Done(value)) => {
let remaining = suspend(a);
let race = RaceResult::Right { value, remaining };
result(race)
}
(StepResult::Next(a), StepResult::Yield { output, next }) => {
let send = send(output);
let a = suspend(a);
let b = *next;
let next = race(a, b);
right(send, next)
}
(StepResult::Next(a), StepResult::Next(b)) => {
let on_input = |input: I| {
let a = a(input.clone());
let b = b(input);
race(a, b)
};
bind(receive(), on_input)
}
}
}
pub fn broadcast<'a, I, O, A, B>(
first: Coroutine<'a, I, O, A>,
second: Coroutine<'a, I, O, B>,
) -> Coroutine<'a, I, O, (A, B)>
where
I: Clone,
{
let rr = race(first, second);
let on_result = |res| match res {
RaceResult::Left { value, remaining } => map(remaining, |b| (value, b)),
RaceResult::Right { value, remaining } => map(remaining, |a| (a, value)),
};
bind(rr, on_result)
}