From 34e44dd0545002c0b039ff3d2fa9b3ef4f054190 Mon Sep 17 00:00:00 2001 From: Shun Kashiwa Date: Sun, 1 Oct 2023 04:26:48 -0700 Subject: [PATCH] LocalTransportChannelBuilder --- chorus_book/src/guide-projector.md | 10 ++-- chorus_book/src/guide-transport.md | 28 +++++---- chorus_book/src/header.txt | 4 +- chorus_lib/examples/bookseller.rs | 8 ++- chorus_lib/examples/bookseller2.rs | 7 ++- chorus_lib/examples/hello.rs | 7 ++- chorus_lib/examples/loc-poly.rs | 7 ++- chorus_lib/src/transport/local.rs | 95 ++++++++++++++++++++++++------ 8 files changed, 121 insertions(+), 45 deletions(-) diff --git a/chorus_book/src/guide-projector.md b/chorus_book/src/guide-projector.md index 5378a8b..23bd0c2 100644 --- a/chorus_book/src/guide-projector.md +++ b/chorus_book/src/guide-projector.md @@ -8,14 +8,14 @@ To create a `Projector`, you need to provide the target location and the transpo ```rust # extern crate chorus_lib; -# use chorus_lib::transport::local::{LocalTransport, LocalTransportChannel}; +# use chorus_lib::transport::local::{LocalTransport, LocalTransportChannelBuilder}; # use chorus_lib::core::{ChoreographyLocation, Projector, LocationSet}; -# let transport_channel = LocalTransportChannel::new().with(Alice).with(Bob); -# let alice_transport = LocalTransport::new(Alice, transport_channel.clone()); # #[derive(ChoreographyLocation)] # struct Alice; # #[derive(ChoreographyLocation)] # struct Bob; +# let transport_channel = LocalTransportChannelBuilder::new().with(Alice).with(Bob).build(); +# let alice_transport = LocalTransport::new(Alice, transport_channel.clone()); let projector = Projector::new(Alice, alice_transport); ``` @@ -27,9 +27,9 @@ To execute a choreography, you need to call the `epp_and_run` method on the `Pro ```rust # extern crate chorus_lib; -# use chorus_lib::transport::local::{LocalTransport, LocalTransportChannel}; +# use chorus_lib::transport::local::{LocalTransport, LocalTransportChannelBuilder}; # use chorus_lib::core::{ChoreographyLocation, Projector, Choreography, ChoreoOp, LocationSet}; -# let transport_channel = LocalTransportChannel::new().with(Alice).with(Bob); +# let transport_channel = LocalTransportChannelBuilder::new().with(Alice).with(Bob).build(); # let alice_transport = LocalTransport::new(Alice, transport_channel.clone()); # #[derive(ChoreographyLocation)] # struct Alice; diff --git a/chorus_book/src/guide-transport.md b/chorus_book/src/guide-transport.md index 56f99db..085db99 100644 --- a/chorus_book/src/guide-transport.md +++ b/chorus_book/src/guide-transport.md @@ -8,7 +8,9 @@ ChoRus provides two built-in transports: `local` and `http`. ### The Local Transport -The `local` transport is used to execute choreographies on the same machine on different threads. This is useful for testing and prototyping. Each `local` transport is defined over `LocalTransportChannel`, which contains the set of `ChoreographyLocation` that the `local` transport operates on. You can build a `LocalTransportChannel` by importing the `LocalTransportChannel` struct from the `chorus_lib` crate. +The `local` transport is used to execute choreographies on the same machine on different threads. This is useful for testing and prototyping. + +To use the local transport, we first need to create a `LocalTransportChannel`, which works as a channel between threads and allows them to send messages to each other. To do so, we use the `LocalTransportChannelBuilder` struct from the `chorus_lib` crate. ```rust # extern crate chorus_lib; @@ -17,32 +19,35 @@ The `local` transport is used to execute choreographies on the same machine on d # struct Alice; # #[derive(ChoreographyLocation)] # struct Bob; -use chorus_lib::transport::local::LocalTransportChannel; +use chorus_lib::transport::local::LocalTransportChannelBuilder; -let transport_channel = LocalTransportChannel::new().with(Alice).with(Bob); +let transport_channel = LocalTransportChannelBuilder::new() + .with(Alice) + .with(Bob) + .build(); ``` -To use the `local` transport, first import the `LocalTransport` struct from the `chorus_lib` crate. +Using the `with` method, we add locations to the channel. When we call `build`, it will create an instance of `LocalTransportChannel`. -Then build the transport by using the `LocalTransport::new` associated function, which takes a target location (explained in the [Projector section](./guide-projector.md)) and the `LocalTransportChannel`. +Then, create a transport by using the `LocalTransport::new` function, which takes a target location (explained in the [Projector section](./guide-projector.md)) and the `LocalTransportChannel`. ```rust # extern crate chorus_lib; # use chorus_lib::core::{ChoreographyLocation, LocationSet}; # #[derive(ChoreographyLocation)] # struct Alice; -# use chorus_lib::transport::local::LocalTransportChannel; -# let transport_channel = LocalTransportChannel::new().with(Alice); +# use chorus_lib::transport::local::LocalTransportChannelBuilder; +# let transport_channel = LocalTransportChannelBuilder::new().with(Alice).build(); use chorus_lib::transport::local::{LocalTransport}; let alice_transport = LocalTransport::new(Alice, transport_channel.clone()); ``` -Because of the nature of the `Local` transport, you must use the same `LocalTransportChannel` instance for all locations. You can `clone` the `LocalTransprotChannel` instance and pass it to each `Projector::new` constructor. +Because of the nature of the `Local` transport, you must use the same `LocalTransportChannel` instance for all locations. You can `clone` the `LocalTransportChannel` instance and pass it to each `Projector::new` constructor. ```rust # extern crate chorus_lib; -# use chorus_lib::transport::local::{LocalTransport, LocalTransportChannel}; +# use chorus_lib::transport::local::{LocalTransport, LocalTransportChannelBuilder}; # use std::thread; # use chorus_lib::core::{ChoreographyLocation, ChoreoOp, Choreography, Projector, LocationSet}; # #[derive(ChoreographyLocation)] @@ -55,7 +60,10 @@ Because of the nature of the `Local` transport, you must use the same `LocalTran # fn run(self, op: &impl ChoreoOp) { # } # } -let transport_channel = LocalTransportChannel::new().with(Alice).with(Bob); +let transport_channel = LocalTransportChannelBuilder::new() + .with(Alice) + .with(Bob) + .build(); let mut handles: Vec> = Vec::new(); { // create a transport for Alice diff --git a/chorus_book/src/header.txt b/chorus_book/src/header.txt index d22111b..f24bfe6 100644 --- a/chorus_book/src/header.txt +++ b/chorus_book/src/header.txt @@ -1,13 +1,13 @@ # extern crate chorus_lib; # use chorus_lib::core::{ChoreoOp, Choreography, ChoreographyLocation, Projector, Located, Superposition, Runner, LocationSet}; -# use chorus_lib::transport::local::{LocalTransport, LocalTransportChannel}; +# use chorus_lib::transport::local::{LocalTransport, LocalTransportChannelBuilder}; # #[derive(ChoreographyLocation)] # struct Alice; # #[derive(ChoreographyLocation)] # struct Bob; # #[derive(ChoreographyLocation)] # struct Carol; -# let transport_channel = LocalTransportChannel::new().with(Alice).with(Bob).with(Carol); +# let transport_channel = LocalTransportChannelBuilder::new().with(Alice).with(Bob).with(Carol).build(); # let alice_transport = LocalTransport::new(Alice, transport_channel.clone()); # let bob_transport = LocalTransport::new(Bob, transport_channel.clone()); # let carol_transport = LocalTransport::new(Carol, transport_channel.clone()); \ No newline at end of file diff --git a/chorus_lib/examples/bookseller.rs b/chorus_lib/examples/bookseller.rs index 61152ea..2237be3 100644 --- a/chorus_lib/examples/bookseller.rs +++ b/chorus_lib/examples/bookseller.rs @@ -3,10 +3,11 @@ extern crate chorus_lib; use std::io; use std::thread; +use chorus_lib::transport::local::LocalTransportChannelBuilder; use chrono::NaiveDate; use chorus_lib::core::{ChoreoOp, Choreography, ChoreographyLocation, LocationSet, Projector}; -use chorus_lib::transport::local::{LocalTransport, LocalTransportChannel}; +use chorus_lib::transport::local::LocalTransport; fn get_book(title: &str) -> Option<(i32, NaiveDate)> { match title.trim() { @@ -72,7 +73,10 @@ impl Choreography for BooksellerChoreography { } fn main() { - let transport_channel = LocalTransportChannel::new().with(Seller).with(Buyer); + let transport_channel = LocalTransportChannelBuilder::new() + .with(Seller) + .with(Buyer) + .build(); let transport_seller = LocalTransport::new(Seller, transport_channel.clone()); let transport_buyer = LocalTransport::new(Buyer, transport_channel.clone()); diff --git a/chorus_lib/examples/bookseller2.rs b/chorus_lib/examples/bookseller2.rs index e493af6..b62c0da 100644 --- a/chorus_lib/examples/bookseller2.rs +++ b/chorus_lib/examples/bookseller2.rs @@ -6,7 +6,7 @@ use std::thread; use chorus_lib::{ core::{ChoreoOp, Choreography, ChoreographyLocation, Located, LocationSet, Projector}, - transport::local::{LocalTransport, LocalTransportChannel}, + transport::local::{LocalTransport, LocalTransportChannelBuilder}, }; use chrono::NaiveDate; @@ -142,10 +142,11 @@ fn main() { i }; - let transport_channel = LocalTransportChannel::new() + let transport_channel = LocalTransportChannelBuilder::new() .with(Seller) .with(Buyer1) - .with(Buyer2); + .with(Buyer2) + .build(); let seller_projector = Arc::new(Projector::new( Seller, diff --git a/chorus_lib/examples/hello.rs b/chorus_lib/examples/hello.rs index 32176d9..ab10faa 100644 --- a/chorus_lib/examples/hello.rs +++ b/chorus_lib/examples/hello.rs @@ -3,7 +3,7 @@ extern crate chorus_lib; use std::thread; use chorus_lib::core::{ChoreoOp, Choreography, ChoreographyLocation, LocationSet, Projector}; -use chorus_lib::transport::local::{LocalTransport, LocalTransportChannel}; +use chorus_lib::transport::local::{LocalTransport, LocalTransportChannelBuilder}; // --- Define two locations (Alice and Bob) --- @@ -43,7 +43,10 @@ fn main() { let mut handles: Vec> = Vec::new(); // Create a transport channel // let transport_channel = LocalTransportChannel::::new(); - let transport_channel = LocalTransportChannel::new().with(Alice).with(Bob); + let transport_channel = LocalTransportChannelBuilder::new() + .with(Alice) + .with(Bob) + .build(); // Run the choreography in two threads { // let transport_channel = transport_channel.clone(); diff --git a/chorus_lib/examples/loc-poly.rs b/chorus_lib/examples/loc-poly.rs index f2a50d5..b12b3af 100644 --- a/chorus_lib/examples/loc-poly.rs +++ b/chorus_lib/examples/loc-poly.rs @@ -5,7 +5,7 @@ use std::thread; use chorus_lib::core::{ ChoreoOp, Choreography, ChoreographyLocation, Located, LocationSet, Portable, Projector, }; -use chorus_lib::transport::local::{LocalTransport, LocalTransportChannel}; +use chorus_lib::transport::local::{LocalTransport, LocalTransportChannelBuilder}; #[derive(ChoreographyLocation)] struct Alice; @@ -56,10 +56,11 @@ impl Choreography> for MainChoreography { } fn main() { - let transport_channel = LocalTransportChannel::new() + let transport_channel = LocalTransportChannelBuilder::new() .with(Alice) .with(Bob) - .with(Carol); + .with(Carol) + .build(); let mut handles = vec![]; { diff --git a/chorus_lib/src/transport/local.rs b/chorus_lib/src/transport/local.rs index 6533467..c8e8b31 100644 --- a/chorus_lib/src/transport/local.rs +++ b/chorus_lib/src/transport/local.rs @@ -28,25 +28,29 @@ impl Clone for LocalTransportChannel { } } -impl LocalTransportChannel { - /// Creates a new `LocalTransportChannel` instance - pub fn new() -> Self { - Self { - location_set: PhantomData, - queue_map: HashMap::new().into(), - } - } -} - impl LocalTransportChannel { - /// Adds a new location to the set of locations in the `LocalTransportChannel`. - pub fn with( - self, - _location: NewLocation, - ) -> LocalTransportChannel> { + /// Creates a new `LocalTransportChannel` instance. + /// + /// You must specify the location set of the channel. The channel can only be used by locations in the set. + /// + /// In most cases, you should use `LocalTransportChannelBuilder` instead of calling this method directly. + /// + /// # Examples + /// ``` + /// use chorus_lib::transport::local::{LocalTransportChannel}; + /// use chorus_lib::core::{LocationSet, ChoreographyLocation}; + /// + /// #[derive(ChoreographyLocation)] + /// struct Alice; + /// + /// #[derive(ChoreographyLocation)] + /// struct Bob; + /// + /// let transport_channel = LocalTransportChannel::::new(); + /// ``` + pub fn new() -> LocalTransportChannel { let mut queue_map: QueueMap = HashMap::new(); - let mut str_list = L::to_string_list(); - str_list.push(NewLocation::name()); + let str_list = L::to_string_list(); for sender in &str_list { let mut n = HashMap::new(); for receiver in &str_list { @@ -62,6 +66,58 @@ impl LocalTransportChannel { } } +/// A builder for `LocalTransportChannel`. +/// +/// Use this builder to create a `LocalTransportChannel` instance. +/// +/// # Examples +/// +/// ``` +/// use chorus_lib::core::{LocationSet, ChoreographyLocation}; +/// use chorus_lib::transport::local::{LocalTransportChannelBuilder}; +/// +/// #[derive(ChoreographyLocation)] +/// struct Alice; +/// +/// #[derive(ChoreographyLocation)] +/// struct Bob; +/// +/// let transport_channel = LocalTransportChannelBuilder::new() +/// .with(Alice) +/// .with(Bob) +/// .build(); +/// ``` +pub struct LocalTransportChannelBuilder { + location_set: PhantomData, +} + +impl LocalTransportChannelBuilder { + /// Creates a new `LocalTransportChannelBuilder` instance + pub fn new() -> Self { + Self { + location_set: PhantomData, + } + } +} + +impl LocalTransportChannelBuilder { + /// Adds a new location to the set of locations in the `LocalTransportChannel`. + pub fn with( + &self, + location: NewLocation, + ) -> LocalTransportChannelBuilder> { + _ = location; + LocalTransportChannelBuilder { + location_set: PhantomData, + } + } + + /// Builds a `LocalTransportChannel` instance. + pub fn build(&self) -> LocalTransportChannel { + LocalTransportChannel::new() + } +} + /// The local transport. /// /// This transport uses a blocking queue to allow for communication between threads. Each location must be executed in its thread. @@ -140,7 +196,10 @@ mod tests { fn test_local_transport() { let v = 42; - let transport_channel = LocalTransportChannel::new().with(Alice).with(Bob); + let transport_channel = LocalTransportChannelBuilder::new() + .with(Alice) + .with(Bob) + .build(); let mut handles = Vec::new(); {