Skip to content

Commit

Permalink
LocalTransportChannelBuilder
Browse files Browse the repository at this point in the history
  • Loading branch information
shumbo committed Oct 1, 2023
1 parent 8c02c24 commit 34e44dd
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 45 deletions.
10 changes: 5 additions & 5 deletions chorus_book/src/guide-projector.md
Original file line number Diff line number Diff line change
Expand Up @@ -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);
```

Expand All @@ -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;
Expand Down
28 changes: 18 additions & 10 deletions chorus_book/src/guide-transport.md
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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)]
Expand All @@ -55,7 +60,10 @@ Because of the nature of the `Local` transport, you must use the same `LocalTran
# fn run(self, op: &impl ChoreoOp<Self::L>) {
# }
# }
let transport_channel = LocalTransportChannel::new().with(Alice).with(Bob);
let transport_channel = LocalTransportChannelBuilder::new()
.with(Alice)
.with(Bob)
.build();
let mut handles: Vec<thread::JoinHandle<()>> = Vec::new();
{
// create a transport for Alice
Expand Down
4 changes: 2 additions & 2 deletions chorus_book/src/header.txt
Original file line number Diff line number Diff line change
@@ -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());
8 changes: 6 additions & 2 deletions chorus_lib/examples/bookseller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down Expand Up @@ -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());

Expand Down
7 changes: 4 additions & 3 deletions chorus_lib/examples/bookseller2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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,
Expand Down
7 changes: 5 additions & 2 deletions chorus_lib/examples/hello.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) ---

Expand Down Expand Up @@ -43,7 +43,10 @@ fn main() {
let mut handles: Vec<thread::JoinHandle<()>> = Vec::new();
// Create a transport channel
// let transport_channel = LocalTransportChannel::<LocationSet!(Bob, Alice)>::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();
Expand Down
7 changes: 4 additions & 3 deletions chorus_lib/examples/loc-poly.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -56,10 +56,11 @@ impl Choreography<Located<i32, Alice>> 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![];
{
Expand Down
95 changes: 77 additions & 18 deletions chorus_lib/src/transport/local.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,25 +28,29 @@ impl<L: HList> Clone for LocalTransportChannel<L> {
}
}

impl LocalTransportChannel<LocationSet!()> {
/// Creates a new `LocalTransportChannel` instance
pub fn new() -> Self {
Self {
location_set: PhantomData,
queue_map: HashMap::new().into(),
}
}
}

impl<L: HList> LocalTransportChannel<L> {
/// Adds a new location to the set of locations in the `LocalTransportChannel`.
pub fn with<NewLocation: ChoreographyLocation>(
self,
_location: NewLocation,
) -> LocalTransportChannel<HCons<NewLocation, L>> {
/// 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::<LocationSet!(Alice, Bob)>::new();
/// ```
pub fn new() -> LocalTransportChannel<L> {
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 {
Expand All @@ -62,6 +66,58 @@ impl<L: HList> LocalTransportChannel<L> {
}
}

/// 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<L: HList> {
location_set: PhantomData<L>,
}

impl LocalTransportChannelBuilder<LocationSet!()> {
/// Creates a new `LocalTransportChannelBuilder` instance
pub fn new() -> Self {
Self {
location_set: PhantomData,
}
}
}

impl<L: HList> LocalTransportChannelBuilder<L> {
/// Adds a new location to the set of locations in the `LocalTransportChannel`.
pub fn with<NewLocation: ChoreographyLocation>(
&self,
location: NewLocation,
) -> LocalTransportChannelBuilder<HCons<NewLocation, L>> {
_ = location;
LocalTransportChannelBuilder {
location_set: PhantomData,
}
}

/// Builds a `LocalTransportChannel` instance.
pub fn build(&self) -> LocalTransportChannel<L> {
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.
Expand Down Expand Up @@ -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();
{
Expand Down

0 comments on commit 34e44dd

Please sign in to comment.