1 unstable release
0.1.0-beta1 | Nov 7, 2022 |
---|
#680 in Concurrency
16KB
194 lines
refcapsule
Safely send references to other threads in rust
A way to create a scope in which you can send references across a channel
Example:
use std::thread;
use std::time::Duration;
use std::sync::mpsc::channel;
use refcapsule::{Capsule, with_encapsulated};
let (sender, receiver) = channel::<Capsule<u32>>();
// receiver of references
thread::spawn(move || {
{
let r = receiver.recv().unwrap();
thread::sleep(Duration::from_millis(100));
assert_eq!(*r, 4);
}
{
let r = receiver.recv().unwrap();
thread::sleep(Duration::from_millis(100));
assert_eq!(*r, 12);
}
});
let x: u32 = 4;
let s1 = sender.clone();
with_encapsulated(&x, move |x| s1.send(x).unwrap());
with_encapsulated(&12, move |cap| sender.send(cap).unwrap());
lib.rs
:
This module is somewhat similar to scoped threads, but allows passing references to other threads over channels, or similar mechanisms.
It captures zero or more references inside of "capsules" with a specific lifetime, then runs a function in a context where control won't be returned to the caller until all capsules for that lifetime have been dropped.
Since it blocks waiting for the "capsules" to be dropped, the capsules can be safely passed to other threads (for example with a channel), wher they can be derferenced as references again.
Examples
use std::thread;
use std::time::Duration;
use std::sync::mpsc::channel;
use refcapsule::{Capsule, with_encapsulated};
let (sender, receiver) = channel::<Capsule<u32>>();
// receiver of references
thread::spawn(move || {
{
let r = receiver.recv().unwrap();
thread::sleep(Duration::from_millis(100));
assert_eq!(*r, 4);
}
{
let r = receiver.recv().unwrap();
thread::sleep(Duration::from_millis(100));
assert_eq!(*r, 12);
}
});
let x: u32 = 4;
let s1 = sender.clone();
with_encapsulated(&x, move |x| s1.send(x).unwrap());
with_encapsulated(&12, move |cap| sender.send(cap).unwrap());
Things that shouldn't compile
Mutating the original variable, while it is encapsulated:
use refcapsule::with_encapsulated;
let mut x = 43;
with_encapsulated(&mut x, |y| {
x = 4;
});
Encapsulating a reference with a lifetime shorter than the encapsulation scope:
use refcapsule::{with_encapsulated, encapsulate::gen};
with_encapsulated(gen(|s| {
let x = 43;
s.encapsulate(&x);
}), |x| {});
Mutating the original variable when it is encapsulated using a generator function:
use refcapsule::{with_encapsulated, encapsulate::gen};
let mut x = 43;
with_encapsulated(gen(|s| {
s.encapsulate_mut(&mut x);
}), |y| {
x = 4;
});
Save a scope for a longer duration:
use refcapsule::{with_encapsulated, encapsulate::gen};
with_encapsulated(gen(|s| s), |s| ());