Maybe first, I need to get clarify the nature of the sharing. Apologies in advance for this long post.
In this particular program, there is single tokio::reactor::Core
and a single call to its run()
method. The future passed to run()
is a for_each()
on a UDP stream. The for_each()
closure has the chain of futures, which is indeed the only site where the data is accessed. That chain's final future is spawned onto the event loop for every request, but I think means "put the work on the existing thread for this event loop", and not "create a new thread for this work"
Given all this, maybe this isn't sharing between threads, because there's only one. So maybe the locking construct isn't needed. I was looking at RwLock
but perhaps that's irrelevant to this problem. What I need to do is:
-
Create a HashMap whose lifetime encompasses running the event loop.
-
Make a mutable reference to the HashMap available inside the for_each()
closure.
-
Somehow avoid inadvertent capturing by any of the closures so that the value can continue to be moved.
The way I pass data through the closures currently was adding them to the data that was passed to the for_each()
The way this is done is by implementing the UdpCodec
trait:
impl UdpCodec for MyCodec {
type In = (SocketAddr, MyTask);
type Out = (SocketAddr, Vec<u8>);
.....
MyTask
is a bag of information needed for the request. Just to keep changes simple, I added a HashMap reference to the In
associated type (this defines the argument passed to the for_each() closure):
impl UdpCodec for MyCodec {
type In = (SocketAddr, MyTask, &HashMap<String, u64>);
type Out = (SocketAddr, Vec<u8>);
No dice:
type In = (SocketAddr, KnockdTask, &HashMap<String, u64>);
^ expected lifetime parameter
Then I tried to add lifetimes:
impl<'a> UdpCodec for MyCodec {
type In = (SocketAddr, MyTask, &'a HashMap<String, u64>);
type Out = (SocketAddr, Vec<u8>);
Also no dice:
error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
--> src/main.rs:41:clock6:
impl<'a> UdpCodec for KnockCodec {
^^ unconstrained lifetime parameter
This doesn't seem right. Maybe types in there cannot be references. So I tried an Rc:
impl UdpCodec for MyCodec {
type In = (SocketAddr, MyTask, Rc<HashMap<String, u64>>);
type Out = (SocketAddr, Vec<u8>);
and also, changed the final expression in the function that returns this data:
Ok((*addr, task, self.addrs.clone()))
This compiles and the Rc is available in the closure! But, actually trying to use it:
.and_then(move |args| {
let (o, t, mut state) = args;
state.borrow_mut().insert(String::from("sample-key"), 5);
results in:
state.borrow_mut().insert(String::from("hi"), 5);
^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
I think this is closer to the right way to do it. But I'm not sure how to get the mutability back. Any ideas?