I'm trying to make some observables. The subject that is being observed has a collection of objects that implement its trait. Using the subject in a tokio task causes a compilation error: future created by async block is not "Send"
Code:
use std::time::Duration;
use chrono::{DateTime, Local};
use tokio::time::sleep;
trait TimerObserver<'observer, 'subject: 'observer> {
fn observe(&'observer mut self, time: &'subject DateTime<Local>);
}
trait Timer {
fn get_time() -> DateTime<Local>;
}
trait ObservableTimer<'subject, 'observer> {
fn add_observer(&'subject mut self, observer: Box<dyn TimerObserver<'observer, 'subject>>);
fn set_time(&'subject mut self, time: DateTime<Local>);
}
#[derive(Clone)] // THIS ALSO ERRORS BECAUSE DYNS CANNOT BE CLONED
struct ATimer<'subject, 'observer> {
observers: Vec<Box<dyn TimerObserver<'observer, 'subject>>>, // THIS IS THE ERROR
now: DateTime<Local>,
}
impl<'subject, 'observer> ObservableTimer<'subject, 'observer> for ATimer<'subject, 'observer> {
fn add_observer(&'subject mut self, observer: Box<dyn TimerObserver<'observer, 'subject>>) {
self.observers.push(observer);
}
fn set_time(&'subject mut self, time: DateTime<Local>) {
self.now = time;
}
}
#[derive(Clone)]
struct MyView<'subject> {
now: Option<&'subject DateTime<Local>>,
}
impl<'observer, 'subject: 'observer> TimerObserver<'observer, 'subject> for MyView<'observer> {
fn observe(&'observer mut self, time: &'subject DateTime<Local>) {
println!("received time: {}", time);
self.now = Some(time);
}
}
async fn do_it() {
let mut view = MyView { now: None };
let mut timer = ATimer {
observers: vec![],
now: Local::now(),
};
let observer = Box::new(view);
timer.add_observer(observer);
let mut timer_w = timer.clone();
tokio::spawn(async move {
loop {
sleep(Duration::from_secs(1)).await;
timer_w.clone().set_time(Local::now());
}
});
// give us a few secs to watch
sleep(Duration::from_secs(10)).await;
}
and the error:
error: future cannot be sent between threads safely
--> src/example2.rs:55:5
|
55 | tokio::spawn(async move {
| ^^^^^^^^^^^^ future created by async block is not `Send`
|
= help: the trait `std::marker::Send` is not implemented for `(dyn TimerObserver<'_, '_> + 'static)`
note: captured value is not `Send`
--> src/example2.rs:56:27
|
56 | let mut timer_w = timer_w.clone();
| ^^^^^^^ has type `ATimer<'_, '_>` which is not `Send`
note: required by a bound in `tokio::spawn`
--> /home/coliny/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.14.0/src/task/spawn.rs:127:21
|
127 | T: Future + Send + 'static,
| ^^^^ required by this bound in `tokio::spawn`
error[E0277]: the trait bound `dyn TimerObserver<'_, '_>: Clone` is not satisfied
--> src/example2.rs:21:5
|
19 | #[derive(Clone)]
| ----- in this derive macro expansion
20 | struct ATimer<'subject, 'observer> {
21 | observers: Vec<Box<dyn TimerObserver<'observer, 'subject>>>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `dyn TimerObserver<'_, '_>`
|
= note: required because of the requirements on the impl of `Clone` for `Box<dyn TimerObserver<'_, '_>>`
= note: 1 redundant requirement hidden
= note: required because of the requirements on the impl of `Clone` for `Vec<Box<dyn TimerObserver<'_, '_>>>`
note: required by `clone`
--> /home/coliny/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/clone.rs:122:5
|
122 | fn clone(&self) -> Self;
| ^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
For more information about this error, try `rustc --explain E0277`.
error: could not compile `prideandjoy` due to 2 previous errors
Some of the lifetimes may be redundant but I wanted to be explicit for other reasons.
Help