I am implementing a small json-service using the hyper crate. Now, I am having trouble adding a small in-memory storage to my and_then future-chaining.
Instead of having some global variable, which I think is bad, I thought that I can just add a simple Vec to the struct which is used as a hyper::server::Service.
I am always getting "cannot infer an appropriate lifetime due to conflicting requirements" due to the call and_then(|x: MyType| persist(x, &mut self.storage)).
I assume this has something to do with the declaration of call in the Service-trait, because the self argument is not mutable (its just a &self).
Is there a way to do what I am trying to do (pass a mutable reference from inside &self)?
If not, what would be a proper way to pass something mutable to the request-handler-chain from the outside (one might call this dependency injection)?
Please bear with me: this is my first little rust exercise where I am trying to adapt the things I learn from the book "Programming in Rust" (which is great by the way)
Thank you very much. This is pretty much the same issue, still I am having trouble adopting to it.
I changed my service-struct to contain a RefCell<Vec < MyType>> to handle the interior mutability which I think I understood.
The closure was changed to .and_then(|x: MyType| persist(x, &mut self.storage.borrow_mut()))
I am still getting the lifetime error and you mentioned in the other post to wrap the RefCell in another Rc to fix a lifetime issue. I dont understand why I should need this: I only want one shared mutable instance accross all requests (for now). Wrapping this in an Rc gives new errors, specifically serde_json is not able to serialize an Rc.
With all those problems it seems to me that my "design" is a rather bad approach anyway. Are there other alternatives? Of course I am still interested in how to fix the current issue in order to learn the language.
The Rc is needed to allow your closure given to and_then to be 'static - that is, it does not have any references. This, in turn, is needed because the entire future you return from call() must be 'static.
Are you sure serde doesn't support serializing an Rc<T: Serialize>? This would imply otherwise.
As far as I understood, I can use a Rc like using the wrapped value, no need to unwrap it with some function call.
.with_body(serde_json::to_vec_pretty(&self.storage).unwrap())
| ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `serde::Serialize` is not implemented for `std::rc::Rc<std::cell::RefCell<std::vec::Vec<domain::MyType>>>`
I thought I might have to use &self.storage.borrow() in the marked call, but this gives me the same error.
This is how I create the server
let store = Rc::new(RefCell::new(vec![]));
store.borrow_mut().push(some_val_of_mytype);
let address = "127.0.0.1:8080".parse().unwrap();
let server = hyper::server::Http::new()
.bind(&address, move || Ok(MyTypeService {storage: store.clone()}))
.unwrap();
server.run().unwrap();
I solved the json-serialization problem with another indirection. I hide the Vec behind an Repository implementation.
Anyways: now I am still stuck with the lifetime-issue, despite wrapping the storage/repository behind a Rc<RefCell<..>>. Calling persist still gives me
cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
Another thing I didn't get was that I had to change the signature of persist to receive a RefMut because otherwise the compiler complained that the trait "BikeRepository" isn't implemented. I thought using borrow_mut() gives a an actual mut-ref to the contained object.
Because you’re referencing self while calling persist, that closure is capturing a reference to self, which means it’s no longer 'static.
The way to handle this is to clone the Rc outside the closure and then move it inside. Below is an example and also a way to avoid having RefMut in persist’s signature.
let repo = Rc::clone(&self.repository);
let future = request
.body()
.concat2()
.and_then(parse_json)
.and_then(move |x: Bike| {
// put the RefMut into a local;
let mut repo = repo.borrow_mut();
// now deref and borrow mut the inner data, and you don’t need the RefMut in the persist signature
persist(x, &mut *repo)
})
.then(make_put_response);