2 errors: E0495 E0623. And code suggestions welcome

Hello,

I need help again. This is taken from a WASM application and heavily reduced. The code throws two errors:

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter 'a in generic type due to conflicting requirements
error[E0623]: lifetime mismatch

I'm not sure how to fix them. Full Details:

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter 'a in generic type due to conflicting requirements
  --> src/main.rs:68:2
   |
68 |     fn handle_event<'a>(&mut self, mut objects: &'a mut Vec<&'a mut Object>, event: &FromClientEvent) -> Result<(), FromServerToClientEvent> {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the method body at 68:2...
  --> src/main.rs:68:2
   |
68 |       fn handle_event<'a>(&mut self, mut objects: &'a mut Vec<&'a mut Object>, event: &FromClientEvent) -> Result<(), FromServerToClientEvent> {
   |  _____^
69 | |         match self.machine.take().unwrap().step(objects, self) {
70 | |             Ok(next_state) => {
71 | |                 self.machine = Some(next_state);
...  |
78 | |         Ok(())
79 | |     }
   | |_____^
note: ...but the lifetime must also be valid for the anonymous lifetime #3 defined on the method body at 68:2...
  --> src/main.rs:68:2
   |
68 |       fn handle_event<'a>(&mut self, mut objects: &'a mut Vec<&'a mut Object>, event: &FromClientEvent) -> Result<(), FromServerToClientEvent> {
   |  _____^
69 | |         match self.machine.take().unwrap().step(objects, self) {
70 | |             Ok(next_state) => {
71 | |                 self.machine = Some(next_state);
...  |
78 | |         Ok(())
79 | |     }
   | |_____^
   = note: ...so that the method type is compatible with trait:
           expected fn(&mut AddWeightComponent, &mut std::vec::Vec<&mut Object>, &FromClientEvent) -> std::result::Result<(), FromServerToClientEvent>
              found fn(&mut AddWeightComponent, &mut std::vec::Vec<&mut Object>, &FromClientEvent) -> std::result::Result<(), FromServerToClientEvent>

error[E0623]: lifetime mismatch
  --> src/main.rs:69:43
   |
68 |     fn handle_event<'a>(&mut self, mut objects: &'a mut Vec<&'a mut Object>, event: &FromClientEvent) -> Result<(), FromServerToClientEvent> {
   |                         ---------               ---------------------------
   |                         |
   |                         these two types are declared with different lifetimes...
69 |         match self.machine.take().unwrap().step(objects, self) {
   |                                                 ^^^^^^^ ...but data from `self` flows into `objects` here

The code is at the playground.

Also if you read my code you'll notice three "@todos". I'd like suggestions on how to make it better, because it seem really bad. Also if there are other suggestions they are really welcome, obviously.

If you ever see yourself using &mut SomeTypeWithLifetime in a type you are likely doing something wrong. Try and refactor your code to not store references like this.

Instead, think of references as compile time locks, where &mut _ means a unique lock and &_ means a shared lock, read more about this here https://limpet.net/mbrubeck/2019/02/07/rust-a-unique-perspective.html

1 Like

Okay, I'm trying to refactor this. In the thread there was suggested to not modify the objects in the state machine but to send the differences over the thread back and merge them there. Well, it's a good idea, but after all, I didn't go down this route. I will try now.
Thanks

1 Like

Thanks KrishnaSannasi.

I've read the link and I know the basics in theory. But using them is hard for me as you can see.

I see what you are hinting at. I could use specs but I want to write my own way using state machines.

Basically what I have in mind is this:
(single threaded) fn f(game_object_ids: Vec<ID>) -> Vec<Object>
f "collects" the requested Objects and returns a "working set" Vec. All working sets do not share the same ids, if id 2 occurs multiple times, than only in a specific working set.
I use unsafe to get all those &mut references out of the hashmap.

(multi-threaded) I start worker threads. Every thread gets a list of "working sets". The same object ids are always handled in the same worker to maintain non-ub.
Then every worker starts processing the first working set. This means that a state machine is feed an event/message with all the objects of the working set.

This is such a message:
pub struct TakeItem<'a> {
objects: &'a mut Vec<&'a mut Object>,
component: &'a mut dyn Component,
}

At the end of the day I need to access the objects in my state machine, because I've chosen to modify them at that level. But initially they are all stored in hashmap.
So I've got to get multiple references out of the map. Because otherwise, I'd need to re(move) the object from the map and move it to the state machine, so I don't have &mut references anymore, and after that to put them back into the hashmap for every event, which does not make sense to me.

It was suggested to not modify the objects in the state machine but to send the differences over the thread back and merge them there. Well, it's does not fit into my model.
Because if there are changes within a working set, for instance the object with id 2 has changes to be merged than every other object wanting to interact with object id 2 has to already account the changes to properly calculate the results, which simply does not make much sense, because the calculations are simple and I always would need to apply the changes more or less quite often indeed.

I really would like to know how it works with these &'a mut references, if it's possible at all.

I think that the suggestion to split up diff and update is a good one, even if each diff is small. This method also makes it easier to parallelize generating the diffs, because you will only need a shared reference to objects, not unique references.

This seems dangerous, before venturing further into unsafe please go through the nomicon

1 Like

Ok, I'm still figuring out how to rewrite parts of it. But obviously the lifetime errors have vanished. So that was indeed a working solution.

Thanks!