use rand::{thread_rng, Rng}; use mpstthree::binary::struct_trait::{end::End, recv::Recv, send::Send, session::Session}; use mpstthree::functionmpst::fork::fork_mpst; use mpstthree::meshedchannels::MeshedChannels; use mpstthree::role::Role; use mpstthree::checker_concat; use std::error::Error; use mpstthree::functionmpst::close::close_mpst; use mpstthree::role::a::RoleA; use mpstthree::role::a_to_all::RoleAtoAll; use mpstthree::role::all_to_a::RoleAlltoA; use mpstthree::role::b::RoleB; use mpstthree::role::c::RoleC; use mpstthree::role::end::RoleEnd; use mpstthree::name::a::NameA; use mpstthree::name::b::NameB; use mpstthree::name::c::NameC; use mpstthree::functionmpst::recv::recv_mpst_a_from_b; use mpstthree::functionmpst::recv::recv_mpst_b_from_a; use mpstthree::functionmpst::recv::recv_mpst_b_from_c; use mpstthree::functionmpst::recv::recv_mpst_c_from_b; use mpstthree::functionmpst::send::send_mpst_a_to_b; use mpstthree::functionmpst::send::send_mpst_b_to_a; use mpstthree::functionmpst::send::send_mpst_b_to_c; use mpstthree::functionmpst::send::send_mpst_c_to_b; use mpstthree::functionmpst::offer::offer_mpst_session_to_b_from_a; use mpstthree::functionmpst::offer::offer_mpst_session_to_c_from_a; use mpstthree::functionmpst::choose::choose_left_mpst_session_a_to_all; use mpstthree::functionmpst::choose::choose_right_mpst_session_a_to_all; use mpstthree::functionmpst::ChooseMpst; use mpstthree::functionmpst::OfferMpst; use petgraph::dot::Dot; // Test our usecase // Simple types // Client = A // Authenticator = B // Server = C type BtoAClose = End; type BtoCClose = End; type BtoAVideo = Recv>; type BtoCVideo = Send>; type CtoBClose = ::Dual; type CtoAClose = End; type CtoBVideo = as Session>::Dual; type AtoCClose = ::Dual; type AtoBClose = ::Dual; type AtoBVideo = as Session>::Dual; // Stacks type StackBEnd = RoleEnd; type StackBEndDual = ::Dual; type StackBVideo = RoleA>>>; type StackBVideoDual = ::Dual; type StackBFull = RoleA>>; type StackCEnd = RoleEnd; type StackCEndDual = ::Dual; type StackCVideo = RoleB>; type StackCVideoDual = ::Dual; type StackCFull = RoleAlltoA; type StackAEnd = RoleEnd; type StackAVideo = RoleB>; type StackAChoice = RoleAtoAll; type StackAFull = RoleB>; // Creating the MP sessions // For A type ChooseAtoB = ChooseMpst, CtoBVideo, AtoBClose, CtoBClose, StackBVideoDual, StackBEnd, NameB>; type ChooseAtoC = ChooseMpst, BtoCClose, AtoCClose, StackCVideoDual, StackCEnd, NameC>; type InitA = Send>>; type EndpointAFull = MeshedChannels, ChooseAtoC, StackAFull, NameA>; // For B type EndpointBVideo = MeshedChannels, BtoCVideo, StackBVideo, NameB>; type OfferB = OfferMpst, BtoCVideo, BtoAClose, BtoCClose, StackBVideo, StackBEnd, NameB>; type InitB = Recv>>; type EndpointBFull = MeshedChannels, End, StackBFull, NameB>; // For C type EndpointCVideo = MeshedChannels, StackCVideo, NameC>; type OfferC = OfferMpst, CtoAClose, CtoBClose, StackCVideo, StackCEnd, NameC>; type EndpointCFull = MeshedChannels, End, StackCFull, NameC>; // Functions related to endpoints fn server(s: EndpointCFull) -> Result<(), Box> { offer_mpst_session_to_c_from_a( s, |s: EndpointCVideo| { let (request, s) = recv_mpst_c_from_b(s)?; let s = send_mpst_c_to_b(request + 1, s); close_mpst(s) }, close_mpst, ) } fn authenticator(s: EndpointBFull) -> Result<(), Box> { let (id, s) = recv_mpst_b_from_a(s)?; let s = send_mpst_b_to_a(id + 1, s); offer_mpst_session_to_b_from_a( s, |s: EndpointBVideo| { let (request, s) = recv_mpst_b_from_a(s)?; let s = send_mpst_b_to_c(request + 1, s); let (video, s) = recv_mpst_b_from_c(s)?; let s = send_mpst_b_to_a(video + 1, s); assert_eq!(request, id + 1); assert_eq!(video, id + 3); close_mpst(s) }, close_mpst, ) } fn client_video(s: EndpointAFull) -> Result<(), Box> { let mut rng = thread_rng(); let id: i32 = rng.gen(); let s = send_mpst_a_to_b(id, s); let (accept, s) = recv_mpst_a_from_b(s)?; assert_eq!(accept, id + 1); let s = choose_left_mpst_session_a_to_all::< CtoBVideo, CtoBClose, AtoBVideo, CtoAClose, AtoBClose, BtoAClose, StackBVideoDual, StackBEndDual, StackCVideoDual, StackCEndDual, StackAVideo, StackAEnd, >(s); let s = send_mpst_a_to_b(accept, s); let (result, s) = recv_mpst_a_from_b(s)?; assert_eq!(result, accept + 3); close_mpst(s) } fn client_close(s: EndpointAFull) -> Result<(), Box> { let mut rng = thread_rng(); let id: i32 = rng.gen(); let s = send_mpst_a_to_b(id, s); let (accept, s) = recv_mpst_a_from_b(s)?; assert_eq!(accept, id + 1); let s = choose_right_mpst_session_a_to_all::< CtoBVideo, CtoBClose, AtoBVideo, CtoAClose, AtoBClose, BtoAClose, StackBVideoDual, StackBEndDual, StackCVideoDual, StackCEndDual, StackAVideo, StackAEnd, >(s); close_mpst(s) } ///////////////////////////////////////// pub fn run_a_usecase_left() { // Test video branch. let (thread_a, thread_b, thread_c) = fork_mpst(client_video, authenticator, server); assert!(thread_a.join().is_ok()); assert!(thread_b.join().is_ok()); assert!(thread_c.join().is_ok()); } pub fn run_a_usecase_right() { // Test end branch. let (thread_a, thread_b, thread_c) = fork_mpst(client_close, authenticator, server); assert!(thread_a.join().is_ok()); assert!(thread_b.join().is_ok()); assert!(thread_c.join().is_ok()); } pub fn run_a_usecase_checker() { let (graphs, kmc) = checker_concat!( "", EndpointAFull, EndpointBFull, EndpointCFull ) .unwrap(); ////////////// Test graph A let graph_a = &graphs["RoleA"]; assert_eq!( format!("{:?}", Dot::new(&graph_a)), "digraph {\n \ 0 [ label = \"\\\"0\\\"\" ]\n \ 1 [ label = \"\\\"1\\\"\" ]\n \ 2 [ label = \"\\\"2\\\"\" ]\n \ 3 [ label = \"\\\"2.1\\\"\" ]\n \ 4 [ label = \"\\\"2.2\\\"\" ]\n \ 5 [ label = \"\\\"2.3\\\"\" ]\n \ 6 [ label = \"\\\"2.1\\\"\" ]\n \ 0 -> 1 [ label = \"\\\"RoleA!RoleB: i32\\\"\" ]\n \ 1 -> 2 [ label = \"\\\"RoleA?RoleB: i32\\\"\" ]\n \ 2 -> 3 [ label = \"\\\"RoleA!RoleB: i32\\\"\" ]\n \ 3 -> 4 [ label = \"\\\"RoleA?RoleB: i32\\\"\" ]\n \ 4 -> 5 [ label = \"\\\"0\\\"\" ]\n \ 2 -> 6 [ label = \"\\\"0\\\"\" ]\n\ }\n" ); ////////////// Test graph B let graph_b = &graphs["RoleB"]; assert_eq!( format!("{:?}", Dot::new(&graph_b)), "digraph {\n \ 0 [ label = \"\\\"0\\\"\" ]\n \ 1 [ label = \"\\\"1\\\"\" ]\n \ 2 [ label = \"\\\"2\\\"\" ]\n \ 3 [ label = \"\\\"2.1\\\"\" ]\n \ 4 [ label = \"\\\"2.2\\\"\" ]\n \ 5 [ label = \"\\\"2.3\\\"\" ]\n \ 6 [ label = \"\\\"2.4\\\"\" ]\n \ 7 [ label = \"\\\"2.5\\\"\" ]\n \ 8 [ label = \"\\\"2.1\\\"\" ]\n \ 0 -> 1 [ label = \"\\\"RoleB?RoleA: i32\\\"\" ]\n \ 1 -> 2 [ label = \"\\\"RoleB!RoleA: i32\\\"\" ]\n \ 2 -> 3 [ label = \"\\\"RoleB?RoleA: i32\\\"\" ]\n \ 3 -> 4 [ label = \"\\\"RoleB!RoleC: i32\\\"\" ]\n \ 4 -> 5 [ label = \"\\\"RoleB?RoleC: i32\\\"\" ]\n \ 5 -> 6 [ label = \"\\\"RoleB!RoleA: i32\\\"\" ]\n \ 6 -> 7 [ label = \"\\\"0\\\"\" ]\n \ 2 -> 8 [ label = \"\\\"0\\\"\" ]\n\ }\n" ); ////////////// Test graph C let graph_c = &graphs["RoleC"]; assert_eq!( format!("{:?}", Dot::new(&graph_c)), "digraph {\n \ 0 [ label = \"\\\"0\\\"\" ]\n \ 1 [ label = \"\\\"0.1\\\"\" ]\n \ 2 [ label = \"\\\"0.2\\\"\" ]\n \ 3 [ label = \"\\\"0.3\\\"\" ]\n \ 4 [ label = \"\\\"0.1\\\"\" ]\n \ 0 -> 1 [ label = \"\\\"RoleC?RoleB: i32\\\"\" ]\n \ 1 -> 2 [ label = \"\\\"RoleC!RoleB: i32\\\"\" ]\n \ 2 -> 3 [ label = \"\\\"0\\\"\" ]\n \ 0 -> 4 [ label = \"\\\"0\\\"\" ]\n\ }\n" ); ////////////// Test KMC output assert_eq!(kmc, None); }