stepancheg / grpc-rust

Rust implementation of gRPC
MIT License
1.38k stars 125 forks source link

Mutating `&self` in v0.6.2 #169

Closed thomasantony closed 4 years ago

thomasantony commented 4 years ago

I have been trying to create an RPC function that takes in a streaming request and uses the incoming data to mutate a field on &self. I followed the guidelines at https://github.com/stepancheg/grpc-rust/blob/v0.6/docs/FAQ.md and tried using Arc<Mutex<Datatype>>. I also used the interop example code to implement the function with the streaming input. Here is a rough idea of what the code looks like:

fn update_machine_state(&self, o: RequestOptions, 
                            p: StreamingRequest<MachineState>)
                             -> SingleResponse<MachineStateUpdateReply>
    {
        // Parse incoming stream of machine states
        let return_stream = p
            .0
            .map(|state|
            {
                {
                    let new_state = MachineState::new();
                    new_state.lat = state.lat;
                    let data = *self.service_data.lock().unwrap();
                    data.set_machine_state(new_state);
                }
            })
            .fold(0, |a, _| futures::finished::<_, grpc::Error>(a+1))
            .map(|num_packets|{
                let mut reply = MachineStateUpdateReply::new();
                reply.set_num_packets(num_packets);
                reply
            });
        SingleResponse::no_metadata(return_stream)
    }

I get the error:

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
  --> gandalf-core/src/server.rs:66:18
   |
66 |               .map(|state|
   |  __________________^
67 | |             {
68 | |                 {
69 | |                     let new_state = MachineState::new();
...  |
73 | |                 }
74 | |             })
   | |_____________^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 59:5...
  --> gandalf-core/src/server.rs:59:5
   |
59 | /     fn update_machine_state(&self, o: RequestOptions,
60 | |                             p: StreamingRequest<MachineState>)
61 | |                              -> SingleResponse<MachineStateUpdateReply>
62 | |     {
...  |
81 | |         SingleResponse::no_metadata(return_stream)
82 | |     }
   | |_____^
   = note: ...so that the types are compatible:
           expected &&server::GandalfServiceImpl
              found &&server::GandalfServiceImpl
   = note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `futures::Map<futures::stream::Fold<futures::stream::Map<std::boxed::Box<dyn futures::Stream<Error = grpc::error::Error, Item = gandalf_api::gandalf::MachineState> + std::marker::Send>, [closure@gandalf-core/src/server.rs:66:18: 74:14 self:&&server::GandalfServiceImpl]>, [closure@gandalf-core/src/server.rs:75:22: 75:69], futures::Done<i32, grpc::error::Error>, i32>, [closure@gandalf-core/src/server.rs:76:18: 80:14]>` will meet its required lifetime bounds
  --> gandalf-core/src/server.rs:81:9
   |
81 |         SingleResponse::no_metadata(return_stream)
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^

I am very new to async programming. Is there something obvious that I am missing? Am I supposed to be doing something else to mutate state in the new version of the code?

I think this may be related to this question: https://users.rust-lang.org/t/best-pattern-for-async-update-of-self-object/15205

Any help would be greatly appreciated!

thomasantony commented 4 years ago

Nevermind. I figured it out. I had to clone the Arc variable outside of the async part of the code and it went fine.