rusty_junctions/
lib.rs

1//! Crate implementing Join Patterns from the [Join Calculus](https://www.microsoft.com/en-us/research/wp-content/uploads/2017/01/join-tutorial.pdf) developed by
2//! Cédric Fournet and Georges Gonthier.
3//!
4//! Join Patterns are based on message-passing concurrency and offer a declarative
5//! way of expression concurrent computation that is entirely thread-safe and
6//! requires no manual coordination efforts.
7//!
8//! See the example of a storage cell written using this crate:
9//!
10//! ```
11//! use rusty_junctions::Junction;
12//!
13//! fn main() {
14//!     /* Start of the Join Pattern setup. */
15//!
16//!     // Declare a new Junction to create new channels and construct new
17//!     // Join Patterns based on them.
18//!     let cell = Junction::new();
19//!
20//!     // New channel to retrieve the value of the storage cell.
21//!     let get = cell.recv_channel::<i32>();
22//!
23//!     // New channel to update the value of the storage cell.
24//!     let put = cell.send_channel::<i32>();
25//!
26//!     // New channel to swap the value of the storage cell for a new one and
27//!     // retrieve the value that was just replaced.
28//!     let swap = cell.bidir_channel::<i32, i32>();
29//!
30//!     // New channel that will actually carry the value so that at no point
31//!     // any given thread will have possession over it so concurrency issues
32//!     // are avoided by design.
33//!     let val = cell.send_channel::<i32>();
34//!
35//!     // Set up some clones of the above channels we can move over to the
36//!     // thread in which the function body of the Join Pattern will run.
37//!     //
38//!     // Clones of channels work like clones of the std::sync::mpsc::Sender
39//!     // clones - any message sent from the clone will be received as if
40//!     // sent from the original.
41//!     let get_val = val.clone();
42//!     let put_val = val.clone();
43//!     let swap_val = val.clone();
44//!     let val_val = val.clone();
45//!
46//!     // Declare a new Join Pattern to update the storage cell value. If
47//!     // both the put and val channel have sent a message, meaning someone
48//!     // requested a value update and there is a value to be updated, send
49//!     // a new val message through one of val's clones that carries the
50//!     // updated value.
51//!     cell.when(&put).and(&val).then_do(move |new, _old| {
52//!         println!(">> put-val pattern fired with new={}!", new);
53//!         put_val.send(new).unwrap();
54//!     });
55//!
56//!     // Declare a new Join Pattern to retrieve the storage cell value. If
57//!     // both the get and val channel have sent a message, meaning someone
58//!     // requested the value and there is a value to be given, return that
59//!     // value and resend it through one of val's clones so that the value
60//!     // is still available in future and not just consumed once.
61//!     cell.when(&val).and_recv(&get).then_do(move |v| {
62//!         println!(">> val-get pattern fired with v={}!", v);
63//!
64//!         get_val.send(v.clone()).unwrap();
65//!
66//!         v
67//!     });
68//!
69//!     // Declare a new Join Pattern to swap the storage cell value with a
70//!     // new one and retrieve the old. Essentially works like a combination
71//!     // of the previous two Join Patterns, with one crucial distinction:
72//!     // with this Join Pattern, the update of the value and the retrieval
73//!     // of the old are atomic, meaning that it is guaranteed that even in
74//!     // a multithreaded environment with many users accessing the storage
75//!     // cell, the value retrieved is exactly the value that has been
76//!     // updated.
77//!     cell.when(&val).and_bidir(&swap).then_do(move |old, new| {
78//!         println!(
79//!             ">> val-swap pattern fired with old={} and new={}!",
80//!             old, new
81//!         );
82//!         swap_val.send(new).unwrap();
83//!
84//!         old
85//!     });
86//!
87//!     // Declare a new Join Pattern that mentions the same channel multiple
88//!     // times, so if the val channel has sent two messages they will be
89//!     // combined into a single messages sent by a clone of val. This ensures
90//!     // that eventually, the storage cell will only keep a single value
91//!     // around.
92//!     cell.when(&val).and(&val).then_do(move |a, b| {
93//!         println!(">> val-val pattern fired with a={} and b={}!", a, b);
94//!         val_val.send(a + b).unwrap();
95//!     });
96//!
97//!     /* End of the Join Pattern setup. */
98//!
99//!     // Initialise the storage cell by sending an initial value that
100//!     // can be picked up in future executions of the above Join Patterns.
101//!     val.send(1729).unwrap();
102//!
103//!     // Request a value update if one is available.
104//!     put.send(42).unwrap();
105//!
106//!     // Send another value that will eventually get combined with the
107//!     // existing one.
108//!     val.send(1).unwrap();
109//!
110//!     // Request another value update.
111//!     put.send(22).unwrap();
112//!
113//!     // Request the current value of the storage cell and print it.
114//!     println!("get.recv()={}", get.recv().unwrap());
115//!
116//!     // Request a swap of the current value of the storage cell with a new
117//!     // one and print the old value that is retrieved as a result.
118//!     println!("swap.send_recv()={}", swap.send_recv(16).unwrap());
119//!
120//!     // Request the current value of the storage cell again and print it.
121//!     println!("get.recv()={}", get.recv().unwrap());
122//! }
123//! ```
124//!
125//! The above example is reasonably complex to show off most of the
126//! capabilities of this crate, as well as the general workflow of setting
127//! up channels, then Join Patterns synchronising the channels and running
128//! arbitrary code, followed by actually sending messages on the declared
129//! channels to satisfy the conditions declared in the Join Patterns that will
130//! trigger an execution of their function body.
131//!
132//! For more examples, visit the [`examples`](https://github.com/smueksch/rusty_junctions/tree/master/examples) folder in the [Rusty Junctions GitHub
133//! repository](https://github.com/smueksch/rusty_junctions).
134
135mod bag;
136pub mod channels;
137mod controller;
138mod counter;
139mod function_transforms;
140mod inverted_index;
141mod junction;
142pub mod patterns;
143pub mod types;
144
145pub use junction::Junction;