generic_session_types/chan/
mod.rs

1use crate::*;
2use std::{future::Future, marker::PhantomData};
3
4pub trait RawChan {
5    type R;
6    type SendFuture<'a>: Future<Output = Result<(), Error>> + 'a
7    where
8        Self: 'a;
9    fn send(&mut self, r: Self::R) -> Self::SendFuture<'_>;
10
11    type RecvFuture<'a>: Future<Output = Result<Self::R, Error>>
12    where
13        Self: 'a;
14    fn recv(&mut self) -> Self::RecvFuture<'_>;
15
16    type CloseFuture: Future<Output = Result<(), Error>> + 'static;
17    fn close(self) -> Self::CloseFuture;
18}
19
20#[repr(transparent)]
21#[must_use]
22pub struct Chan<P: HasDual, E, C: RawChan>(C, PhantomData<(P, E)>);
23
24impl<P: HasDual, E, C: RawChan> Chan<P, E, C> {
25    pub fn from_raw(c: C) -> Self {
26        Self(c, PhantomData)
27    }
28    pub fn into_raw(self) -> C {
29        self.0
30    }
31}
32
33impl<P: HasDual, E, T, C: RawChan> Chan<Send<T, P>, E, C>
34where
35    C::R: Repr<T>,
36{
37    pub async fn send(self, t: T) -> Result<Chan<P, E, C>, Error> {
38        let mut c = self.0;
39        let r = <C::R as Repr<T>>::from(t);
40        c.send(r).await?;
41        let chan = Chan(c, PhantomData);
42        Ok(chan)
43    }
44}
45
46impl<P: HasDual, E, T, C: RawChan> Chan<Recv<T, P>, E, C>
47where
48    C::R: Repr<T>,
49{
50    pub async fn recv(self) -> Result<(T, Chan<P, E, C>), Error> {
51        let mut c = self.0;
52        let r = c.recv().await.map_err(|_| Error::RecvErr)?;
53        let t: T = repr::Repr::try_into(r).map_err(|_| Error::ConvertErr)?;
54        let chan = Chan(c, PhantomData);
55        Ok((t, chan))
56    }
57}
58
59impl<P: HasDual, Q: HasDual, E, C: RawChan> Chan<Choose<P, Q>, E, C>
60where
61    C::R: Repr<bool>,
62{
63    pub async fn left(self) -> Result<Chan<P, E, C>, Error> {
64        let mut c = self.0;
65        c.send(<C::R as Repr<bool>>::from(false)).await?;
66        Ok(Chan(c, PhantomData))
67    }
68    pub async fn right(self) -> Result<Chan<Q, E, C>, Error> {
69        let mut c = self.0;
70        c.send(<C::R as Repr<bool>>::from(true)).await?;
71        Ok(Chan(c, PhantomData))
72    }
73}
74
75pub enum Branch<L, R> {
76    Left(L),
77    Right(R),
78}
79
80impl<P: HasDual, Q: HasDual, E, C: RawChan> Chan<Offer<P, Q>, E, C>
81where
82    C::R: Repr<bool>,
83{
84    pub async fn offer(self) -> Result<Branch<Chan<P, E, C>, Chan<Q, E, C>>, Error> {
85        let mut c = self.0;
86        let r = c.recv().await.map_err(|_| Error::RecvErr)?;
87        let b = repr::Repr::try_into(r).map_err(|_| Error::ConvertErr)?;
88        match b {
89            false => Ok(Branch::Left(Chan(c, PhantomData))),
90            true => Ok(Branch::Right(Chan(c, PhantomData))),
91        }
92    }
93}
94
95impl<P: HasDual, E, C: RawChan> Chan<Rec<P>, E, C> {
96    pub fn rec(self) -> Chan<P, (P, E), C> {
97        Chan::from_raw(self.into_raw())
98    }
99}
100
101impl<P: HasDual, E, C: RawChan> Chan<Var<Z>, (P, E), C> {
102    pub fn zero(self) -> Chan<P, (P, E), C> {
103        Chan::from_raw(self.into_raw())
104    }
105}
106
107impl<P: HasDual, E, N, C: RawChan> Chan<Var<S<N>>, (P, E), C>
108where
109    Var<N>: HasDual,
110{
111    pub fn succ(self) -> Chan<Var<N>, E, C> {
112        Chan::from_raw(self.into_raw())
113    }
114}
115
116impl<C: RawChan, E> Chan<Close, E, C> {
117    pub async fn close(self) -> Result<(), Error> {
118        self.0.close().await
119    }
120}
121
122#[macro_export]
123macro_rules! send {
124    ( $c:ident, $msg:expr ) => {
125        let $c = $c.send($msg).await?;
126    };
127}
128
129#[macro_export]
130macro_rules! recv {
131    ( $c:ident, $msg:ident ) => {
132        let ($msg, $c) = $c.recv().await?;
133    };
134}
135
136#[macro_export]
137macro_rules! close {
138    ( $c:ident ) => {
139        $c.close().await?;
140    };
141}
142#[macro_export]
143macro_rules! choose_offer {
144    ( $choose:ident $offer:ident {
145        $($p:ident ( $t:ty ) $o:ident),+
146    } with $offerExt:ident) => {
147        struct $choose {
148        }
149
150        enum $offer {
151        }
152
153        impl HasDual for $choose { type Dual = $offer; }
154
155        impl HasDual for $offer { type Dual = $choose; }
156
157        choose_offer!($choose; 0; $($p($t)),*); // call def choose
158
159        choose_offer!($offer $offerExt; $($o < $t as HasDual>::Dual),*);
160    };
161
162    // def choose
163    ($choose:ident; $e:expr ; ) => {};
164    ($choose:ident; $e:expr ; $p:ident ($t:ty) $(, $ps:ident ($ts:ty) )* ) => {
165        async fn $p<E, C: RawChan>(chan: Chan< $choose, E, C>) -> Result< Chan< $t, E, C>, Error>
166        where
167            <C as $crate::RawChan>::R: $crate::Repr<u8>,
168        {
169            let mut c = chan.into_raw();
170            c.send(<C::R as Repr<u8>>::from($e)).await?;
171            Ok(Chan::from_raw(c))
172        }
173
174
175        choose_offer!($choose; $e + 1; $($ps ($ts)),* );
176    };
177
178    // def offer
179
180    (offer_body $ext:ident $t:ident $c:ident ; $e:expr ; ) => {
181            Err(Error::ConvertErr)
182    };
183    (offer_body $ext:ident $t:ident $c:ident ; $e:expr ; $p:ident $(, $ps:ident)* ) => {
184        if ($t == $e) {
185            Ok($ext::$p(Chan::from_raw($c)))
186        } else {
187            choose_offer!(offer_body $ext $t $c ; $e + 1 ; $( $ps ),*)
188        }
189    };
190
191    ($offer:ident $ext:ident; $($p:ident $t:ty),+) => {
192
193        pub enum $ext<E, C: RawChan> {
194            $( $p(Chan< $t, E, C>) ),*
195        }
196
197        impl<E, C: RawChan> OfferExt< $offer, E> for Chan< $offer, E, C>
198        where
199            C::R: Repr<u8>,
200        {
201            type C = C;
202            type OfferChan = $ext<E, Self::C>;
203
204            type OfferFuture = impl std::future::Future<Output = Result<Self::OfferChan, Error>> + 'static where Self:'static;
205            fn offer(self) -> Self::OfferFuture {
206                let mut c = self.into_raw();
207                async move {
208                    let r = c.recv().await.map_err(|_| Error::RecvErr)?;
209                    let t: u8 = Repr::try_into(r).map_err(|_| Error::ConvertErr)?;
210                    choose_offer!(offer_body $ext t c ; 0 ; $( $p ),* )
211                }
212            }
213        }
214    };
215}
216
217pub trait OfferExt<P: HasDual, E> {
218    type C: RawChan;
219    type OfferChan;
220    type OfferFuture: Future<Output = Result<Self::OfferChan, Error>> + 'static
221    where
222        Self: 'static;
223    fn offer(self) -> Self::OfferFuture;
224}
225
226pub mod mpsc;