use mpstthree::binary::struct_trait::{end::End, recv::Recv, send::Send, session::Session}; use mpstthree::generate; use mpstthree::role::broadcast::RoleBroadcast; use mpstthree::role::end::RoleEnd; use std::error::Error; // See the folder scribble_protocols for the related Scribble protocol // Create new MeshedChannels for four participants generate!("rec_and_cancel", MeshedChannels, A, C, S); // Types // A type Choose0fromAtoS = ::Dual; type Choose0fromAtoC = ::Dual; enum Branching1fromCtoA { Pay(MeshedChannels, NameA>), Quit(MeshedChannels), } type Recurs1AtoC = Recv; // S enum Branching0fromAtoS { Login( MeshedChannels< Recv<(), End>, Send<(i64, i64), Recurs1StoC>, RoleA>>, NameS, >, ), Fail(MeshedChannels, End, RoleA, NameS>), } type Recurs0StoA = Recv; enum Branching1fromCtoS { Pay( MeshedChannels< End, Recv<(String, i64), Send<(i64, i64), Recurs1StoC>>, RoleC>>, NameS, >, ), Quit(MeshedChannels, RoleC, NameS>), } type Recurs1StoC = Recv; // C enum Branching0fromAtoC { Login( MeshedChannels< Recv<(), Choose1fromCtoA>, Recv<(i64, i64), Choose1fromCtoS>, RoleA>, NameC, >, ), Fail(MeshedChannels, End, RoleA, NameC>), } type Recurs0CtoA = Recv; type Choose1fromCtoA = ::Dual; type Choose1fromCtoS = ::Dual; // Creating the MP sessions // Step 1 type EndpointA1 = MeshedChannels, NameA>; type EndpointC1 = MeshedChannels, RoleS, NameC>; type EndpointC1Pay = MeshedChannels< Choose1fromCtoA, Send<(String, i64), Recv<(i64, i64), Choose1fromCtoS>>, RoleS>, NameC, >; type EndpointS1 = MeshedChannels, RoleC>, NameS>; // Step 0 type EndpointA0 = MeshedChannels< Recv<(String, String), Choose0fromAtoC>, Choose0fromAtoS, RoleC, NameA, >; type EndpointA0Fail = MeshedChannels, Send, RoleC>, NameA>; type EndpointA0Login = MeshedChannels, Send<(), End>, RoleC>>, NameA>; type EndpointC0 = MeshedChannels, End, RoleA>, NameC>; type EndpointS0 = MeshedChannels, NameS>; // Functions fn endpoint_a(s: EndpointA0) -> Result<(), Box> { let ((id, pw), s) = s.recv()?; if id != pw { // actual condition id != pw let s: EndpointA0Fail = choose_mpst_a_to_all!(s, Branching0fromAtoC::Fail, Branching0fromAtoS::Fail); let s = s.send("Fail".to_string())?; let s = s.send("Fail".to_string())?; s.close() } else { let s: EndpointA0Login = choose_mpst_a_to_all!(s, Branching0fromAtoC::Login, Branching0fromAtoS::Login); let s = s.send(())?; let s = s.send(())?; recurs_a(s) } } fn recurs_a(s: EndpointA1) -> Result<(), Box> { offer_mpst!(s, { Branching1fromCtoA::Quit(s) => { s.close() }, Branching1fromCtoA::Pay(s) => { recurs_a(s) }, }) } fn endpoint_s(s: EndpointS0) -> Result<(), Box> { offer_mpst!(s, { Branching0fromAtoS::Fail(s) => { let (_, s) = s.recv()?; s.close() }, Branching0fromAtoS::Login(s) => { let (_, s) = s.recv()?; recurs_s(s) }, }) } fn recurs_s(s: EndpointS1) -> Result<(), Box> { let s = s.send((1, 1))?; offer_mpst!(s, { Branching1fromCtoS::Quit(s) => { let (_, s) = s.recv()?; s.close() }, Branching1fromCtoS::Pay(s) => { let (_, s) = s.recv()?; recurs_s(s) }, }) } fn endpoint_c(s: EndpointC0) -> Result<(), Box> { let id = String::from("id"); let pw = String::from("pw"); let s = s.send((id, pw))?; offer_mpst!(s, { Branching0fromAtoC::Fail(s) => { let (_, s) = s.recv()?; s.close() }, Branching0fromAtoC::Login(s) => { let (_, s) = s.recv()?; recurs_c(s, 100) }, }) } fn recurs_c(s: EndpointC1, loops: i32) -> Result<(), Box> { let ((balance, overdraft), s) = s.recv()?; match loops { 0 => { let s = choose_mpst_c_to_all!(s, Branching1fromCtoA::Quit, Branching1fromCtoS::Quit); let s = s.send(())?; s.close() } _ => { let s: EndpointC1Pay = choose_mpst_c_to_all!(s, Branching1fromCtoA::Pay, Branching1fromCtoS::Pay); let sum = balance + overdraft; let payee = String::from("payee"); let s = s.send((payee, sum))?; recurs_c(s, loops - 1) } } } fn main() { let (thread_a, thread_s, thread_c) = fork_mpst(endpoint_a, endpoint_c, endpoint_s); thread_a.join().unwrap(); thread_c.join().unwrap(); thread_s.join().unwrap(); }