This question already has answers here:
Sending trait objects between threads in Rust
(1 answer)
Sharing a struct with trait objects as properties across threads
(1 answer)
How to clone a struct storing a boxed trait object?
(3 answers)
How do I clone a HashMap containing a boxed trait object?
(1 answer)
Closed 3 years ago.
I've been struggling with this for a while now and just going in circles, so I'm hoping someone can point out where I'm going wrong.
I'm playing with Actix Web, and setting up my first handlers - which is a simple Healthcheck of the system. So what I've got is:
A Healthcheck trait defining a healthcheck
A HealthcheckHandler struct that implements the Handler trait (This is an Actix Web concept) and contains a HashMap
A function that builds an App instance for the healthcheck routes (This is an Actix Web concept) by taking a HashMap<String, &Healthcheck>
When I try to build this I get errors that the trait "cannot be sent between threads safely".
I've tried with &Healthcheck, Box<Healthcheck>, Box<Healthcheck + Send> based on another answer on here, and even Mutex<&Healthcheck> all without luck, but all with subtly different errors. It all seems to be around needing to implement some combinations of Sync, Send and/or Clone, but I'm not sure how to get around that here.
Any pointers to what I should to fix this?
Actual example code:
pub trait Healthcheck {
fn check(&self) -> Result<String, String>;
}
struct HealthcheckHandler {
handlers: HashMap<String, Box<Healthcheck>>,
}
pub fn build_app(handlers: HashMap<String, Box<Healthcheck>>) -> App<()> {
let handler = HealthcheckHandler {
handlers: handlers,
};
App::new()
.prefix("/health")
.resource("", |r| {
r.get().h(handler);
})
}
pub fn start(settings: HashMap<String, String>) {
let mut healthchecks: HashMap<String, Box<Healthcheck>> = HashMap::new();
let server = server::new(|| { // <-- This is where the errors happen. This closure is used to spawn threads.
vec![
build_app(healthchecks).middleware(middleware::Logger::default())
]
});
}
Cheers
Related
This question already has an answer here:
How can a function append a value to a vector and also return that value?
(1 answer)
Closed 2 years ago.
I am trying to add an item to a Vec<T>, call a function and await it. I am still wrapping my head around the ownership and borrow rules. I understand the below won't work:
pub async fn begin_session(&mut self, stream: TcpStream) {
let session = Session::new(stream);
self.sessions.push(session);
session.start_receiver().await; // obviously, won't work
}
The solution that I came up with below doesn't seem ideal (or thread-safe) to me:
pub async fn begin_session(&mut self, stream: TcpStream) {
let session = Session::new(stream);
self.sessions.push(session);
let session = self.sessions.last().unwrap();
session.start_receiver().await; // That works.
}
Is there a function in Vec<T> that does a push(T) and also returns T?
just doesn't seem ideal (or thread-safe) to me
It might not be ideal if the optimizer does not realize that the unwrap() will always be successful.
However, thread-safety does not play a role here: if you are planning to share the Vec or your Self later on, you will have to take care of that somehow.
Is there a function in Vec that does a push(T) and then also return T?
If it were there, then such a method would most likely return a &T or a &mut T which you can then copy or clone if needed. Other people may prefer to return the index instead. There are many possibilities depending on what you exactly need.
Whatever is best for your project, remember that you can add the method yourself to Vec. For instance:
trait PushReturn<T> {
fn push_return(&mut self, t: T) -> &mut T;
}
impl<T> PushReturn<T> for Vec<T> {
fn push_return(&mut self, t: T) -> &mut T {
self.push(t);
self.last_mut().unwrap()
}
}
This seems like a good case in which to use reference-counted objects in the form of std::rc::Rc.
Your code might end up looking something like this:
pub async fn begin_session(&mut self, stream: TcpStream) {
let session = Rc::new(Session::new(stream));
self.sessions.push(Rc::clone(&session));
&session.start_receiver().await;
}
When you clone an Rc, you're just cloning the reference to the object, and increasing the reference count. You're not cloning the object itself.
Disclaimer: I, too, am just learning Rust. It would be good to get a second opinion on this.
This question already has answers here:
Why can't I store a value and a reference to that value in the same struct?
(4 answers)
How to return a reference to a sub-value of a value that is under a mutex?
(5 answers)
Returning a RWLockReadGuard independently from a method
(2 answers)
How can I store a Chars iterator in the same struct as the String it is iterating on?
(2 answers)
Closed 3 years ago.
I would like to wrap a low-level third-party API with my own struct and functions to make it more friendly. Unfortunately, the third-party API needs a reference to a socket in its constructor, which means I'd like my Struct to "own" the socket (someone has to own it so that it can be borrowed, right? and I'd like that hidden as an implementation detail in my API).
The third-party API looks something like this:
struct LowLevelApi<'a> {
stream: &'a mut TcpStream,
// ...
}
impl<'a> LowLevelApi<'a> {
pub fn new(socket: &'a mut TcpStream, ... ) -> LowLevelApi<'a> {
// ...
}
}
I would like to make the interface to my function look like:
pub fn new(host: String, port: u16, ...) -> HighLevelApi {
// ...
}
I tried this:
pub struct HighLevelApi<'a> {
stream: TcpStream,
low: LowLevelApi<'a>
}
impl <'a> HighLevelApi<'a> {
pub fn new(host: String, port: u16) -> HighLevelApi<'a> {
// Ignore lack of error checking for now
let mut stream = TcpStream::connect(format!("{}:{}", host, port)).unwrap();
HighLevelApi {
stream,
low: LowLevelApi::new(&mut stream)
}
}
}
Rust is (rightly) angry: It has no way of knowing that I'm not going to do something bad with the low field later. And even worse, I would need to somehow guarantee that when my structure gets dropped, low gets dropped first, and stream second (since by that point, any relationship between the two is lost - or rather, there never is/was a relationship between the two).
(actually, it's worse than that, because the stream local variable gets moved into the new struct, so the local can't possibly be borrowed by LowLevelApi, but I can't think of a way to initialize HighLevelApi with the stream from the struct, since there's no way to get a handle to that from within the struct's initialization, is there? But based on my guess about what would happen in the paragraph above, it doesn't really matter since it still wouldn't do what I wanted)
What are examples of the various techniques that can be used to store a wrap a third-party (not under my control) struct that needs a reference to something?
The Rental crate seems to do what is needed here, albeit with documentation and examples that leave a lot to the imagination (i.e. trial and error).
Here's roughly what solves this
rental! {
pub mod rentals {
#[rental_mut]
pub struct Wrapper {
stream: Box<TcpStream>,
low: LowLevelApi<'stream>
}
}
}
pub struct HighLevelApi {
wrapper: rentals::Wrapper
}
impl HighLevelApi {
pub fn new(host: String, port: u16) -> HighLevelApi {
Api {
// Ignore lack of error checking for now
wrapper: rentals::Wrapper::new(
Box::new(TcpStream::connect(format!("{}:{}", host, port)).unwrap()),
|s| LowLevelApi::new(s)
)
}
}
pub fn do_something(&mut self) {
self.wrapper.rent_mut(|ll| ll.do_something()) // ll is the LowLevelApi
}
}
I noticed two important things that made this work:
The lifetime name on low in the Wrapper struct must match the name of the "owning" field (in this case "'stream")
You never get direct access to the reference - you get it through a callback/closure:
In the auto-generated constructor (new()) the second parameter isn't a LowLevelApi, it's a closure that gets the &mut TcpStream, and that closure is then expected to return a LowLevelApi
When you want to actually use the LowLevelApi you can "rent" it, hence the wrapper.rent_mut(f) where f is the closure that gets passed a LowLevelApi (ll) and can do what it needs
With these facts, the rest of the Rental documentation makes a lot more sense.
This question already has answers here:
Why are borrows of struct members allowed in &mut self, but not of self to immutable methods?
(2 answers)
cannot borrow `self.x` as immutable because `*self` is also borrowed as mutable
(1 answer)
How can I call a mutating method while holding a reference to self?
(1 answer)
Is it possible to borrow parts of a struct as mutable and other parts as immutable?
(2 answers)
Passing mutable self reference to method of owned object
(2 answers)
Closed 3 years ago.
This question is not about why the compiler gives these errors — I think I understand that. This question is about how to manage the situation on the mutable path while hoping to be able to call other functions.
This is a simplification of what I am trying to do. I have a lot of Foos inside World and I need to update them based on other data from World. I have several private functions inside World that I would like to be able to call.
pub struct Foo {
id: i32,
//...
}
pub struct Bar {
//...
}
pub struct World {
foos: Vec<Foo>,
bars: Vec<Bar>,
//...
}
impl World {
pub fn create() -> World {
World {
foos: Vec::new(),
bars: Vec::new(),
}
}
pub fn update(&mut self) {
for foo in self.get_foos_mut() {
//error[E0XXX]: cannot borrow `*self` as mutable/imutable ...
let _bar = self.get_bar_given_foo(foo);
//alter foo based on bar and other world things calling other world functions...
//...
}
}
//some useful utility functions that should be called several times
//from different World places...
fn get_foos_mut(&mut self) -> &mut [Foo] {
//select slice interval based on foos or any other calculation using self data...
&mut self.foos[..]
}
fn get_bar_given_foo(&self, foo: &Foo) -> &Bar {
//select bar based on foo or any other calculation using self data...
&self.bars[foo.id as usize]
}
//other utility functions that abstract e sequence of operations that I would
//like to use on the update path...
}
fn main() {
let mut world = World::create();
world.update();
}
You can also run the code.
It looks a very limiting situation because when on a mutable path like the update function, I am unable to call any of the private methods from self.
Since I don't want to clone all the data, I could think of three solutions. I tried 1 and 2 and both work.
Inline everything. Since this solution works for the example above, it looks like the compilation error is caused by the limitation of the Rust compiler that as I understand: it just looks the function signature and not the implementation of the functions.
Create functions that receive references to what they need. There is no need borrow self again. The function World::get_foos_mut(&mut self) -> &mut [Foo] could be removed and created a new one outside World: fn world_get_foos_mut(foos: &mut Vec<Foo>) -> &mut [Foo] The code on the playground shows this solution.
Create macros instead of regular functions? Since they are macros I suspect that there won't be any borrow involved. Since I am not familiar with macros I am unable to tell if this works or how to do this yet.
I really need other options because Solution 1 is not viable in my opinion and solution 2 looks very cumbersome and fragile (it looks that I might have the same problems but with the references inside World).
I am really frustrated about not being able to find the correct model to handle this.
Will the Rust compiler try to analyze these situations in the future?
This question already has answers here:
Is there a way other than traits to add methods to a type I don't own?
(2 answers)
How can I add new methods to Iterator?
(1 answer)
Closed 4 years ago.
I have a struct that is used by different functions. Instead of passing the struct as input to the different functions, I think I can implement the struct with all the functions that need to access it. However, there are certain fixed basic functions that I want to provide so that whenever the struct is created, I don't have to implement the same set of functions over and over again.
Put in another way, what I really want is the struct inheritance: I have certain set of methods associated with struct and user can add their custom functions to struct and allow them to access the data contained in data. Is there anyway able to do so?
Concretely, suppose I have a struct called AppContext and the fixed set of functions are new and bdev_name:
pub struct AppContext {
bdev: *mut raw::spdk_bdev,
bdev_desc: *mut raw::spdk_bdev_desc,
bdev_io_channel: *mut raw::spdk_io_channel,
buff: *mut c_char,
bdev_name: *const c_char,
}
impl AppContext {
pub fn new() -> Self {
let context: AppContext;
unsafe {
context = mem::uninitialized();
}
context
}
pub fn bdev_name(&mut self, name: &str) {
self.bdev_name = CString::new(name)
.expect("Couldn't create a string")
.into_raw()
}
}
Now, when I use this struct, I do:
let mut context = AppContext::new();
context.bdev_name("Nvme0n1");
I want to add one extra function (say end()) that can work on the data within the context struct. However, end() is very domain specific function and needed in a specific module, and thus it's not a good idea to implement as part of the context struct.
Is there any way I can workaround the issue (i.e. add custom function to predefined struct)?
This question already has answers here:
How do I create a global, mutable singleton?
(7 answers)
How do I keep internal state in a WebAssembly module written in Rust?
(2 answers)
Closed 4 years ago.
I'm attempting to write a data store in Rust that receives objects from JavaScript across the wasm-bindgen boundary and stores them for later retrieval. This is a simplified version of what I was hoping would work:
static mut MAP: HashMap<i32, String> = HashMap::new();
#[wasm_bindgen]
pub fn add_value(index: i32, value: String) {
unsafe {
MAP.insert(index, value);
}
}
#[wasm_bindgen]
pub fn get_value(index: i32) -> String {
unsafe {
(*MAP.get(&index).unwrap()).clone()
}
}
However I get this error from the Rust compiler:
error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
How can I store state so that subsequent calls across the wasm-bindgen boundary can retrieve previously stored values?