From 637646eafcb988d1ecabf97c90524a7b21611648 Mon Sep 17 00:00:00 2001 From: Philip Munksgaard Date: Wed, 2 Sep 2015 11:29:31 -0700 Subject: [PATCH 1/6] start adding multiple offers and such This is an experiment that introduces arity specialized branching constructs. The idea is to add multiple specialized Offer/Choose constructs according to arity. That way, instead of chaining lots of Offer's and having to do `sel2().sel2().sel2()`, we'd simply have an `OfferN` with associated `sel1()`, `sel2()`, ..., and `selN()` methods. This commit only introduces Offer3 and Choose3 structs, but serves to give us an idea of how our library would end up looking. --- src/lib.rs | 135 +++++++++++++++++++++++++++-------------------------- 1 file changed, 68 insertions(+), 67 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 211e464..1831cda 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -69,7 +69,7 @@ use std::sync::mpsc::{Sender, Receiver, channel, Select}; use std::collections::HashMap; use std::marker::PhantomData; -pub use Branch::*; +pub use Branch2::*; /// A session typed channel. `P` is the protocol and `E` is the environment, /// containing potential recursion targets @@ -108,10 +108,12 @@ pub struct Recv ( PhantomData<(A, P)> ); pub struct Send ( PhantomData<(A, P)> ); /// Active choice between `P` and `Q` -pub struct Choose ( PhantomData<(P, Q)> ); +pub struct Choose2 ( PhantomData<(P, Q)> ); +pub struct Choose3 ( PhantomData<(P, Q, R)> ); /// Passive choice (offer) between `P` and `Q` -pub struct Offer ( PhantomData<(P, Q)> ); +pub struct Offer2 ( PhantomData<(P, Q)> ); +pub struct Offer3 ( PhantomData<(P, Q, R)> ); /// Enter a recursive environment pub struct Rec

( PhantomData

); @@ -136,12 +138,20 @@ unsafe impl HasDual for Recv { type Dual = Send; } -unsafe impl HasDual for Choose { - type Dual = Offer; +unsafe impl HasDual for Choose2 { + type Dual = Offer2; } -unsafe impl HasDual for Offer { - type Dual = Choose; +unsafe impl HasDual for Choose3 { + type Dual = Offer3; +} + +unsafe impl HasDual for Offer2 { + type Dual = Choose2; +} + +unsafe impl HasDual for Offer3 { + type Dual = Choose3; } unsafe impl HasDual for Var { @@ -156,9 +166,15 @@ unsafe impl HasDual for Rec

{ type Dual = Rec; } -pub enum Branch { - Left(L), - Right(R) +pub enum Branch2 { + B1(B1), + B2(B2), +} + +pub enum Branch3 { + B1(B1), + B2(B2), + B3(B3), } impl Chan { @@ -192,12 +208,12 @@ impl Chan> { } } -impl Chan> { +impl Chan> { /// Perform an active choice, selecting protocol `P`. #[must_use] pub fn sel1(self) -> Chan { unsafe { - write_chan(&self, true); + write_chan(&self, 1u8); transmute(self) } } @@ -206,82 +222,67 @@ impl Chan> { #[must_use] pub fn sel2(self) -> Chan { unsafe { - write_chan(&self, false); + write_chan(&self, 2u8); transmute(self) } } } -/// Convenience function. This is identical to `.sel2()` -impl Chan> { - #[must_use] - pub fn skip(self) -> Chan { - self.sel2() - } -} - -/// Convenience function. This is identical to `.sel2().sel2()` -impl Chan>> { - #[must_use] - pub fn skip2(self) -> Chan { - self.sel2().sel2() - } -} - -/// Convenience function. This is identical to `.sel2().sel2().sel2()` -impl Chan>>> { - #[must_use] - pub fn skip3(self) -> Chan { - self.sel2().sel2().sel2() - } -} - -/// Convenience function. This is identical to `.sel2().sel2().sel2().sel2()` -impl Chan>>>> { +impl Chan> { + /// Passive choice. This allows the other end of the channel to select one + /// of two options for continuing the protocol: either `P` or `Q`. #[must_use] - pub fn skip4(self) -> Chan { - self.sel2().sel2().sel2().sel2() + pub fn offer(self) -> Branch2, Chan> { + unsafe { + let b: u8 = read_chan(&self); + if b == 1u8 { + Branch2::B1(transmute(self)) + } else { + Branch2::B2(transmute(self)) + } + } } } -/// Convenience function. This is identical to `.sel2().sel2().sel2().sel2().sel2()` -impl Chan>>>>> { +impl Chan> { + /// Perform an active choice, selecting protocol `P`. #[must_use] - pub fn skip5(self) -> Chan { - self.sel2().sel2().sel2().sel2().sel2() + pub fn sel1(self) -> Chan { + unsafe { + write_chan(&self, 1u8); + transmute(self) + } } -} -/// Convenience function. -impl Chan>>>>>> { + /// Perform an active choice, selecting protocol `Q`. #[must_use] - pub fn skip6(self) -> Chan { - self.sel2().sel2().sel2().sel2().sel2().sel2() + pub fn sel2(self) -> Chan { + unsafe { + write_chan(&self, 2u8); + transmute(self) + } } -} -/// Convenience function. -impl Chan>>>>>>> { + /// Perform an active choice, selecting protocol `R`. #[must_use] - pub fn skip7(self) -> Chan { - self.sel2().sel2().sel2().sel2().sel2().sel2().sel2() + pub fn sel3(self) -> Chan { + unsafe { + write_chan(&self, 3u8); + transmute(self) + } } } -impl Chan> { +impl Chan> { /// Passive choice. This allows the other end of the channel to select one /// of two options for continuing the protocol: either `P` or `Q`. #[must_use] - pub fn offer(self) -> Branch, Chan> { + pub fn offer(self) -> Branch3, Chan, Chan> { unsafe { - let b = read_chan(&self); - if b { - Branch::Left(transmute(self)) - } else { - Branch::Right(transmute(self)) + match read_chan(&self) { + 1u8 => Branch3::B1(transmute(self)), + 2u8 => Branch3::B2(transmute(self)), + _ => Branch3::B3(transmute(self)) } } } @@ -389,7 +390,7 @@ impl<'c, T> ChanSelect<'c, T> { } pub fn add_offer_ret(&mut self, - chan: &'c Chan>, + chan: &'c Chan>, ret: T) { self.chans.push((unsafe { transmute(chan) }, ret)); @@ -442,7 +443,7 @@ impl<'c> ChanSelect<'c, usize> { } pub fn add_offer(&mut self, - c: &'c Chan>) + c: &'c Chan>) { let index = self.chans.len(); self.add_offer_ret(c, index); From 471dddcc2a71bbcade5052303aef157f74af7f95 Mon Sep 17 00:00:00 2001 From: Philip Munksgaard Date: Wed, 2 Sep 2015 11:38:35 -0700 Subject: [PATCH 2/6] Make the ATM example use Offer2 and Offer3 --- examples/atm.rs | 62 +++++++++++++++++++++---------------------------- 1 file changed, 27 insertions(+), 35 deletions(-) diff --git a/examples/atm.rs b/examples/atm.rs index 2c09bb5..0b5747e 100644 --- a/examples/atm.rs +++ b/examples/atm.rs @@ -3,16 +3,14 @@ use session_types::*; use std::thread::spawn; type Id = String; -type Atm = Recv, Eps>>; +type Atm = Recv, Eps>>; -type AtmInner = Offer>>; +type AtmInner = Offer3; type AtmDeposit = Recv>>; -type AtmWithdraw = Recv, Var>>; -type AtmBalance = Send>; +type AtmWithdraw = Recv, Var>>; type Client = ::Dual; @@ -30,59 +28,53 @@ fn atm(c: Chan<(), Atm>) { c.sel1().enter() }; let mut balance = 0; + loop { - c = offer! { - c, - Deposit => { + c = match c.offer() { + Branch3::B1(c) => { let (c, amt) = c.recv(); - balance += amt; - c.send(balance).zero() + balance = amt; + c.send(balance).zero() // c.send(new_bal): Chan<(AtmInner, ()) Var> }, - Withdraw => { + Branch3::B2(c) => { let (c, amt) = c.recv(); - if amt > balance { - c.sel2().zero() - } else { - balance -= amt; + if amt <= balance { + balance = balance - amt; c.sel1().zero() + } else { + c.sel2().zero() } }, - Balance => { - c.send(balance).zero() - }, - Quit => { - c.close(); - break - } - } + Branch3::B3(c) => { c.close(); break } + }; } } fn deposit_client(c: Chan<(), Client>) { let c = match c.send("Deposit Client".to_string()).offer() { - Left(c) => c.enter(), - Right(_) => panic!("deposit_client: expected to be approved") + B1(c) => c.enter(), + B2(_) => panic!("deposit_client: expected to be approved") }; let (c, new_balance) = c.sel1().send(200).recv(); println!("deposit_client: new balance: {}", new_balance); - c.zero().skip3().close(); + c.zero().sel3().close(); } fn withdraw_client(c: Chan<(), Client>) { let c = match c.send("Withdraw Client".to_string()).offer() { - Left(c) => c.enter(), - Right(_) => panic!("withdraw_client: expected to be approved") + B1(c) => c.enter(), + B2(_) => panic!("withdraw_client: expected to be approved") }; - match c.sel2().sel1().send(100).offer() { - Left(c) => { + match c.sel2().send(100).offer() { + B1(c) => { println!("withdraw_client: Successfully withdrew 100"); - c.zero().skip3().close(); + c.zero().sel3().close(); } - Right(c) => { + B2(c) => { println!("withdraw_client: Could not withdraw. Depositing instead."); - c.zero().sel1().send(50).recv().0.zero().skip3().close(); + c.zero().sel1().send(50).recv().0.zero().sel3().close(); } } } From c936af4bb047d72cc2fe18bb3fb70c5e2f9033ca Mon Sep 17 00:00:00 2001 From: Philip Munksgaard Date: Wed, 2 Sep 2015 12:30:13 -0700 Subject: [PATCH 3/6] Use tuples instead of explicit OfferNs Definitely prettier, but we still need the BranchN constructs. --- examples/atm.rs | 8 ++++---- src/lib.rs | 34 ++++++++++++++++------------------ 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/examples/atm.rs b/examples/atm.rs index 0b5747e..f62be83 100644 --- a/examples/atm.rs +++ b/examples/atm.rs @@ -3,14 +3,14 @@ use session_types::*; use std::thread::spawn; type Id = String; -type Atm = Recv, Eps>>; +type Atm = Recv, Eps)>>; -type AtmInner = Offer3; + Eps)>; type AtmDeposit = Recv>>; -type AtmWithdraw = Recv, Var>>; +type AtmWithdraw = Recv, Var)>>; type Client = ::Dual; diff --git a/src/lib.rs b/src/lib.rs index 1831cda..f300ded 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -108,12 +108,10 @@ pub struct Recv ( PhantomData<(A, P)> ); pub struct Send ( PhantomData<(A, P)> ); /// Active choice between `P` and `Q` -pub struct Choose2 ( PhantomData<(P, Q)> ); -pub struct Choose3 ( PhantomData<(P, Q, R)> ); +pub struct Choose ( PhantomData ); /// Passive choice (offer) between `P` and `Q` -pub struct Offer2 ( PhantomData<(P, Q)> ); -pub struct Offer3 ( PhantomData<(P, Q, R)> ); +pub struct Offer ( PhantomData ); /// Enter a recursive environment pub struct Rec

( PhantomData

); @@ -138,20 +136,20 @@ unsafe impl HasDual for Recv { type Dual = Send; } -unsafe impl HasDual for Choose2 { - type Dual = Offer2; +unsafe impl HasDual for Choose<(P, Q)> { + type Dual = Offer<(P::Dual, Q::Dual)>; } -unsafe impl HasDual for Choose3 { - type Dual = Offer3; +unsafe impl HasDual for Choose<(P, Q, R)> { + type Dual = Offer<(P::Dual, Q::Dual, R::Dual)>; } -unsafe impl HasDual for Offer2 { - type Dual = Choose2; +unsafe impl HasDual for Offer<(P, Q)> { + type Dual = Choose<(P::Dual, Q::Dual)>; } -unsafe impl HasDual for Offer3 { - type Dual = Choose3; +unsafe impl HasDual for Offer<(P, Q, R)> { + type Dual = Choose<(P::Dual, Q::Dual, R::Dual)>; } unsafe impl HasDual for Var { @@ -208,7 +206,7 @@ impl Chan> { } } -impl Chan> { +impl Chan> { /// Perform an active choice, selecting protocol `P`. #[must_use] pub fn sel1(self) -> Chan { @@ -228,7 +226,7 @@ impl Chan> { } } -impl Chan> { +impl Chan> { /// Passive choice. This allows the other end of the channel to select one /// of two options for continuing the protocol: either `P` or `Q`. #[must_use] @@ -244,7 +242,7 @@ impl Chan> { } } -impl Chan> { +impl Chan> { /// Perform an active choice, selecting protocol `P`. #[must_use] pub fn sel1(self) -> Chan { @@ -273,7 +271,7 @@ impl Chan> { } } -impl Chan> { +impl Chan> { /// Passive choice. This allows the other end of the channel to select one /// of two options for continuing the protocol: either `P` or `Q`. #[must_use] @@ -390,7 +388,7 @@ impl<'c, T> ChanSelect<'c, T> { } pub fn add_offer_ret(&mut self, - chan: &'c Chan>, + chan: &'c Chan>, ret: T) { self.chans.push((unsafe { transmute(chan) }, ret)); @@ -443,7 +441,7 @@ impl<'c> ChanSelect<'c, usize> { } pub fn add_offer(&mut self, - c: &'c Chan>) + c: &'c Chan>) { let index = self.chans.len(); self.add_offer_ret(c, index); From c1f4ebc52999c3df5910257674c4cc53a973cd1b Mon Sep 17 00:00:00 2001 From: Philip Munksgaard Date: Wed, 13 Jan 2016 19:30:38 +0100 Subject: [PATCH 4/6] Make all the tests and examples run. --- examples/arithmetic.rs | 96 ++++++------ examples/echo-server.rs | 10 +- examples/many-clients.rs | 6 +- examples/planeclip.rs | 16 +- src/lib.rs | 317 +++++++++++++++++++++++++++------------ 5 files changed, 283 insertions(+), 162 deletions(-) diff --git a/examples/arithmetic.rs b/examples/arithmetic.rs index 4e9bb19..4a8f602 100644 --- a/examples/arithmetic.rs +++ b/examples/arithmetic.rs @@ -9,30 +9,30 @@ use std::thread::spawn; // Offers: Add, Negate, Sqrt, Eval type Srv = - Offer>>>, - Offer>>, - Offer>, Var>>, - Recv bool, Recv>>>>>>>; + Offer<(Eps, + Recv>>>, + Recv>>, + Recv>, Var)>>, + Recv bool, Recv>>>)>; fn server(c: Chan<(), Rec>) { let mut c = c.enter(); loop { - c = offer!{ c, - CLOSE => { + c = match c.offer() { + Branch5::B1(c) => { c.close(); return }, - ADD => { + Branch5::B2(c) => { let (c, n) = c.recv(); let (c, m) = c.recv(); c.send(n + m).zero() }, - NEGATE => { + Branch5::B3(c) => { let (c, n) = c.recv(); c.send(-n).zero() }, - SQRT => { + Branch5::B4(c) => { let (c, x) = c.recv(); if x >= 0.0 { c.sel1().send(x.sqrt()).zero() @@ -40,7 +40,7 @@ fn server(c: Chan<(), Rec>) { c.sel2().zero() } }, - EVAL => { + Branch5::B5(c) => { let (c, f) = c.recv(); let (c, n) = c.recv(); c.send(f(n)).zero() @@ -53,43 +53,44 @@ fn server(c: Chan<(), Rec>) { // uses of session types, but they do showcase subtyping, recursion and how to // work the types in general. -type AddCli = - Choose>>>, R>>; +type AddCli = + Choose<(Eps, + Send>>>, + R, S, T)>; -fn add_client(c: Chan<(), Rec>>) { - let (c, n) = c.enter().sel2().sel1().send(42).send(1).recv(); +fn add_client(c: Chan<(), Rec>>) { + let (c, n) = c.enter().sel2().send(42).send(1).recv(); println!("{}", n); c.zero().sel1().close() } -type NegCli = - Choose>>, - S>>>; +type NegCli = + Choose<(Eps, + R, + Send>>, + S, T)>; -fn neg_client(c: Chan<(), Rec>>) { - let (c, n) = c.enter().skip2().sel1().send(42).recv(); +fn neg_client(c: Chan<(), Rec>>) { + let (c, n) = c.enter().sel3().send(42).recv(); println!("{}", n); c.zero().sel1().close(); } type SqrtCli = - Choose>, Var>>, - T>>>>; + Choose<(Eps, + R, + S, + Send>, Var)>>, + T)>; fn sqrt_client(c: Chan<(), Rec>>) { - match c.enter().skip3().sel1().send(42.0).offer() { - Left(c) => { + match c.enter().sel4().send(42.0).offer() { + B1(c) => { let (c, n) = c.recv(); println!("{}", n); c.zero().sel1().close(); } - Right(c) => { + B2(c) => { println!("Couldn't take square root!"); c.zero().sel1().close(); } @@ -99,11 +100,11 @@ fn sqrt_client(c: Chan<(), Rec>>) { // `fn_client` sends a function over the channel type PrimeCli = - Choose bool, Send>>>>>>>; + Choose<(Eps, + R, + S, + T, + Send bool, Send>>>)>; fn fn_client(c: Chan<(), Rec>>) { fn even(n: i64) -> bool { @@ -111,7 +112,7 @@ fn fn_client(c: Chan<(), Rec>>) { } let (c, b) = c.enter() - .skip4() + .sel5() .send(even) .send(42) .recv(); @@ -119,7 +120,6 @@ fn fn_client(c: Chan<(), Rec>>) { c.zero().sel1().close(); } - // `ask_neg` and `get_neg` use delegation, that is, sending a channel over // another channel. @@ -127,20 +127,22 @@ fn fn_client(c: Chan<(), Rec>>) { // sends the whole channel to `get_neg`. `get_neg` then receives the negated // integer and prints it. -type AskNeg = - Choose>>, - S>>>; +type AskNeg = + Choose<(Eps, + R, + Send>>, + S, T)>; -fn ask_neg(c1: Chan<(), Rec>>, - c2: Chan<(), Send, ()), Recv>>, Eps>>) { - let c1 = c1.enter().sel2().sel2().sel1().send(42); +fn ask_neg + (c1: Chan<(), Rec>>, + c2: Chan<(), Send, ()), Recv>>, Eps>>) { + let c1 = c1.enter().sel3().send(42); c2.send(c1).close(); } -fn get_neg(c1: Chan<(), Recv, ()), Recv>>, Eps>>) { +fn get_neg + (c1: Chan<(), Recv, ()), Recv>>, Eps>>) { let (c1, c2) = c1.recv(); let (c2, n) = c2.recv(); println!("{}", n); diff --git a/examples/echo-server.rs b/examples/echo-server.rs index 2596ad8..af3f1c1 100644 --- a/examples/echo-server.rs +++ b/examples/echo-server.rs @@ -8,19 +8,19 @@ use session_types::*; use std::thread::spawn; -type Srv = Offer>>; +type Srv = Offer<(Eps, Recv>)>; fn srv(c: Chan<(), Rec>) { let mut c = c.enter(); loop { - c = offer!{ c, - CLOSE => { + c = match c.offer() { + Branch2::B1(c) => { println!("Closing server."); c.close(); break }, - RECV => { + Branch2::B2(c) => { let (c, s) = c.recv(); println!("Received: {}", s); c.zero() @@ -32,7 +32,7 @@ fn srv(c: Chan<(), Rec>) { type Cli = ::Dual; fn cli(c: Chan<(), Rec>) { - let mut stdin = std::io::stdin(); + let stdin = std::io::stdin(); let mut count = 0usize; let mut c = c.enter(); diff --git a/examples/many-clients.rs b/examples/many-clients.rs index f8c79c6..a64c5ff 100644 --- a/examples/many-clients.rs +++ b/examples/many-clients.rs @@ -6,7 +6,7 @@ use std::sync::mpsc::{channel, Receiver}; use std::thread::spawn; use rand::random; -type Server = Recv, Eps>>; +type Server = Recv, Eps)>>; type Client = ::Dual; fn server_handler(c: Chan<(), Server>) { @@ -34,12 +34,12 @@ fn server(rx: Receiver>) { fn client_handler(c: Chan<(), Client>) { let n = random(); match c.send(n).offer() { - Left(c) => { + B1(c) => { let (c, n2) = c.recv(); c.close(); println!("{} + 42 = {}", n, n2); }, - Right(c) => { + B2(c) => { c.close(); println!("{} + 42 is an overflow :(", n); } diff --git a/examples/planeclip.rs b/examples/planeclip.rs index 1559a66..530e302 100644 --- a/examples/planeclip.rs +++ b/examples/planeclip.rs @@ -42,8 +42,8 @@ fn intersect(p1: Point, p2: Point, plane: Plane) -> Option { } } -type SendList = Rec>>>; -type RecvList = Rec>>>; +type SendList = Rec>)>>; +type RecvList = Rec>)>>; fn sendlist (c: Chan<(), SendList>, xs: Vec) @@ -63,11 +63,11 @@ fn recvlist let mut c = c.enter(); loop { c = match c.offer() { - Left(c) => { + B1(c) => { c.close(); break; } - Right(c) => { + B2(c) => { let (c, x) = c.recv(); v.push(x); c.zero() @@ -87,12 +87,12 @@ fn clipper(plane: Plane, let (pt0, mut pt); match ic.offer() { - Left(c) => { + B1(c) => { c.close(); oc.sel1().close(); return } - Right(c) => { + B2(c) => { let (c, ptz) = c.recv(); ic = c.zero(); pt0 = ptz; @@ -105,7 +105,7 @@ fn clipper(plane: Plane, oc = oc.sel2().send(pt).zero(); } ic = match ic.offer() { - Left(c) => { + B1(c) => { if let Some(pt) = intersect(pt, pt0, plane) { oc = oc.sel2().send(pt).zero(); } @@ -113,7 +113,7 @@ fn clipper(plane: Plane, oc.sel1().close(); break; } - Right(ic) => { + B2(ic) => { let (ic, pt2) = ic.recv(); if let Some(pt) = intersect(pt, pt2, plane) { oc = oc.sel2().send(pt).zero(); diff --git a/src/lib.rs b/src/lib.rs index f300ded..6d5723a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -110,7 +110,6 @@ pub struct Send ( PhantomData<(A, P)> ); /// Active choice between `P` and `Q` pub struct Choose ( PhantomData ); -/// Passive choice (offer) between `P` and `Q` pub struct Offer ( PhantomData ); /// Enter a recursive environment @@ -144,6 +143,15 @@ unsafe impl HasDual for Choose<(P, Q, R)> { type Dual = Offer<(P::Dual, Q::Dual, R::Dual)>; } + +unsafe impl HasDual for Choose<(P, Q, R, S)> { + type Dual = Offer<(P::Dual, Q::Dual, R::Dual, S::Dual)>; +} + +unsafe impl HasDual for Choose<(P, Q, R, S, T)> { + type Dual = Offer<(P::Dual, Q::Dual, R::Dual, S::Dual, T::Dual)>; +} + unsafe impl HasDual for Offer<(P, Q)> { type Dual = Choose<(P::Dual, Q::Dual)>; } @@ -152,6 +160,14 @@ unsafe impl HasDual for Offer<(P, Q, R)> { type Dual = Choose<(P::Dual, Q::Dual, R::Dual)>; } +unsafe impl HasDual for Offer<(P, Q, R, S)> { + type Dual = Choose<(P::Dual, Q::Dual, R::Dual, S::Dual)>; +} + +unsafe impl HasDual for Offer<(P, Q, R, S, T)> { + type Dual = Choose<(P::Dual, Q::Dual, R::Dual, S::Dual, T::Dual)>; +} + unsafe impl HasDual for Var { type Dual = Var; } @@ -164,6 +180,11 @@ unsafe impl HasDual for Rec

{ type Dual = Rec; } +// pub enum Branch { +// Left(B1), +// Right(B2), +// } + pub enum Branch2 { B1(B1), B2(B2), @@ -175,6 +196,21 @@ pub enum Branch3 { B3(B3), } +pub enum Branch4 { + B1(B1), + B2(B2), + B3(B3), + B4(B4), +} + +pub enum Branch5 { + B1(B1), + B2(B2), + B3(B3), + B4(B4), + B5(B5), +} + impl Chan { /// Close a channel. Should always be used at the end of your program. pub fn close(self) { @@ -226,23 +262,36 @@ impl Chan> { } } -impl Chan> { - /// Passive choice. This allows the other end of the channel to select one - /// of two options for continuing the protocol: either `P` or `Q`. +impl Chan> { + /// Perform an active choice, selecting protocol `P`. #[must_use] - pub fn offer(self) -> Branch2, Chan> { + pub fn sel1(self) -> Chan { unsafe { - let b: u8 = read_chan(&self); - if b == 1u8 { - Branch2::B1(transmute(self)) - } else { - Branch2::B2(transmute(self)) - } + write_chan(&self, 1u8); + transmute(self) + } + } + + /// Perform an active choice, selecting protocol `Q`. + #[must_use] + pub fn sel2(self) -> Chan { + unsafe { + write_chan(&self, 2u8); + transmute(self) + } + } + + /// Perform an active choice, selecting protocol `R`. + #[must_use] + pub fn sel3(self) -> Chan { + unsafe { + write_chan(&self, 3u8); + transmute(self) } } } -impl Chan> { +impl Chan> { /// Perform an active choice, selecting protocol `P`. #[must_use] pub fn sel1(self) -> Chan { @@ -269,6 +318,94 @@ impl Chan> { transmute(self) } } + + /// Perform an active choice, selecting protocol `R`. + #[must_use] + pub fn sel4(self) -> Chan { + unsafe { + write_chan(&self, 4u8); + transmute(self) + } + } +} + +impl Chan> { + /// Perform an active choice, selecting protocol `P`. + #[must_use] + pub fn sel1(self) -> Chan { + unsafe { + write_chan(&self, 1u8); + transmute(self) + } + } + + /// Perform an active choice, selecting protocol `Q`. + #[must_use] + pub fn sel2(self) -> Chan { + unsafe { + write_chan(&self, 2u8); + transmute(self) + } + } + + /// Perform an active choice, selecting protocol `R`. + #[must_use] + pub fn sel3(self) -> Chan { + unsafe { + write_chan(&self, 3u8); + transmute(self) + } + } + + /// Perform an active choice, selecting protocol `R`. + #[must_use] + pub fn sel4(self) -> Chan { + unsafe { + write_chan(&self, 4u8); + transmute(self) + } + } + + /// Perform an active choice, selecting protocol `R`. + #[must_use] + pub fn sel5(self) -> Chan { + unsafe { + write_chan(&self, 5u8); + transmute(self) + } + } +} + +// impl Chan> { +// /// Passive choice. This allows the other end of the channel to select one +// /// of two options for continuing the protocol: either `P` or `Q`. +// #[must_use] +// pub fn offer(self) -> Branch, Chan> { +// unsafe { +// let b: u8 = read_chan(&self); +// if b == 1u8 { +// Left(transmute(self)) +// } else { +// Right(transmute(self)) +// } +// } +// } +// } + +impl Chan> { + /// Passive choice. This allows the other end of the channel to select one + /// of two options for continuing the protocol: either `P` or `Q`. + #[must_use] + pub fn offer(self) -> Branch2, Chan> { + unsafe { + let b: u8 = read_chan(&self); + if b == 1u8 { + Branch2::B1(transmute(self)) + } else { + Branch2::B2(transmute(self)) + } + } + } } impl Chan> { @@ -286,6 +423,39 @@ impl Chan> { } } +impl Chan> { + /// Passive choice. This allows the other end of the channel to select one + /// of two options for continuing the protocol: either `P` or `Q`. + #[must_use] + pub fn offer(self) -> Branch4, Chan, Chan, Chan> { + unsafe { + match read_chan(&self) { + 1u8 => Branch4::B1(transmute(self)), + 2u8 => Branch4::B2(transmute(self)), + 3u8 => Branch4::B3(transmute(self)), + _ => Branch4::B4(transmute(self)) + } + } + } +} + +impl Chan> { + /// Passive choice. This allows the other end of the channel to select one + /// of two options for continuing the protocol: either `P` or `Q`. + #[must_use] + pub fn offer(self) -> Branch5, Chan, Chan, Chan, Chan> { + unsafe { + match read_chan(&self) { + 1u8 => Branch5::B1(transmute(self)), + 2u8 => Branch5::B2(transmute(self)), + 3u8 => Branch5::B3(transmute(self)), + 4u8 => Branch5::B4(transmute(self)), + _ => Branch5::B5(transmute(self)) + } + } + } +} + impl Chan> { /// Enter a recursive environment, putting the current environment on the /// top of the environment stack. @@ -487,23 +657,23 @@ pub fn connect(srv: F1, cli: F2) /// use session_types::*; /// use std::thread::spawn; /// -/// fn srv(c: Chan<(), Offer, Offer, Eps>>>) { -/// offer! { c, -/// Number => { +/// fn srv(c: Chan<(), Offer<(Recv, Recv, Eps)>>) { +/// match c.offer() { +/// Branch3::B1(c) => { /// let (c, n) = c.recv(); /// assert_eq!(42, n); /// c.close(); /// }, -/// String => { +/// Branch3::B2(c) => { /// c.recv().0.close(); /// }, -/// Quit => { +/// Branch3::B3(c) => { /// c.close(); /// } /// } /// } /// -/// fn cli(c: Chan<(), Choose, Choose, Eps>>>) { +/// fn cli(c: Chan<(), Choose<(Send, Send, Eps)>>) { /// c.sel1().send(42).close(); /// } /// @@ -516,24 +686,24 @@ pub fn connect(srv: F1, cli: F2) /// /// The identifiers on the left-hand side of the arrows have no semantic /// meaning, they only provide a meaningful name for the reader. -#[macro_export] -macro_rules! offer { - ( - $id:ident, $branch:ident => $code:expr, $($t:tt)+ - ) => ( - match $id.offer() { - Branch::Left($id) => $code, - Branch::Right($id) => offer!{ $id, $($t)+ } - } - ); - ( - $id:ident, $branch:ident => $code:expr - ) => ( - $code - ) -} - -/// This macro plays the same role as the `select!` macro does for `Receiver`s. +// #[macro_export] +// macro_rules! offer { +// ( +// $id:ident, $branch:ident => $code:expr, $($t:tt)+ +// ) => ( +// match $id.offer() { +// Branch2::B1($id) => $code, +// Branch2::B2($id) => offer!{ $id, $($t)+ } +// } +// ); +// ( +// $id:ident, $branch:ident => $code:expr +// ) => ( +// $code +// ) +// } + +/// this macro plays the same role as the `select!` macro does for `Receiver`s. /// /// It also supports a second form with `Offer`s (see the example below). /// @@ -576,57 +746,6 @@ macro_rules! offer { /// } /// } /// ``` -/// -/// ```rust -/// #![feature(rand)] -/// #[macro_use] -/// extern crate session_types; -/// extern crate rand; -/// -/// use std::thread::spawn; -/// use session_types::*; -/// -/// type Igo = Choose, Send>; -/// type Ugo = Offer, Recv>; -/// -/// fn srv(chan_one: Chan<(), Ugo>, chan_two: Chan<(), Ugo>) { -/// let _ign; -/// chan_select! { -/// _ign = chan_one.offer() => { -/// String => { -/// let (c, s) = chan_one.recv(); -/// assert_eq!("Hello, World!".to_string(), s); -/// c.close(); -/// }, -/// Number => { -/// unreachable!() -/// } -/// }, -/// _ign = chan_two.offer() => { -/// String => { -/// unreachable!() -/// }, -/// Number => { -/// unreachable!() -/// } -/// } -/// } -/// } -/// -/// fn cli(c: Chan<(), Igo>) { -/// c.sel1().send("Hello, World!".to_string()).close(); -/// } -/// -/// fn main() { -/// let (ca1, ca2) = session_channel(); -/// let (cb1, cb2) = session_channel(); -/// -/// spawn(move|| cli(ca2)); -/// -/// srv(ca1, cb1); -/// } -/// ``` - #[macro_export] macro_rules! chan_select { @@ -644,16 +763,16 @@ macro_rules! chan_select { { unreachable!() } }); - ( - $($res:ident = $rx:ident.offer() => { $($t:tt)+ }),+ - ) => ({ - let index = { - let mut sel = $crate::ChanSelect::new(); - $( sel.add_offer(&$rx); )+ - sel.wait() - }; - let mut i = 0; - $( if index == { i += 1; i - 1 } { $res = offer!{ $rx, $($t)+ } } else )+ - { unreachable!() } - }) + // ( + // $($res:ident = $rx:ident.offer() => { $($t:tt)+ }),+ + // ) => ({ + // let index = { + // let mut sel = $crate::ChanSelect::new(); + // $( sel.add_offer(&$rx); )+ + // sel.wait() + // }; + // let mut i = 0; + // $( if index == { i += 1; i - 1 } { $res = offer!{ $rx, $($t)+ } } else )+ + // { unreachable!() } + // }) } From 8c60f064013c1d443947d25e3b474741dcd1346a Mon Sep 17 00:00:00 2001 From: Philip Munksgaard Date: Wed, 13 Jan 2016 23:30:35 +0100 Subject: [PATCH 5/6] Use macros to declare branch constructs --- Cargo.toml | 3 + src/branch_impls/Cargo.toml | 9 + src/branch_impls/src/lib.rs | 139 +++++++++++++++ src/lib.rs | 342 +----------------------------------- 4 files changed, 156 insertions(+), 337 deletions(-) create mode 100644 src/branch_impls/Cargo.toml create mode 100644 src/branch_impls/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index e3a6fb1..07c55a7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,3 +21,6 @@ chan_select = ["compiletest_rs"] [dependencies] compiletest_rs = { version = "*", optional = true } + +[dependencies.branch_impls] +path = "src/branch_impls" \ No newline at end of file diff --git a/src/branch_impls/Cargo.toml b/src/branch_impls/Cargo.toml new file mode 100644 index 0000000..8ec3ac4 --- /dev/null +++ b/src/branch_impls/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "branch_impls" +version = "0.1.0" +authors = [ "Philip Munksgaard " + ] + + +[lib] +plugin = true \ No newline at end of file diff --git a/src/branch_impls/src/lib.rs b/src/branch_impls/src/lib.rs new file mode 100644 index 0000000..291f2a7 --- /dev/null +++ b/src/branch_impls/src/lib.rs @@ -0,0 +1,139 @@ +#![crate_type="dylib"] +#![feature(plugin_registrar, rustc_private)] + +extern crate syntax; +extern crate rustc; +extern crate rustc_plugin; + +use syntax::codemap::Span; +use syntax::ptr::P; +use syntax::ast::{TokenTree, Item}; +use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager}; +use syntax::ext::quote::rt::ExtParseUtils; +use syntax::util::small_vector::SmallVector; +use syntax::ast::Lit_; +use rustc_plugin::Registry; + +fn commalist(n: u8, before: &str, after: &str) -> String { + let mut buf = "".to_string(); + for i in 1..n { + buf.push_str(&format!("{}B{}{}, ", before, i, after)); + } + buf.push_str(&format!("{}B{}{}", before, n, after)); + + return buf; +} + +fn branch_struct(n: u8) -> String { + let mut buf = format!("pub enum Branch{}<", n); + buf.push_str(&commalist(n, "", "")); + buf.push_str("> { "); + for i in 1..n+1 { + buf.push_str(&format!("B{}(B{}), ", i, i)); + } + + buf.push_str(" }"); + + return buf; +} + +fn hasdual_choose_impl(n: u8) -> String { + let mut buf = "unsafe impl <".to_string(); + buf.push_str(&commalist(n, "", ": HasDual")); + buf.push_str("> HasDual for Choose<("); + buf.push_str(&commalist(n, "", "")); + buf.push_str(")> { type Dual = Offer<("); + buf.push_str(&commalist(n, "", "::Dual")); + buf.push_str(")>; }"); + + return buf; +} + +fn hasdual_offer_impl(n: u8) -> String { + let mut buf = "unsafe impl <".to_string(); + buf.push_str(&commalist(n, "", ": HasDual")); + buf.push_str("> HasDual for Offer<("); + buf.push_str(&commalist(n, "", "")); + buf.push_str(")> { type Dual = Choose<("); + buf.push_str(&commalist(n, "", "::Dual")); + buf.push_str(")>; }"); + + return buf; +} + +fn choose_impl(n: u8) -> String { + let mut buf = "impl Chan> { "); + + for i in 1..n+1 { + buf.push_str("#[must_use] "); + buf.push_str(&format!("pub fn sel{}(self) -> Chan {{ ", i, i)); + buf.push_str(&format!("unsafe {{ write_chan(&self, {}); transmute(self) }} }} ", i)); + } + + buf.push_str("}"); + + return buf; +} + +fn offer_impl(n: u8) -> String { + let mut buf = "impl Chan> {{ #[must_use] pub fn offer(self) -> Branch{}<", n)); + buf.push_str(&commalist(n, "Chan")); + buf.push_str("> { unsafe { match read_chan(&self) { "); + + for i in 1..(n+1) { + buf.push_str(&format!("{}u8 => Branch{}::B{}(transmute(self)), ", i, n, i)); + } + + buf.push_str("_ => unreachable!() "); + buf.push_str("} } } }"); + + return buf; +} + +fn impl_branch(cx: &mut ExtCtxt, n: u8) -> SmallVector> { + let mut v = SmallVector::zero(); + + v.push(cx.parse_item(branch_struct(n))); + v.push(cx.parse_item(hasdual_choose_impl(n))); + v.push(cx.parse_item(hasdual_offer_impl(n))); + v.push(cx.parse_item(offer_impl(n))); + v.push(cx.parse_item(choose_impl(n))); + + return v; +} + +fn branch_impls(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box { + let mut parser = cx.new_parser_from_tts(tts); + let n = match parser.parse_lit() { + Ok(lit) => match lit.node { + Lit_::LitInt(n, _) => n, + _ => { + cx.span_err(lit.span, "Expected literal integer"); + return DummyResult::any(sp); + } + }, + Err(mut e) => { + e.emit(); + return DummyResult::any(sp); + } + } as u8; + + let mut v = SmallVector::zero(); + + for i in 2..n+1 { + v.push_all(impl_branch(cx, i)); + } + + return MacEager::items(v); +} +#[plugin_registrar] +pub fn plugin_registrar(reg: &mut Registry) { + reg.register_macro("branch_impls", branch_impls);} diff --git a/src/lib.rs b/src/lib.rs index d880d0a..2966e9d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -62,6 +62,9 @@ #![cfg_attr(feature = "chan_select", feature(mpsc_select))] +#![feature(plugin)] +#![plugin(branch_impls)] + use std::marker; use std::thread::spawn; use std::mem::transmute; @@ -139,39 +142,6 @@ unsafe impl HasDual for Recv { type Dual = Send; } -unsafe impl HasDual for Choose<(P, Q)> { - type Dual = Offer<(P::Dual, Q::Dual)>; -} - -unsafe impl HasDual for Choose<(P, Q, R)> { - type Dual = Offer<(P::Dual, Q::Dual, R::Dual)>; -} - - -unsafe impl HasDual for Choose<(P, Q, R, S)> { - type Dual = Offer<(P::Dual, Q::Dual, R::Dual, S::Dual)>; -} - -unsafe impl HasDual for Choose<(P, Q, R, S, T)> { - type Dual = Offer<(P::Dual, Q::Dual, R::Dual, S::Dual, T::Dual)>; -} - -unsafe impl HasDual for Offer<(P, Q)> { - type Dual = Choose<(P::Dual, Q::Dual)>; -} - -unsafe impl HasDual for Offer<(P, Q, R)> { - type Dual = Choose<(P::Dual, Q::Dual, R::Dual)>; -} - -unsafe impl HasDual for Offer<(P, Q, R, S)> { - type Dual = Choose<(P::Dual, Q::Dual, R::Dual, S::Dual)>; -} - -unsafe impl HasDual for Offer<(P, Q, R, S, T)> { - type Dual = Choose<(P::Dual, Q::Dual, R::Dual, S::Dual, T::Dual)>; -} - unsafe impl HasDual for Var { type Dual = Var; } @@ -184,37 +154,6 @@ unsafe impl HasDual for Rec

{ type Dual = Rec; } -// pub enum Branch { -// Left(B1), -// Right(B2), -// } - -pub enum Branch2 { - B1(B1), - B2(B2), -} - -pub enum Branch3 { - B1(B1), - B2(B2), - B3(B3), -} - -pub enum Branch4 { - B1(B1), - B2(B2), - B3(B3), - B4(B4), -} - -pub enum Branch5 { - B1(B1), - B2(B2), - B3(B3), - B4(B4), - B5(B5), -} - impl Drop for Chan { fn drop(&mut self) { panic!("Session channel prematurely dropped"); @@ -273,220 +212,6 @@ impl Chan> { } } -impl Chan> { - /// Perform an active choice, selecting protocol `P`. - #[must_use] - pub fn sel1(self) -> Chan { - unsafe { - write_chan(&self, 1u8); - transmute(self) - } - } - - /// Perform an active choice, selecting protocol `Q`. - #[must_use] - pub fn sel2(self) -> Chan { - unsafe { - write_chan(&self, 2u8); - transmute(self) - } - } -} - -impl Chan> { - /// Perform an active choice, selecting protocol `P`. - #[must_use] - pub fn sel1(self) -> Chan { - unsafe { - write_chan(&self, 1u8); - transmute(self) - } - } - - /// Perform an active choice, selecting protocol `Q`. - #[must_use] - pub fn sel2(self) -> Chan { - unsafe { - write_chan(&self, 2u8); - transmute(self) - } - } - - /// Perform an active choice, selecting protocol `R`. - #[must_use] - pub fn sel3(self) -> Chan { - unsafe { - write_chan(&self, 3u8); - transmute(self) - } - } -} - -impl Chan> { - /// Perform an active choice, selecting protocol `P`. - #[must_use] - pub fn sel1(self) -> Chan { - unsafe { - write_chan(&self, 1u8); - transmute(self) - } - } - - /// Perform an active choice, selecting protocol `Q`. - #[must_use] - pub fn sel2(self) -> Chan { - unsafe { - write_chan(&self, 2u8); - transmute(self) - } - } - - /// Perform an active choice, selecting protocol `R`. - #[must_use] - pub fn sel3(self) -> Chan { - unsafe { - write_chan(&self, 3u8); - transmute(self) - } - } - - /// Perform an active choice, selecting protocol `R`. - #[must_use] - pub fn sel4(self) -> Chan { - unsafe { - write_chan(&self, 4u8); - transmute(self) - } - } -} - -impl Chan> { - /// Perform an active choice, selecting protocol `P`. - #[must_use] - pub fn sel1(self) -> Chan { - unsafe { - write_chan(&self, 1u8); - transmute(self) - } - } - - /// Perform an active choice, selecting protocol `Q`. - #[must_use] - pub fn sel2(self) -> Chan { - unsafe { - write_chan(&self, 2u8); - transmute(self) - } - } - - /// Perform an active choice, selecting protocol `R`. - #[must_use] - pub fn sel3(self) -> Chan { - unsafe { - write_chan(&self, 3u8); - transmute(self) - } - } - - /// Perform an active choice, selecting protocol `R`. - #[must_use] - pub fn sel4(self) -> Chan { - unsafe { - write_chan(&self, 4u8); - transmute(self) - } - } - - /// Perform an active choice, selecting protocol `R`. - #[must_use] - pub fn sel5(self) -> Chan { - unsafe { - write_chan(&self, 5u8); - transmute(self) - } - } -} - -// impl Chan> { -// /// Passive choice. This allows the other end of the channel to select one -// /// of two options for continuing the protocol: either `P` or `Q`. -// #[must_use] -// pub fn offer(self) -> Branch, Chan> { -// unsafe { -// let b: u8 = read_chan(&self); -// if b == 1u8 { -// Left(transmute(self)) -// } else { -// Right(transmute(self)) -// } -// } -// } -// } - -impl Chan> { - /// Passive choice. This allows the other end of the channel to select one - /// of two options for continuing the protocol: either `P` or `Q`. - #[must_use] - pub fn offer(self) -> Branch2, Chan> { - unsafe { - let b: u8 = read_chan(&self); - if b == 1u8 { - Branch2::B1(transmute(self)) - } else { - Branch2::B2(transmute(self)) - } - } - } -} - -impl Chan> { - /// Passive choice. This allows the other end of the channel to select one - /// of two options for continuing the protocol: either `P` or `Q`. - #[must_use] - pub fn offer(self) -> Branch3, Chan, Chan> { - unsafe { - match read_chan(&self) { - 1u8 => Branch3::B1(transmute(self)), - 2u8 => Branch3::B2(transmute(self)), - _ => Branch3::B3(transmute(self)) - } - } - } -} - -impl Chan> { - /// Passive choice. This allows the other end of the channel to select one - /// of two options for continuing the protocol: either `P` or `Q`. - #[must_use] - pub fn offer(self) -> Branch4, Chan, Chan, Chan> { - unsafe { - match read_chan(&self) { - 1u8 => Branch4::B1(transmute(self)), - 2u8 => Branch4::B2(transmute(self)), - 3u8 => Branch4::B3(transmute(self)), - _ => Branch4::B4(transmute(self)) - } - } - } -} - -impl Chan> { - /// Passive choice. This allows the other end of the channel to select one - /// of two options for continuing the protocol: either `P` or `Q`. - #[must_use] - pub fn offer(self) -> Branch5, Chan, Chan, Chan, Chan> { - unsafe { - match read_chan(&self) { - 1u8 => Branch5::B1(transmute(self)), - 2u8 => Branch5::B2(transmute(self)), - 3u8 => Branch5::B3(transmute(self)), - 4u8 => Branch5::B4(transmute(self)), - _ => Branch5::B5(transmute(self)) - } - } - } -} - impl Chan> { /// Enter a recursive environment, putting the current environment on the /// top of the environment stack. @@ -512,6 +237,8 @@ impl Chan<(P, E), Var>> { } } +branch_impls!(30); + /// Homogeneous select. We have a vector of channels, all obeying the same /// protocol (and in the exact same point of the protocol), wait for one of them /// to receive. Removes the receiving channel from the vector and returns both @@ -678,52 +405,6 @@ pub fn connect(srv: F1, cli: F2) t.join().unwrap(); } -/// This macro is convenient for server-like protocols of the form: -/// -/// `Offer>>` -/// -/// # Examples -/// -/// Assume we have a protocol `Offer, Offer,Eps>>>` -/// we can use the `offer!` macro as follows: -/// -/// ```rust -/// #[macro_use] extern crate session_types; -/// use session_types::*; -/// use std::thread::spawn; -/// -/// fn srv(c: Chan<(), Offer<(Recv, Recv, Eps)>>) { -/// match c.offer() { -/// Branch3::B1(c) => { -/// let (c, n) = c.recv(); -/// assert_eq!(42, n); -/// c.close(); -/// }, -/// Branch3::B2(c) => { -/// c.recv().0.close(); -/// }, -/// Branch3::B3(c) => { -/// c.close(); -/// } -/// } -/// } -/// -/// fn cli(c: Chan<(), Choose<(Send, Send, Eps)>>) { -/// c.sel1().send(42).close(); -/// } -/// -/// fn main() { -/// let (s, c) = session_channel(); -/// spawn(move|| cli(c)); -/// srv(s); -/// } -/// ``` -/// -/// The identifiers on the left-hand side of the arrows have no semantic -/// meaning, they only provide a meaningful name for the reader. - -/// this macro plays the same role as the `select!` macro does for `Receiver`s. -/// /// It also supports a second form with `Offer`s (see the example below). /// /// # Examples @@ -779,17 +460,4 @@ macro_rules! chan_select { else )+ { unreachable!() } }); - - // ( - // $($res:ident = $rx:ident.offer() => { $($t:tt)+ }),+ - // ) => ({ - // let index = { - // let mut sel = $crate::ChanSelect::new(); - // $( sel.add_offer(&$rx); )+ - // sel.wait() - // }; - // let mut i = 0; - // $( if index == { i += 1; i - 1 } { $res = offer!{ $rx, $($t)+ } } else )+ - // { unreachable!() } - // }) } From 21f59a9c2fd74858a12fa028eba4be3980e5d05c Mon Sep 17 00:00:00 2001 From: Philip Munksgaard Date: Wed, 13 Jan 2016 23:30:50 +0100 Subject: [PATCH 6/6] Try to make branching nicer --- examples/arithmetic.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/examples/arithmetic.rs b/examples/arithmetic.rs index 4a8f602..60ce1f7 100644 --- a/examples/arithmetic.rs +++ b/examples/arithmetic.rs @@ -18,21 +18,22 @@ type Srv = fn server(c: Chan<(), Rec>) { let mut c = c.enter(); loop { + use session_types::Branch5::*; c = match c.offer() { - Branch5::B1(c) => { + B1(c) => { c.close(); return }, - Branch5::B2(c) => { + B2(c) => { let (c, n) = c.recv(); let (c, m) = c.recv(); c.send(n + m).zero() }, - Branch5::B3(c) => { + B3(c) => { let (c, n) = c.recv(); c.send(-n).zero() }, - Branch5::B4(c) => { + B4(c) => { let (c, x) = c.recv(); if x >= 0.0 { c.sel1().send(x.sqrt()).zero() @@ -40,7 +41,7 @@ fn server(c: Chan<(), Rec>) { c.sel2().zero() } }, - Branch5::B5(c) => { + B5(c) => { let (c, f) = c.recv(); let (c, n) = c.recv(); c.send(f(n)).zero()