ferrite_session/internal/session/
cut.rs

1use tokio::{
2  task,
3  try_join,
4};
5
6use crate::internal::{
7  base::{
8    unsafe_create_session,
9    unsafe_run_session,
10    AppendContext,
11    Context,
12    Empty,
13    PartialSession,
14    Protocol,
15    Slot,
16  },
17  functional::{
18    App,
19    Nat,
20  },
21};
22
23pub enum L {}
24
25pub enum R {}
26
27pub enum AllLeft {}
28
29pub enum AllRight {}
30
31pub trait SplitContext<C>
32where
33  C: Context,
34{
35  type Left: Context;
36
37  type Right: Context;
38
39  fn split_endpoints(
40    ctx: C::Endpoints
41  ) -> (
42    <Self::Left as Context>::Endpoints,
43    <Self::Right as Context>::Endpoints,
44  );
45}
46
47impl SplitContext<()> for ()
48{
49  type Left = ();
50  type Right = ();
51
52  fn split_endpoints(_: ()) -> ((), ())
53  {
54    ((), ())
55  }
56}
57
58impl<C> SplitContext<C> for AllLeft
59where
60  C: Context,
61{
62  type Left = C;
63  type Right = ();
64
65  fn split_endpoints(ctx: C::Endpoints) -> (C::Endpoints, ())
66  {
67    (ctx, ())
68  }
69}
70
71impl<C> SplitContext<C> for AllRight
72where
73  C: Context,
74{
75  type Left = ();
76  type Right = C;
77
78  fn split_endpoints(ctx: C::Endpoints) -> ((), C::Endpoints)
79  {
80    ((), ctx)
81  }
82}
83
84impl<X, C, C1, C2> SplitContext<(Empty, C)> for (Empty, X)
85where
86  C: Context,
87  C1: Context,
88  C2: Context,
89  X: SplitContext<C, Left = C1, Right = C2>,
90{
91  type Left = (Empty, C1);
92  type Right = (Empty, C2);
93
94  fn split_endpoints(
95    (a, ctx): ((), C::Endpoints)
96  ) -> (((), C1::Endpoints), ((), C2::Endpoints))
97  {
98    let (ctx1, ctx2) = X::split_endpoints(ctx);
99
100    ((a, ctx1), ((), ctx2))
101  }
102}
103
104impl<X, A, C, C1, C2> SplitContext<(A, C)> for (L, X)
105where
106  A: Slot,
107  C: Context,
108  C1: Context,
109  C2: Context,
110  X: SplitContext<C, Left = C1, Right = C2>,
111{
112  type Left = (A, C1);
113  type Right = (Empty, C2);
114
115  fn split_endpoints(
116    (a, ctx): (A::Endpoint, C::Endpoints)
117  ) -> ((A::Endpoint, C1::Endpoints), ((), C2::Endpoints))
118  {
119    let (ctx1, ctx2) = X::split_endpoints(ctx);
120
121    ((a, ctx1), ((), ctx2))
122  }
123}
124
125impl<X, A, C, C1, C2> SplitContext<(A, C)> for (R, X)
126where
127  A: Slot,
128  C: Context,
129  C1: Context,
130  C2: Context,
131  X: SplitContext<C, Left = C1, Right = C2>,
132{
133  type Left = (Empty, C1);
134  type Right = (A, C2);
135
136  fn split_endpoints(
137    (a, ctx): (A::Endpoint, C::Endpoints)
138  ) -> (((), C1::Endpoints), (A::Endpoint, C2::Endpoints))
139  {
140    let (ctx1, ctx2) = X::split_endpoints(ctx);
141
142    (((), ctx1), (a, ctx2))
143  }
144}
145
146pub trait Cut<C>: SplitContext<C>
147where
148  C: Context,
149{
150  fn cut<A, B>(
151    cont1: PartialSession<Self::Left, A>,
152    cont2: impl FnOnce(
153      <Self::Right as Context>::Length,
154    ) -> PartialSession<
155      <Self::Right as AppendContext<(A, ())>>::Appended,
156      B,
157    >,
158  ) -> PartialSession<C, B>
159  where
160    A: Protocol,
161    B: Protocol,
162    Self::Right: AppendContext<(A, ())>;
163}
164
165impl<X, C> Cut<C> for X
166where
167  C: Context,
168  X: SplitContext<C>,
169{
170  fn cut<A, B>(
171    cont1: PartialSession<Self::Left, A>,
172    cont2: impl FnOnce(
173      <Self::Right as Context>::Length,
174    ) -> PartialSession<
175      <Self::Right as AppendContext<(A, ())>>::Appended,
176      B,
177    >,
178  ) -> PartialSession<C, B>
179  where
180    A: Protocol,
181    B: Protocol,
182    Self::Right: AppendContext<(A, ())>,
183  {
184    cut::<X, _, _, _, _, _, _>(cont1, cont2)
185  }
186}
187
188pub fn cut<X, C, C1, C2, A, B, Func>(
189  cont1: PartialSession<C1, A>,
190  cont2: Func,
191) -> PartialSession<C, B>
192where
193  A: Protocol,
194  B: Protocol,
195  C: Context,
196  C1: Context,
197  C2: Context,
198  X: SplitContext<C, Left = C1, Right = C2>,
199  C2: AppendContext<(A, ())>,
200  Func: FnOnce(C2::Length) -> PartialSession<C2::Appended, B>,
201{
202  let cont3 = cont2(C2::Length::nat());
203
204  unsafe_create_session(move |ctx, sender1| async move {
205    let (ctx1, ctx2) = X::split_endpoints(ctx);
206
207    let (provider_end_a, client_end_a) = A::create_endpoints();
208
209    let ctx3 = C2::append_context(ctx2, (App::new(client_end_a), ()));
210
211    let child1 = task::spawn(async move {
212      unsafe_run_session(cont3, ctx3, sender1).await;
213    });
214
215    let child2 = task::spawn(async {
216      unsafe_run_session(cont1, ctx1, provider_end_a).await;
217    });
218
219    try_join!(child1, child2).unwrap();
220  })
221}
222
223/*
224 Cut (Communication)
225
226   cont1 :: Δ1, Q, Δ2 ⊢ P    cont2 :: Δ3 ⊢ Q
227 ==============================================
228      link(cont1, cont2) :: Δ1, Δ2, Δ3 ⊢ P
229*/
230
231pub fn cut_append<C1, C2, C3, C4, A, B>(
232  cont1: PartialSession<C3, B>,
233  cont2: PartialSession<C2, A>,
234) -> PartialSession<C4, B>
235where
236  A: Protocol,
237  B: Protocol,
238  C1: Context,
239  C2: Context,
240  C3: Context,
241  C4: Context,
242  C1: AppendContext<(A, ()), Appended = C3>,
243  C1: AppendContext<C2, Appended = C4>,
244{
245  unsafe_create_session(move |ctx1, b_sender| async move {
246    let (ctx2, ctx3) = <C1 as AppendContext<C2>>::split_context(ctx1);
247
248    let (provider_end_a, client_end_a) = A::create_endpoints();
249
250    let ctx4 = <C1 as AppendContext<(A, ())>>::append_context(
251      ctx2,
252      (App::new(client_end_a), ()),
253    );
254
255    let child1 = task::spawn(async {
256      unsafe_run_session(cont1, ctx4, b_sender).await;
257    });
258
259    let child2 = task::spawn(async {
260      unsafe_run_session(cont2, ctx3, provider_end_a).await;
261    });
262
263    try_join!(child1, child2).unwrap();
264  })
265}