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
Related
I created two structs, Car and CarModifier. Both Car and CarModifier are instantiated in main.rs. CarModifier modifies one of the fields of Car using data from curl request. Here is the code:
main.rs
use sample::{car::Car, car_modifier::CarModifier};
fn main() {
println!("Hello, world!");
let mut car = Car::new();
let mut car_modifier = CarModifier::new();
car_modifier.update_car(&mut car);
println!("{:?}", car.driver);
}
Car.rs
#[derive(Debug)]
pub struct Car<'a> {
pub driver: &'a [u8]
}
impl<'a> Car<'a> {
pub fn new() -> Self {
Self {
driver: &[26]
}
}
pub fn update_driver(&mut self, new_driver: &'a [u8]) {
self.driver = new_driver;
}
}
CarModifier.rs
use curl::easy::Easy;
use crate::{car::Car};
pub struct CarModifier;
impl CarModifier {
pub fn new() -> Self {
Self {
}
}
pub fn update_car(&mut self, car: &mut Car) {
let mut easy = Easy::new();
easy.url("https://www.rust-lang.org/").unwrap();
let mut transfer = easy.transfer();
transfer.write_function(|data: &[u8]| {
car.update_driver(data);
Ok(data.len())
}).unwrap();
transfer.perform().unwrap();
}
}
This is the error which I get when trying to run
error[E0521]: borrowed data escapes outside of closure
--> src/car_modifier.rs:19:13
|
13 | pub fn update_car(&mut self, car: &mut Car) {
| --- `car` declared here, outside of the closure body
...
18 | transfer.write_function(|data: &[u8]| {
| ---- `data` is a reference that is only valid in the closure body
19 | car.update_driver(data);
| ^^^^^^^^^^^^^^^^^^^^^^^ `data` escapes the closure body here
For more information about this error, try `rustc --explain E0521`.
error: could not compile `sample` due to previous error
I seem to understand from the error that data lives only in the closure body and the code tries to refer that in car.driver which will outlive the closure body, hence the error. Is this the right understanding?
I am also aware that instead of using &[u8], I could use Vec<u8> to resolve the error. But how can I keep using &[u8]?
Basically data belongs to the curl library. It may be a slice of some library internal buffer pool, and may be re-used for some other curl api calls later on, or freed after this call. You need to copy data into the Car structure instead of just having a pointer to the underlying buffer. Rust compiler helps you to catch that problem. In C++ the compiler won't even tell you this error and the C++ code will have runtime problems.
In this code, I have the skeleton of an observable system. The documentation on implementing Observable and other decoupling patterns are usually missing a final step on allowing access to the listener while also having it be &mut during the notification call, but that's what RefCell is intended to handle. So I have this code all worked out, but I'm having a last piece of trouble getting my concrete T into the &dyn Trait.
use std::{cell::RefCell, rc::Rc};
pub trait Observer {
fn notify(&mut self);
}
#[derive(Default)]
pub struct Subject<'s> {
listeners: Vec<Rc<RefCell<Box<dyn Observer + 's>>>>,
}
pub fn wrap<T>(t: T) -> Rc<RefCell<Box<T>>> {
Rc::new(RefCell::new(Box::new(t)))
}
impl<'s> Subject<'s> {
pub fn add_observer(&mut self, observer: Rc<RefCell<Box<dyn Observer + 's>>>) {
self.listeners.push(observer)
}
pub fn notify(&mut self) {
for listener in &mut self.listeners {
listener.borrow_mut().notify();
}
}
}
#[cfg(test)]
mod test {
use super::{wrap, Observer, Subject};
#[derive(Default)]
pub struct Counter {
count: usize,
}
impl Observer for Counter {
fn notify(&mut self) {
self.count += 1;
}
}
#[test]
fn it_observes() {
let mut subject = Subject::default();
let counter = wrap(Counter::default());
subject.add_observer(counter); // mismatched types
for i in 1..5 {
subject.notify();
subject.notify();
assert_eq!(counter.borrow().count, i * 2);
}
}
}
The full error is
error[E0308]: mismatched types
--> src/observer.rs:48:30
|
48 | subject.add_observer(counter);
| ^^^^^^^ expected trait object `dyn Observer`, found struct `Counter`
|
= note: expected struct `Rc<RefCell<Box<(dyn Observer + 'static)>>>`
found struct `Rc<RefCell<Box<Counter>>>
I've seen (what looks like) this pattern used in a number of contexts, but I can't tell what either I'm missing or doing differently.
How do I get the T: Trait out of its static dispatch and into dynamic dispatch?
You can take to boxing outside of your wrap function, and box the counter itself with the proper box type:
pub fn wrap<T>(t: T) -> Rc<RefCell<T>> {
Rc::new(RefCell::new(t))
}
...
let counter: Box<dyn Observer> = Box::new(Counter::default());
let counter = wrap(counter);
Playground
Btw, once you have the dynamic dispatch, you have an dyn Observer so you lose access to the Counter itself. You will have to take ownership of it and downcast the pointer to the concrete type again.
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) {
//
}
}
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();
}
I'm trying to implement an Iron handler that contains a reference to another struct. That struct holds the data and does all operations on the data.
[package]
name = "testcrate"
version = "0.1.0"
authors = ["me"]
[dependencies]
iron = "^0.2"
This is the code:
//! Handlers for the server.
extern crate iron;
use iron::{status, middleware};
use iron::IronResult;
use iron::prelude::Set;
use iron::request::Request;
use iron::response::Response;
/// The MyServer struct holds the data and provides methods
/// to manipulate or retrieve that data.
struct MyServer;
impl MyServer {
pub fn build_response() -> String {
"response".to_string()
}
}
/// The ReadHandler handles the creation of HTTP responses.
pub struct ReadHandler {
pub server: &MyServer,
}
impl middleware::Handler for ReadHandler {
/// Return the current status JSON.
fn handle(&self, req: &mut Request) -> IronResult<Response> {
let body = self.server.build_response();
let response = Response::with((status::Ok, body));
Ok(response)
}
}
Unfortunately I'm getting errors about missing lifetime specifiers:
src/lib.rs:22:17: 22:26 error: missing lifetime specifier [E0106]
src/lib.rs:22 pub server: &MyServer,
^~~~~~~~~
src/lib.rs:22:17: 22:26 help: run `rustc --explain E0106` to see a detailed explanation
But when I add lifetime specifiers (which I didn't fully understand yet)...
pub struct ReadHandler<'a> {
pub server: &'a MyServer,
}
impl<'a> middleware::Handler for ReadHandler<'a> {
// ...
}
...I get another error message:
src/lib.rs:24:1: 32:2 error: the type `ReadHandler<'a>` does not fulfill the required lifetime
src/lib.rs:24 impl<'a> middleware::Handler for ReadHandler<'a> {
src/lib.rs:25
src/lib.rs:26 /// Return the current status JSON.
src/lib.rs:27 fn handle(&self, req: &mut Request) -> IronResult<Response> {
src/lib.rs:28 let body = self.server.build_response();
src/lib.rs:29 let response = Response::with((status::Ok, body));
...
note: type must outlive the static lifetime
There will be other handlers that will access the MyServer in a read-only or read-write mode.
What would be the correct way to add lifetime specifiers? Or do I maybe need a structure like an Arc?
The Handler trait is a subtrait of Any:
pub trait Handler: Send + Sync + Any {
fn handle(&self, &mut Request) -> IronResult<Response>;
}
And the Any trait has a 'static lifetime bound:
pub trait Any: Reflect + 'static {
fn get_type_id(&self) -> TypeId;
}
The 'static bound means that your struct cannot contain references. You'll have to use another type of pointer. Since Handler is also a subtrait of Send and Sync, you'll need to use Arc, since Rc is neither Send nor Sync.