Trait object cannot be shared between threads safely - rust

When I am writing a zookeeper client in RUST.
code like this :
pub trait ZookeeperHandler {
fn on_child_change(&self, path : &str, value : &String);
fn on_valude_change(&self, path : &str, value: String);
fn reload_all_child(&self, path : &str, children : HashMap<String, String>);
}
pub struct WatchNode {
path : String,
node_type: i32,
handler : Box<dyn ZookeeperHandler>,
}
pub struct WatchNodeManager {
watch_nodes : HashMap<String, WatchNode>,
}
impl WatchNodeManager {
//do something
}
pub struct ZKProxy {
init : bool,
address: String,
zk : Option<ZooKeeper>,
watch_nodes : WatchNodeManager,
}
lazy_static! {
pub static ref ZK_PROXY : Box<ZKProxy> = Box::new(ZKProxy::new(String::from("127.0.0.1:2081")));
}
This fails with the following message:
|
59 | / lazy_static! {
60 | | pub static ref ZK_PROXY : Box<ZKProxy> = Box::new(ZKProxy::new(String::from("127.0.0.1:2081")));
61 | | }
| |_^ `(dyn ZookeeperHandler + 'static)` cannot be shared between threads safely
|
As a beginner of RUST, I can't figure out what this error means and how to fix it.

As global statics can be accessed by multiple threads at the same time, they have to be thread safe. Objects can have the auto-trait Sync that indicates that they are thread-safe.
Unless something prevents that, all types are Send + Sync. In your case, though, your type contains a Box<dyn Zookeeper>, which is neither Send nor Sync, because it could be anything that is dyn Zookeeper. You need to tell Rust that this only accepts Sync objects:
pub struct WatchNode {
path: String,
node_type: i32,
handler: Box<dyn ZookeeperHandler + Sync>,
}

Related

How do I deal with Sized requirements in a trait object?

I'm having trouble understanding traits and object safety in Rust.
I have a StoreTrait for storing some data and a Resource struct that holds a reference to a StoreTrait.
I want the Resource to have a reference to a store intance, because many of the methods of Resource will use store, and I don't want to explicitly pass store to every method on Resource.
I also need to have the logic reside in the trait, because I have various impls that will need to share it (an in-memory and an on-disk store). So moving it into the impl is not what I'd prefer.
In the Store trait, I try passing &Self to a function, but it fails because &Self is not Sized:
pub trait StoreTrait {
fn create_resource(&self) {
let agent = Resource::new(self);
}
}
struct Resource<'a> {
store: &'a dyn StoreTrait,
}
impl<'a> Resource<'a> {
pub fn new(store: &dyn StoreTrait) -> Resource {
Resource { store }
}
}
error[E0277]: the size for values of type `Self` cannot be known at compilation time
--> src/lib.rs:3:35
|
3 | let agent = Resource::new(self);
| ^^^^ doesn't have a size known at compile-time
|
= note: required for the cast to the object type `dyn StoreTrait`
help: consider further restricting `Self`
|
2 | fn create_resource(&self) where Self: Sized {
| ^^^^^^^^^^^^^^^^^
This is where this might become an XY problem
The compiler suggests using where Self: Sized bounds in these methods.
However, this causes another problem later when calling save_resource() from a Resource, since that means I'm invoking a method on a trait object with a Sized bound.
pub trait StoreTrait {
// So after adding the trait bounds here...
fn create_resource(&self)
where
Self: Sized,
{
let agent = Resource::new(self);
}
// And here (internal logic requires that)...
fn save_resource(&self, resource: Resource)
where
Self: Sized,
{
// This now requires `Self: Sized`, too!
self.create_resource()
}
}
pub struct Resource<'a> {
pub store: &'a dyn StoreTrait,
}
impl<'a> Resource<'a> {
pub fn new(store: &dyn StoreTrait) -> Resource {
Resource { store }
}
pub fn save(&self) {
self.store.save_resource(self)
}
}
playground
error: the `save_resource` method cannot be invoked on a trait object
--> src/lib.rs:26:20
|
13 | Self: Sized;
| ----- this has a `Sized` requirement
...
26 | self.store.save_resource(self)
| ^^^^^^^^^^^^^
How do I circumvent setting the trait bound? Or how do I prevent calling a method on a trait object? Perhaps I'm doing something else that doesn't make a ton of sense?
edit: I ended up changing the arguments for the functions. Whenever I used &dyn StoreTrait, I switched to &impl StoreTrait. This means the functions with that signature are compiled for every implementation, which makes the binary a bit bigger, but it now works with the sized requirement. yay!
Perhaps if you just move function from the trait to each implementation it will do what you want?
fn main() {}
pub trait StoreTrait {
fn create_resource(&self);
fn save_resource(&self, resource: &Resource);
}
struct Resource<'a> {
store: &'a dyn StoreTrait,
}
impl<'a> Resource<'a> {
pub fn new(store: &dyn StoreTrait) -> Resource {
Resource { store }
}
pub fn edit(&self) {
self.store.save_resource(self)
}
}
struct StoreMem {
resources: Vec<String>,
}
impl StoreTrait for StoreMem {
fn create_resource(&self) {
let agent = Resource::new(self);
}
fn save_resource(&self, resource: &Resource) {
//
}
}
struct StoreDisk {
resources: Vec<String>,
}
impl StoreTrait for StoreDisk {
fn create_resource(&self) {
let agent = Resource::new(self);
}
fn save_resource(&self, resource: &Resource) {
//
}
}

How to solve "no method named `foo` found for mutable reference `&mut Bar<X>` in the current scope"

I'm working on a generic data structure that will hold pointers to some structs, and using a Handle that would normally be held by the struct, will call back into the structure to remove the pointer when the Handle is dropped. I'm unable to come up with a solution that will allow the call from the handle back into the node. I've tried a few different permutations of trait bound narrowing and associated type hackery with no success... I'm feeling like the issue is related to some kind of infinite associated type recursion (something like https://github.com/rust-lang/rust/issues/23122), but just not sure. The error is
error[E0599]: no method named `remove` found for mutable reference `&mut Node<X>` in the current scope
--> src/lib.rs:50:15
|
50 | m.remove(self.index); // <<----- ???
| ^^^^^^ method not found in `&mut Node<X>`
|
= note: the method `remove` exists but the following trait bounds were not satisfied:
`<X as FooTrait>::T = X`
pub struct Node<T: FooTrait> {
items: Vec<*mut T>,
}
impl <T: FooTrait<T=T>> Node<T> {
pub fn new() ->Node<T> {
Node {
items: Default::default(),
}
}
pub fn insert(&mut self, item: &mut T) {
let handle = Handle::new(self,0);
item.set_handle(handle);
self.items.push(item);
}
pub fn remove(&mut self, index: u16) {
self.items.swap_remove(index as usize);
}
}
pub struct Handle<X:FooTrait> {
node: *mut Node<X>,
index: u16,
}
impl <T:FooTrait> Handle<T> {
fn new(node: &mut Node<T>, i: u16) -> Handle<T> {
Handle {
node: node,
index: i
}
}
}
impl <X:FooTrait> Drop for Handle<X> {
fn drop(&mut self) {
unsafe {
let m = self.node.as_mut().unwrap();
m.remove(self.index); // <<----- ???
}
}
}
pub trait FooTrait {
type T : FooTrait;
fn set_handle(&mut self, h: Handle<Self::T>);
}
Yes this is caused by recursive constraints.
remove(&mut self, index: u16) is only defined for types that contain to T: FooTrait<T=T>, causing the FooTrait::T to reference itself, because T is that FooTrait<T=T> type.

Rust: impl trait cannot be shared between threads safely

I have a struct RabbitMQBackend which implements a trait Backend like:
pub trait Backend {
// Start consuming message from the queue.
fn pull(&self, sender: &Sender<String>);
}
pub struct RabbitMQBackend {
// Some fields ...
}
impl Backend for RabbitMQBackend {
fn pull(&self, sender: &Sender<String>) {do something...}
}
I am creating an instance of this struct like:
let rmq_backend = RabbitMQBackend::new("amqp://user:password#localhost:5672/", "testqueue2");
let mut consumer = ThreadConsumer::new();
consumer.consume(&rmq_backend);
where ThreadConsumer is:
pub struct ThreadConsumer {
pub sender: Sender<String>,
pub receiver: Receiver<String>,
}
impl Consumer for ThreadConsumer {
fn new() -> Self {
let (sender, receiver) = bounded(3);
ThreadConsumer {
sender: sender,
receiver: receiver,
}
}
fn consume(&mut self, backend: &impl Backend) {
let consumer = thread::spawn(move || {
backend.pull(&self.sender);
});
}
}
The problem is I am trying to call the backend.pull function from inside a separate thread, but I am getting this error:
error[E0277]: `impl Backend` cannot be shared between threads safely
--> src/consumer/thread_consumer/thread_consumer.rs:23:24
|
23 | let consumer = thread::spawn(move || {
| ^^^^^^^^^^^^^ `impl Backend` cannot be shared between threads safely
|
= help: the trait `std::marker::Sync` is not implemented for `impl Backend`
help: consider further restricting this bound with `+ std::marker::Sync`
--> src/consumer/thread_consumer/thread_consumer.rs:20:37
|
20 | fn consume(&mut self, backend: &impl Backend) {
| ^^^^^^^^^^^^
= note: required because of the requirements on the impl of `std::marker::Send` for `&impl Backend`
= note: required because it appears within the type `[closure#src/consumer/thread_consumer/thread_consumer.rs:23:38: 25:10 backend:&impl Backend, self:&mut consumer::thread_consumer::thread_consumer::ThreadConsumer]
Note 1: I tried implementing the Send and Senc trait for the Backend trait and RabbitMQBackend struct like:
pub trait Backend: Send + Sync {
// Start consuming message from the queue.
fn pull(&self, sender: &Sender<String>);
}
pub struct RabbitMQBackend {
// Some fields ...
}
unsafe impl Send for RabbitMQBackend {}
unsafe impl Sync for RabbitMQBackend {}
then passed the backend function arg like
fn consume(&mut self, backend: &impl Backend + Send + Sync) {...}
but it raised the following error
= note: but, the lifetime must be valid for the static lifetime...
= note: ...so that the types are compatible:
How can I resolve this issue?
The native Rust threads are not scoped. This means once the thread is spawned it will live its life independent from its creator (as far as the Rust compiler is concerned anyway). So if you want to move a reference into a thread, that reference needs to live forever (aka 'static) as, as far as the compiler is concerned, the creator thread could die immediately and the child never.
So I see two solutions there:
don't do that, use something like Arc (and probably a mutex or rwlock depending on the thread safety of the backend) or somesuch for your backend, such that your backend has "multiple owners" via the Arc, this way you obviate the ref' issue
use scoped threads

Lifetime issue with Actix Web

I'm implementing middleware with Actix-web and having an issue with lifetime that I couldn't figure out.
extern crate actix_web;
use actix_web::actix::{Actor, Addr, Context, System};
use actix_web::middleware::Middleware;
use actix_web::{http, server, App, HttpRequest, Responder};
use std::collections::HashMap;
pub struct CacheActor {
caches: HashMap<String, String>,
}
impl CacheActor {
pub fn new() -> Self {
CacheActor {
caches: HashMap::new(),
}
}
}
impl Actor for CacheActor {
type Context = Context<Self>;
}
fn create_resource(req: HttpRequest, addr: &Addr<CacheActor>) -> impl Responder {
unimplemented!();
format!("Unimplemented")
}
fn list_resources(req: HttpRequest, addr: &Addr<CacheActor>) -> impl Responder {
unimplemented!();
format!("Unimplemented")
}
pub trait TusMiddlewareTrait {
fn with_tus(self, addr: &Addr<CacheActor>) -> App;
}
impl TusMiddlewareTrait for App {
fn with_tus(self, addr: &Addr<CacheActor>) -> App {
self.route("/files", http::Method::GET, |req| list_resources(req, addr))
.route("/files", http::Method::POST, |req| {
create_resource(req, addr)
})
}
}
fn main() {
let system = System::new("Example");
let cache_addr = CacheActor::new().start();
server::new(|| App::new().with_tus(&cache_addr))
.bind("127.0.0.1:8080")
.unwrap()
.run();
system.run();
}
The error that I get is the following,
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/tus/middleware.rs:84:49
|
84 | .route("/files", http::Method::GET, |req| list_resources(req, addr))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 81:5...
--> src/tus/middleware.rs:81:5
|
81 | / fn with_tus(self, addr: &actix::Addr<cache::CacheActor>) -> App {
82 | | self.middleware(TusMiddleware)
83 | | .route("/files", http::Method::OPTIONS, tus_information)
84 | | .route("/files", http::Method::GET, |req| list_resources(req, addr))
... |
87 | | })
88 | | }
| |_____^
= note: ...so that the types are compatible:
expected &&actix::address::Addr<tus::cache::CacheActor>
found &&actix::address::Addr<tus::cache::CacheActor>
= note: but, the lifetime must be valid for the static lifetime...
As for what I understand, I am passing cache_addr as a reference to with_tus function. Inside each closure in route, addr is also a reference.
I don't understand why the compiler said the lifetime cannot outlive the anonymous lifetime #1. From what I can tell is that cache_addr's lifetime still outlives the closure. The lifetime should cover up until system.run() line. Can someone enlighten me?
Edit:
I updated the code above to MCVE (at least to a point that it is simple enough to copy the whole code and run cargo build while still preserving the same error message). I can't run it on rust-playground. It doesn't support actix crate at this point. I tried reducing it further but it's giving me a different error. Sorry, I am pretty new to Rust.
My questions are twofold, one I like to understand what's the error telling me. Second, I like to know how to properly do this with actix thus why the sample code is dependent on actix.
Look at the App::route signature:
pub fn route<T, F, R>(self, path: &str, method: Method, f: F) -> App<S>
where
F: WithFactory<T, S, R>,
R: Responder + 'static,
T: FromRequest<S> + 'static,
F generic depends on T and R that in turn have 'static lifetime requirement.
Your closure captures an &Addr<CacheActor> that it is not valid for 'static lifetime and this generates the error.
A possibility that I see is to use the App "State", directly from the docs:
Application state is shared with all routes and resources within the same application. When using an http actor, state can be accessed with the HttpRequest::state() as read-only, but interior mutability with RefCell can be used to achieve state mutability. State is also available for route matching predicates and middlewares.
In this case should be something like:
extern crate actix_web;
use actix_web::actix::{Actor, Addr, Context, System};
use actix_web::{http, server, App, HttpRequest, HttpResponse, Result};
use std::collections::HashMap;
use actix_web::dev::Handler;
#[derive(Clone)]
pub struct CacheActor {
caches: HashMap<String, String>,
}
impl CacheActor {
pub fn new() -> Self {
CacheActor {
caches: HashMap::new(),
}
}
}
impl Actor for CacheActor {
type Context = Context<Self>;
}
impl<S> Handler<S> for CacheActor {
type Result = String;
fn handle(&self, _req: &HttpRequest<S>) -> Self::Result {
unimplemented!();
}
}
fn list_resources(req: &HttpRequest<Addr<CacheActor>>) -> Result<HttpResponse> {
Ok(HttpResponse::Found()
.header(http::header::LOCATION, format!("hello {}", req.path()))
.finish())
}
fn main() {
let system = System::new("Example");
server::new(|| {
let cache_addr = CacheActor::new().start();
App::with_state(cache_addr)
.resource("/world", |r| r.method(http::Method::GET).f(list_resources))
})
.bind("127.0.0.1:8080")
.unwrap()
.run();
system.run();
}

How to move a value out of an object-safe trait object?

A Mech carries a driver, which is a Named entity. At run-time, an omitted Mech constructor consults external source for the specific type of driver to use.
trait Named {
fn name(self) -> String;
}
struct Person {
first_name: String,
last_name: String
}
impl Named for Person {
fn name(self) -> String {
format!("{} {}", self.first_name, self.last_name)
}
}
pub struct Mech<'a> {
driver: Box<Named + 'a>,
}
impl<'a> Mech<'a> {
pub fn driver_name(self) -> String {
self.driver.name()
}
}
Method driver_name returns ownership to a String, for it to be further used in chained calls (in actual code it's a Command). It fails compilation with:
error[E0161]: cannot move a value of type Named + 'a: the size of Named + 'a cannot be statically determined
--> src/lib.rs:22:9
|
22 | self.driver.name()
| ^^^^^^^^^^^
Making the trait Sized fails the object safety:
trait Named: Sized {
fn name(self) -> String;
}
↓
error[E0038]: the trait `Named` cannot be made into an object
--> src/lib.rs:17:5
|
17 | driver: Box<Named + 'a>,
| ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Named` cannot be made into an object
|
= note: the trait cannot require that `Self : Sized`
Is there a way to make this pattern happen?
Is there anything fundamental that I seem to be missing?
In case this is impossible to achieve, what's a good way to work around it?
As the compiler hinted, the trait cannot be statically determined because you are dealing with dynamic dispatch. Ownership is still possible in this scenario using self: Box<Self>.
trait Named {
fn name(self: Box<Self>) -> String;
}
struct Person {
first_name: String,
last_name: String,
}
impl Named for Person {
fn name(self: Box<Self>) -> String {
format!("{} {}", self.first_name, self.last_name)
}
}
pub struct Mech<'a> {
driver: Box<Named + 'a>,
}
impl<'a> Mech<'a> {
pub fn driver_name(self) -> String {
self.driver.name()
}
}
fn main() {}

Resources