Why isn't a Box automatically Sized? [duplicate] - rust

This question already has answers here:
What does "Sized is not implemented" mean?
(2 answers)
Why is the `Sized` bound necessary in this trait?
(2 answers)
How do you create a Box<dyn Trait>, or a boxed unsized value in general?
(3 answers)
Closed 5 years ago.
I am trying to implement a server using Mio and a reactor pattern. I want my Reactor to handle both TcpListeners and TcpStreams, so abstracting over that is my real challenge here.
I have a trait ReAgent that implements various handlers for informing the Reactor about changes in status, while Reactor informs each individual ReAgent about events important to that ReAgent. In turn, I'll have two different ReAgent types, one for accepting (TcpListeners) which will spawn clients (TcpStreams) to pass back to the Reactor for event handling. A very standard Reactor pattern for multiple server endpoints; I've written half a dozen of these in C/C++ over my career. Eliding details about my TokenPool, etc., here's where my headache lies:
pub struct Reactor<'a> {
poll: Poll,
agents: HashMap<Token, Box<ReAgent + 'a>>,
tokens: TokenPool,
}
impl<'a> Reactor<'a> {
pub fn add_agent<R: ReAgent + 'a>(&mut self, mut agent: Box<R>) -> Result<()>
{
if let Some(next_token) = self.tokens.pop() {
agent.set_token(next_token);
self.agents.insert(agent.get_token(), agent);
return Ok(())
}
bail!(ErrorKind::ConnectionsExhausted)
}
}
//...
/// Received a Box<ReAgent> (a Client);
/// add and start conversation
Some(boxed_agent) => self.add_agent(boxed_agent)
When I compile this, I get:
Some(boxed_agent) => self.add_agent(boxed_agent)
^^^^^^^^^ `reagent::ReAgent` does not have a constant size known at compile-time
... which I don't get at all. It's a Box. A Box has a known constant size at compile time. That's the whole point here of using Box to support a dynamic type object, right? The client has a known size, it's a concrete implementation of ReAgent.
What am I missing?
I know I'll probably have to use a RefCell later, since I'm mutating the ReAgent to set its polling token; that's for later, I just want to get past this.

Related

Pass a String parameter to several threads in Rust [duplicate]

This question already has an answer here:
Sharing String between threads in Rust
(1 answer)
Closed 2 years ago.
I have a struct like this:
pub struct Connector {
host: String,
executor: ThreadPool,
}
This struct features a method, that dispatches work (TCP-connections) on several threads via TcpStream::connect().
Unfortunately I got an error when referencing a field of a struct.
self.executor.execute(move || {
if let Ok(_) = TcpStream::connect((self.host.as_str(), 8080)) {
println!("Connection established");
//...
}
});
This code above leads to following error message:
std::sync::mpsc::Sender<std::boxed::Box<(dyn threadpool::FnBox + std::marker::Send + 'static)>>` cannot be shared between threads safely
I have also tried to make the host-field a &'static str, but since this is data from external input this does not work (I can't transform a String-object into a 'static str).
How can I insert the struct's field into its threads as parameters?
Edit: Creating a new variable inside the scope leads to:
creates a temporary which is freed while still in use
In your code you're not passing a String parameter; you're passing a &str parameter. Since you're effectively passing it to a different thread, the Rust compiler cannot check whether the reference will live long enough. Passing a &'static str would indeed have been a good solution if the string was actually static, but if that's not the case, you have to pass something that's owned.
In this case, the answer is somewhat complicated by the fact that TcpStream::connect() likely accepts a T: ToSocketAddrs and what works will depend on what impls exist for ToSocketAddrs. For example, tokio's ToSocketAddrs is implemented for (&'_ str, u16) but not for (String, u16). It is implemented for String, though, so perhaps the simplest solution here is to build a String and allow the closure to take ownership of that String, along these lines:
let addr = format!("{}:{}", &self.host, 8080);
self.executor.execute(move || {
if let Ok(_) = TcpStream::connect(addr) {
println!("Connection established");
//...
}
});

Constructing and returning a struct with custom &str members [duplicate]

This question already has answers here:
Return local String as a slice (&str)
(7 answers)
Proper way to return a new string in Rust
(2 answers)
Is there any way to return a reference to a variable created in a function?
(5 answers)
Why can't I store a value and a reference to that value in the same struct?
(4 answers)
Closed 2 years ago.
I'm working with an external type (i.e., not my code), that has a bunch of &str members:
#[derive(Default, Clone)]
pub struct SomeExternalThingie<'a> {
pub name: &'a str,
pub description: Option<&'a str>,
pub author: Option<&'a str>,
}
I want to make my own function which constructs and returns one of these things. I want to dynamically construct some of the strings used as members:
fn my_func_to_make_a_thingie<'a>(name: &'a str) -> MyThingie<'a> {
let mydesc = format!("Hi, I'm your friendly neighborhood {}!",
name);
SomeExternalThingie {
name: name,
description: Some(mydesc.as_str()),
..Default::default()
}
}
Of course, this won't compile, because the lifetime of mydesc ends when the function does. What's the best practice for dealing with a situation like this? I'm obviously new to Rust, but it seems like this will be a common scenario.
My only thought to change the return type to return both the desired structure and the storage for the string(s)... either by returning a tuple, or making a custom struct. This feels awkward, though, and I was wondering if there was a better way, or at least a convention of sorts.
For some context - the actual use case that prompted this was that I wanted to return a clap::App object. I wanted to do this mostly for organizational reasons - I know that in this case I can just include it in my main function, without the sub-function (even though it makes it longer than I'd like), and I'll probably end up doing this. However, this seems like a common pattern, and I wanted to learn the "Rust way" to deal with this.

Share function reference between threads in Rust [duplicate]

This question already has answers here:
Sending trait objects between threads in Rust
(1 answer)
How can I pass a reference to a stack variable to a thread?
(1 answer)
Closed 3 years ago.
I want to share a function reference between threads but the Rust compiler says `dyn for<'r> std::ops::Fn(&'r std::string::String) -> std::string::String` cannot be shared between threads safely. I'm well informed about Send, Sync, and Arc<T> when sharing "regular" values between threads but in this case I can't understand the problem. A function has a static address during the runtime of the program, therefore I can't see a problem here.
How can I make this work?
fn main() {
// pass a function..
do_sth_multithreaded(&append_a);
do_sth_multithreaded(&identity);
}
fn append_a(string: &String) -> String {
let mut string = String::from(string);
string.push('a');
string
}
fn identity(string: &String) -> String {
String::from(string)
}
fn do_sth_multithreaded(transform_fn: &dyn Fn(&String) -> String) {
for i in 0..4 {
let string = format!("{}", i);
thread::spawn(move || {
println!("Thread {}: {}", i, transform_fn(&string))
});
}
}
A function has a static address during the runtime of the program, therefore I can't see a problem here.
That's nice for functions, but you're passing a &dyn Fn, and that could just as well be a closure or (in unstable Rust) a custom object implementing that trait. And this object might not have a static address. So you can't guarantee that the object will outlive the threads you spawn.
But that's not even what the compiler is complaining about (yet!). It's actually complaining that it doesn't know whether you're allowed to access the Fn from another thread. Again, not relevant for function pointers, but relevant for closures.
Here's a signature that works for your example:
fn do_sth_multithreaded(transform_fn: &'static (dyn Fn(&String) -> String + Sync))
Note the 'static lifetime bound and the Sync bound.
But while the static lifetime works for this case, it probably means you can't ever send closures. To make that work, you need to use a scoped thread system (for example, from the crossbeam crate) to make sure do_sth_multithreaded waits for the threads to finish before returning. Then you can relax the static lifetime bound.

How do I access struct fields within default method definitions of traits? [duplicate]

This question already has answers here:
Is it possible to access struct fields from within a trait?
(3 answers)
Implementing a trait for multiple types at once
(4 answers)
Closed 3 years ago.
I see some related questions (like this and this) but I'm hoping that my use case for default methods is unique enough to ask a slightly different question. The following minimal example works and outputs "Sheriff Ted" shot "Billy the Kid"!:
#[derive(Debug)]
struct Actor {
name: String,
}
fn main() {
let cop = Actor {
name: String::from("Sheriff Ted"),
};
let robber = Actor {
name: String::from("Billy the Kid")
};
println!("{:?} shot {:?}!", cop.name, robber.name); // without the trait. with:
// cop.shoot(&robber);
}
//pub trait Shoot {
// fn shoot(&self, other: &Actor) {
// println!("\n{:?} shot {:?}!",
// &self.name,
// &other.name,
// )
// }
//}
//
//impl Shoot for Actor {}
As you can see, I want impart the Shoot implementation and the shoot method it contains on the Actor struct. When I uncomment the Shoot trait, its implementation on Actor, and the call cop.shoot(&robber), I get the error message related questions have gotten, as well: error[E0609]: no field 'name' on type '&Self'.
My first thought was to specify &self: Actor in the default method's signature, but that yields the delimiter error, so isn't syntactically valid.
I think this question is unique because the other questions seem to misunderstand how the generics they specify are shadowing their intended types, and in my case I'm not understanding why I can't access fields within the structs on which I am trying to implement a default method.
This works for cases when only Actors need to shoot, but I am looking for a way to apply this behavior (right now, just printlning) across multiple types.
impl Actor {
fn shoot(&self, other: &Actor) {
println!("\n{:?} shot {:?}!",
self.name,
other.name,
)
}
}
You are not trying to implement a default method on any structs; you are implementing it for the trait. Therefore you can't access any fields on any structs; you can only access what the trait demands.
A default implementation of a trait methods means that any type that implements the non-defaulted methods of the trait can use the default method, no matter what it looks like otherwise. But you expect that the implementing type has a name field in addition to what the trait demands (it demands nothing, by the way).
This is simply not a valid assumption.
I wonder why you're using a trait here at all. If you are okay with requiring self to be Actor in the shoot method, why is it a method of a trait? Why isn't it an inherent method of the Actor struct without any traits?
After having read Sebastian's response, I think the "answer" is: you can't name struct fields in traits' default methods because you don't know what fields a struct may have until the implementation of the trait. So you'd define an (abstract?) method signature, and then make it concrete when it's implemented. In my case, this works:
trait Shoot {
fn shoot(&self, other: &Actor);
}
impl Shoot for Actor {
fn shoot(&self, other: &Actor) {
println!("\n{:?} shot {:?}!",
self.name,
other.name,
);
}
}
Still interested to know if I can constrain a trait to be applied only to structs with certain fields and if this is different than "trait bounds". (It is, I think...)

Rust - Passing Trait Objects to Threads [duplicate]

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

Resources