I have the following struct:
#[derive(Default)]
pub struct AppState {
actors: HashMap<String, ActorValue>,
feature: HashMap<String, FeatureValue>,
}
Actors are registered when running the application upon receiving a network request (i.e., they are inserted into the HashMap). Furthermore, a user can create a new feature for which a certain actor may be required.
pub enum ActorValue {
Automotive(AutomotiveActor),
Power(PowerActor),
}
pub enum FeatureValue {
Automotive(AutomotiveFeature),
// ....
}
pub struct AutomotiveFeature {
pub actor_name: String,
// ... more Actor-related String fields
}
pub struct AutomotiveActor {
name: String,
// ... more String fields
}
So, when creating an instance of AutomotiveFeature I am currently cloning the name of the respective AutomotiveActor instance to populate the actor_name:
let automotive_actor = app_state.actors.iter()
.find(|x| matches!(x.1, ActorValue::Automotive(_)))
.map(|x| match x.1 {
ActorValue::Automotive(p) => Some(p),
_ => None,
})
.flatten();
match automotive_actor {
Some(a) => {
let feature = AutomotiveFeature { actor_name: a.name.clone() };
}
None => {}
}
However, I am essentially keeping redundant info. Ideally, I could just replace all the String fields relating to the actor in the feature with a reference:
pub struct AutomotiveFeature {
pub actor: &AutomotiveActor
}
But I am getting lifetime issues and I don't know how I can annotate them correctly, considering I have two HashMaps.
If I use:
pub struct AutomotiveFeature {
pub actor: &'static AutomotiveActor
}
I get the following errors:
error[E0502]: cannot borrow `*state` as mutable because it is also borrowed as immutable
--> crates/code/src/my_code.rs:146:13
|
38 | let automotive_actor: Option<&AutomotiveActor> = app_state
| __________________________________________________-
39 | | .actors()
| |_____________________________- immutable borrow occurs here
...
43 | ActorValue::Automotive(p) => Some(p),
| ------- returning this value requires that `*state` is borrowed for `'static`
...
146 | / app_state
147 | | .features_mut()
| |____________________________^ mutable borrow occurs here
error: lifetime may not live long enough
--> crates/code/src/my_code.rs:43:40
|
35 | app_state: &mut AppState,
| - let's call the lifetime of this reference `'1`
...
43 | ActorValue::Automotive(p) => Some(p),
| ^^^^^^^ returning this value requires that `'1` must outlive `'static`
I have already looked at similar post, such as "Store reference of struct in other struct". Unfortunately, I cannot use std::rc::Rc; because I get the error:
`Rc<AutomotiveActor>` cannot be sent between threads safely
I am getting lifetime issues and I don't know how I can annotate them correctly"
Note that you can only explain to the compiler how long something lives. You can't actually make an object live longer by annotating a lifetime. References do not own an object or keep it alive. Rc/Arc actually keep an object alive, so I have a suspicion that this is what you want.
The reason I want to have a reference is that I can then implement methods as part of AutomotiveActor and then directly call automotive_actor.start_car()
I suspect that start_car() modifies the automotive_actor and is therefore a mut fn. This completely renders your initial idea of using references impossible, because you can only ever have one mutable reference to an object.
Rc/Arc also only provide immutable access to the object, but you can combine them with RefCell/Mutex to create interior mutability.
Rc<AutomotiveActor> cannot be sent between threads safely
This makes me assume that your project is multi-threaded and therefore requires thread safety. This means you probably want to use Arc<Mutex>.
This is one possible layout:
use std::{
collections::HashMap,
sync::{Arc, Mutex},
};
#[derive(Default)]
pub struct AppState {
actors: HashMap<String, ActorValue>,
feature: HashMap<String, FeatureValue>,
}
pub enum ActorValue {
Automotive(Arc<Mutex<AutomotiveActor>>),
//Power(PowerActor),
}
pub enum FeatureValue {
Automotive(AutomotiveFeature),
// ....
}
pub struct AutomotiveFeature {
pub actor: Arc<Mutex<AutomotiveActor>>,
// ... more Actor-related String fields
}
pub struct AutomotiveActor {
name: String,
// ... more String fields
}
fn main() {
let mut app_state = AppState::default();
let new_actor = Arc::new(Mutex::new(AutomotiveActor {
name: String::from("MyActor"),
}));
app_state.actors.insert(
new_actor.lock().unwrap().name.clone(),
ActorValue::Automotive(Arc::clone(&new_actor)),
);
let automotive_actor = app_state
.actors
.iter()
.find(|x| matches!(x.1, ActorValue::Automotive(_)))
.map(|x| match x.1 {
ActorValue::Automotive(p) => Some(p),
_ => None,
})
.flatten();
match automotive_actor {
Some(a) => {
let feature = AutomotiveFeature {
actor: Arc::clone(a),
};
}
None => {}
}
}
Related
I would like to return binary data in chunks of specific size. Here is a minimal example.
I made a wrapper struct for hyper::Response to hold my data like status, status text, headers and the resource to return:
pub struct Response<'a> {
pub resource: Option<&'a Resource>
}
This struct has a build method that creates the hyper::Response:
impl<'a> Response<'a> {
pub fn build(&mut self) -> Result<hyper::Response<hyper::Body>, hyper::http::Error> {
let mut response = hyper::Response::builder();
match self.resource {
Some(r) => {
let chunks = r.data
.chunks(100)
.map(Result::<_, std::convert::Infallible>::Ok);
response.body(hyper::Body::wrap_stream(stream::iter(chunks)))
},
None => response.body(hyper::Body::from("")),
}
}
}
There is also another struct holding the database content:
pub struct Resource {
pub data: Vec<u8>
}
Everything works until I try to create a chunked response. The Rust compiler gives me the following error:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:14:15
|
14 | match self.resource {
| ^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the lifetime `'a` as defined on the impl at 11:6...
--> src/main.rs:11:6
|
11 | impl<'a> Response<'a> {
| ^^
note: ...so that the types are compatible
--> src/main.rs:14:15
|
14 | match self.resource {
| ^^^^^^^^^^^^^
= note: expected `Option<&Resource>`
found `Option<&'a Resource>`
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that the types are compatible
--> src/main.rs:19:31
|
19 | response.body(hyper::Body::wrap_stream(stream::iter(chunks)))
| ^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected `From<&[u8]>`
found `From<&'static [u8]>`
I don't know how to fulfill these lifetime requirements. How can I do this correctly?
The problem is not in the 'a itself, but in the fact that the std::slice::chunks() function returns an iterator that borrows the original slice. You are trying to create a stream future from this Chunks<'_, u8> value, but the stream requires it to be 'static. Even if your Resource did not have the 'a lifetime, you would still have the r.data borrowed, and it would still fail.
Remember that here 'static does not mean that the value lives forever, but that it can be made to live as long as necessary. That is, the future must not hold any (non-'static) borrows.
You could clone all the data, but if it is very big, it can be costly. If so, you could try using Bytes, that is just like Vec<u8> but reference counted.
It looks like there is no Bytes::chunks() function that returns an iterator of Bytes. Fortunately it is easy to do it by hand.
Lastly, remember that iterators in Rust are lazy, so they keep the original data borrowed, even if it is a Bytes. So we need to collect them into a Vec to actually own the data (playground):
pub struct Resource {
pub data: Bytes,
}
impl<'a> Response<'a> {
pub fn build(&mut self) -> Result<hyper::Response<hyper::Body>, hyper::http::Error> {
let mut response = hyper::Response::builder();
match self.resource {
Some(r) => {
let len = r.data.len();
let chunks = (0..len)
.step_by(100)
.map(|x| {
let range = x..len.min(x + 100);
Ok(r.data.slice(range))
})
.collect::<Vec<Result<Bytes, std::convert::Infallible>>>();
response.body(hyper::Body::wrap_stream(stream::iter(chunks)))
}
None => response.body(hyper::Body::from("")),
}
}
}
UPDATE: We can avoid the call to collect() if we notice that stream::iter() takes ownership of an IntoIterator that can be evaluated lazily, as long as we make it 'static. It can be done if we do a (cheap) clone of r.data and move it into the lambda (playground):
let data = r.data.clone();
let len = data.len();
let chunks = (0..len).step_by(100)
.map(move |x| {
let range = x .. len.min(x + 100);
Result::<_, std::convert::Infallible>::Ok(data.slice(range))
});
response.body(hyper::Body::wrap_stream(stream::iter(chunks)))
The following is MVP of what I am doing
use std::sync::Arc;
use clokwerk::Interval::*;
use clokwerk::TimeUnits;
use std::time::Duration;
use std::thread;
#[derive(Clone, Debug)]
pub struct Person {
pub name: String,
pub age: u16,
}
pub fn print_debug_person(person_arc: Arc<Person>) {
println!("Person is :{:?}", person_arc)
}
fn main() {
let p = Person { name: "Asnim".to_string(), age: 10 };
let p = Arc::new(p);
let mut scheduler = clokwerk::Scheduler::new();
for loop_period in 1..5 {
let person_arc = p.clone();
scheduler.every(loop_period.seconds()).run(move || print_debug_person(person_arc));
}
loop {
scheduler.run_pending();
thread::sleep(Duration::from_millis(10));
}
}
Here the code fails with error
error[E0507]: cannot move out of `person_arc`, a captured variable in an `FnMut` closure
--> src/main.rs:27:79
|
26 | let person_arc = p.clone();
| ---------- captured outer variable
27 | scheduler.every(loop_period.seconds()).run(move || print_debug_person(person_arc));
| ^^^^^^^^^^ move occurs because `person_arc` has type `Arc<Person>`, which does not implement the `Copy` trait
What am I doing wrong here. What change should I make so that arc can be passed to this function?
Isn't Arc the right structure to use?
I wont able able add Copy trait to the struct as String doesn't implement Copy trait. Right?
Dependencies
clokwerk = "0.3.5"
The function print_debug_person takes ownership of the value given to it, so calling it with person_arc will attempt to move it. However, since the closure is intended to be called multiple times, this would leave the value invalid for future calls.
To fix this, you can either make a new Arc<Person> each time by cloning it:
scheduler.every(loop_period.seconds()).run(move || print_debug_person(person_arc.clone()));
Or, since your function doesn't seem to need ownership, it should just borrow the Person:
pub fn print_debug_person(person: &Person) {
println!("Person is :{:?}", person)
}
Which you can call with a &Arc<Person> due to deref coercion:
scheduler.every(loop_period.seconds()).run(move || print_debug_person(&person_arc));
This question already has answers here:
Why does refactoring by extracting a method trigger a borrow checker error?
(2 answers)
Closed 3 years ago.
I struggle with iterator which also mutates other fields of it's owner.
I've re-created a simplified example Playground:
#[derive(PartialEq)]
enum ResourceEnum {
Food,
}
struct Resource {
r#type: ResourceEnum,
amount: u32,
}
trait Building {
fn produce(&self) -> Option<Resource>;
}
struct Farm {}
struct City {
buildings: Vec<Box<dyn Building>>,
resources: Vec<Resource>,
}
impl City {
fn add_resource(&mut self, received: Option<Resource>) {
if let Some(received) = received {
if let Some(mut res) = self
.resources
.iter_mut()
.find(|r| r.r#type == received.r#type)
{
res.amount += received.amount;
} else {
self.resources.push(received);
}
}
}
}
impl Building for Farm {
fn produce(&self) -> Option<Resource> {
Some(Resource {
r#type: ResourceEnum::Food,
amount: 10,
})
}
}
fn main() {
let mut city = City {
buildings: vec![],
resources: vec![],
};
city.buildings.iter().for_each(|f| {
city.add_resource(f.produce());
});
}
Error:
error[E0502]: cannot borrow `city` as mutable because it is also borrowed as immutable
--> src/main.rs:55:36
|
53 | city.buildings.iter().for_each(|f| {
| -------------- -------- ^^^ mutable borrow occurs here
| | |
| | immutable borrow later used by call
| immutable borrow occurs here
54 | city.add_resource(f.produce());
| ---- second borrow occurs due to use of `city` in closure
What I'm trying to achieve is to have a single struct holding my 'world' -> City, which holds buildings like farms and all it's available resources like food.
At each state update I want to compute harvest from all farms and so on... and add produced resources into City storage, but can't figure out a way without storing all production as a separate Vector and iterating over it once again to just add it into City storage which seems redundant.
I guess I struggle to find a better way to design a structure of my world, but can't think of anything.
What can of course work is to separate the production of resources and adding them to the city. I've modified your Playground to get it to compile:
let mut v:Vec<Option<ResourceEnum>> = city.buildings.iter().map(|f| f.produce()).collect();
v.drain(..).for_each(|r| city.add_resource(r));
But certainly you cannot call a mutable function on City while iterating on the buildings inside the same object.
I am trying to create an in-memory database using HashMap. I have a struct Person:
struct Person {
id: i64,
name: String,
}
impl Person {
pub fn new(id: i64, name: &str) -> Person {
Person {
id: id,
name: name.to_string(),
}
}
pub fn set_name(&mut self, name: &str) {
self.name = name.to_string();
}
}
And I have struct Database:
use std::collections::HashMap;
use std::sync::Arc;
use std::sync::Mutex;
struct Database {
db: Arc<Mutex<HashMap<i64, Person>>>,
}
impl Database {
pub fn new() -> Database {
Database {
db: Arc::new(Mutex::new(HashMap::new())),
}
}
pub fn add_person(&mut self, id: i64, person: Person) {
self.db.lock().unwrap().insert(id, person);
}
pub fn get_person(&self, id: i64) -> Option<&mut Person> {
self.db.lock().unwrap().get_mut(&id)
}
}
And code to use this database:
let mut db = Database::new();
db.add_person(1, Person::new(1, "Bob"));
I want to change person's name:
let mut person = db.get_person(1).unwrap();
person.set_name("Bill");
The complete code in the Rust playground.
When compiling, I get a problem with Rust lifetimes:
error[E0597]: borrowed value does not live long enough
--> src/main.rs:39:9
|
39 | self.db.lock().unwrap().get_mut(&id)
| ^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
40 | }
| - temporary value only lives until here
|
note: borrowed value must be valid for the anonymous lifetime #1 defined on the method body at 38:5...
--> src/main.rs:38:5
|
38 | / pub fn get_person(&self, id: i64) -> Option<&mut Person> {
39 | | self.db.lock().unwrap().get_mut(&id)
40 | | }
| |_____^
How to implement this approach?
The compiler rejects your code because it violates the correctness model enforced by Rust and could cause crashes. For one, if get_person() were allowed to compile, one might call it from two threads and modify the underlying object without the protection of the mutex, causing data races on the String object inside. Worse, one could wreak havoc even in a single-threaded scenario by doing something like:
let mut ref1 = db.get_person(1).unwrap();
let mut ref2 = db.get_person(1).unwrap();
// ERROR - two mutable references to the same object!
let vec: Vec<Person> = vec![];
vec.push(*ref1); // move referenced object to the vector
println!(*ref2); // CRASH - object already moved
To correct the code, you need to adjust your design to satisfy the following constraints:
No reference can be allowed to outlive the referred-to object;
During the lifetime of a mutable reference, no other reference (mutable or immutable) to the object may exist..
The add_person method already complies with both rules because it eats the object you pass it, moving it to the database.
What if we modified get_person() to return an immutable reference?
pub fn get_person(&self, id: i64) -> Option<&Person> {
self.db.lock().unwrap().get(&id)
}
Even this seemingly innocent version still doesn't compile! That is because it violates the first rule. Rust cannot statically prove that the reference will not outlive the database itself, since the database is allocated on the heap and reference-counted, so it can be dropped at any time. But even if it were possible to somehow explicitly declare the lifetime of the reference to one that provably couldn't outlive the database, retaining the reference after unlocking the mutex would allow data races. There is simply no way to implement get_person() and still retain thread safety.
A thread-safe implementation of a read can opt to return a copy of the data. Person can implement the clone() method and get_person() can invoke it like this:
#[derive(Clone)]
struct Person {
id: i64,
name: String
}
// ...
pub fn get_person(&self, id: i64) -> Option<Person> {
self.db.lock().unwrap().get(&id).cloned()
}
This kind of change won't work for the other use case of get_person(), where the method is used for the express purpose of obtaining a mutable reference to change the person in the database. Obtaining a mutable reference to a shared resource violates the second rule and could lead to crashes as shown above. There are several ways to make it safe. One is by providing a proxy in the database for setting each Person field:
pub fn set_person_name(&self, id: i64, new_name: String) -> bool {
match self.db.lock().unwrap().get_mut(&id) {
Some(mut person) => {
person.name = new_name;
true
}
None => false
}
}
As the number of fields on Person grows, this would quickly get tedious. It could also get slow, as a separate mutex lock would have to be acquired for each access.
There is fortunately a better way to implement modification of the entry. Remember that using a mutable reference violates the rules unless Rust can prove that the reference won't "escape" the block where it is being used. This can be ensured by inverting the control - instead of a get_person() that returns the mutable reference, we can introduce a modify_person() that passes the mutable reference to a callable, which can do whatever it likes with it. For example:
pub fn modify_person<F>(&self, id: i64, f: F) where F: FnOnce(Option<&mut Person>) {
f(self.db.lock().unwrap().get_mut(&id))
}
The usage would look like this:
fn main() {
let mut db = Database::new();
db.add_person(1, Person::new(1, "Bob"));
assert!(db.get_person(1).unwrap().name == "Bob");
db.modify_person(1, |person| {
person.unwrap().set_name("Bill");
});
}
Finally, if you're worried about the performance of get_person() cloning Person for the sole reason of inspecting it, it is trivial to create an immutable version of modify_person that serves as a non-copying alternative to get_person():
pub fn read_person<F, R>(&self, id: i64, f: F) -> R
where F: FnOnce(Option<&Person>) -> R {
f(self.db.lock().unwrap().get(&id))
}
Besides taking a shared reference to Person, read_person is also allowing the closure to return a value if it chooses, typically something it picks up from the object it receives. Its usage would be similar to the usage of modify_person, with the added possibility of returning a value:
// if Person had an "age" field, we could obtain it like this:
let person_age = db.read_person(1, |person| person.unwrap().age);
// equivalent to the copying definition of db.get_person():
let person_copy = db.read_person(1, |person| person.cloned());
This post use the pattern cited as "inversion of control" in the well explained answer and just add only sugar for demonstrating another api for an in-memory db.
With a macro rule it is possible to expose a db client api like that:
fn main() {
let db = Database::new();
let person_id = 1234;
// probably not the best design choice to duplicate the person_id,
// for the purpose here is not important
db.add_person(person_id, Person::new(person_id, "Bob"));
db_update!(db #person_id => set_name("Gambadilegno"));
println!("your new name is {}", db.get_person(person_id).unwrap().name);
}
My opinionated macro has the format:
<database_instance> #<object_key> => <method_name>(<args>)
Below the macro implementation and the full demo code:
use std::collections::HashMap;
use std::sync::Arc;
use std::sync::Mutex;
macro_rules! db_update {
($db:ident # $id:expr => $meth:tt($($args:tt)*)) => {
$db.modify_person($id, |person| {
person.unwrap().$meth($($args)*);
});
};
}
#[derive(Clone)]
struct Person {
id: u64,
name: String,
}
impl Person {
pub fn new(id: u64, name: &str) -> Person {
Person {
id: id,
name: name.to_string(),
}
}
fn set_name(&mut self, value: &str) {
self.name = value.to_string();
}
}
struct Database {
db: Arc<Mutex<HashMap<u64, Person>>>, // access from different threads
}
impl Database {
pub fn new() -> Database {
Database {
db: Arc::new(Mutex::new(HashMap::new())),
}
}
pub fn add_person(&self, id: u64, person: Person) {
self.db.lock().unwrap().insert(id, person);
}
pub fn modify_person<F>(&self, id: u64, f: F)
where
F: FnOnce(Option<&mut Person>),
{
f(self.db.lock().unwrap().get_mut(&id));
}
pub fn get_person(&self, id: u64) -> Option<Person> {
self.db.lock().unwrap().get(&id).cloned()
}
}
I have a struct that has a vector of another struct type.
struct Element {
val: String,
}
struct Collection {
elements: Vec<Element>,
}
impl Collection {
fn process(&mut self) {
for entry in &self.elements.iter_mut() {
entry.val = "New value".to_string();
println!("{}", entry.val);
}
}
}
fn main() {
let e1 = Element {
val: "My first entry".to_string(),
};
let e2 = Element {
val: "My second entry".to_string(),
};
let mut c = Collection { elements: vec![] };
c.elements.push(e1);
c.elements.push(e2);
c.process();
}
When I try to iterate over it, I get the following error:
error[E0277]: the trait bound `&std::slice::IterMut<'_, Element>: std::iter::Iterator` is not satisfied
--> src/main.rs:11:22
|
11 | for entry in &self.elements.iter_mut() {
| -^^^^^^^^^^^^^^^^^^^^^^^^
| |
| `&std::slice::IterMut<'_, Element>` is not an iterator; maybe try calling `.iter()` or a similar method
| help: consider removing 1 leading `&`-references
|
= help: the trait `std::iter::Iterator` is not implemented for `&std::slice::IterMut<'_, Element>`
= note: required by `std::iter::IntoIterator::into_iter`
I think this is because &self.elements is really a reference. Using self.elements would work, but I was hoping to modify the actual objects rather than a copy.
What would be a proper way of doing this?
Switch to this:
for entry in self.elements.iter_mut() { /* ... */ }
Or more idiomatically:
for entry in &mut self.elements { /* ... */ }
IterMut contains a reference to the items in the vector (and thus will change the vector items directly), but it is itself an object on the stack that will be changed as the iteration progresses.
the trait bound `&std::slice::IterMut<'_, Element>: std::iter::Iterator` is not satisfied
This is saying that you've got an IterMut by reference. That is, the precedence is different from what you think it is:
&self.elements.iter_mut()
&(self.elements.iter_mut()) // Is this
(&self.elements).iter_mut() // Not this
However, we'd have to do something like this:
(&mut self.elements).iter_mut()
because iter_mut needs a mutable reference as the receiver. Rust understands that and lets us just do the straightforward version and appropriately pass the mutability around:
self.elements.iter_mut()