[Hyper] pass mutable argument to &self.call

Hello everyone

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.

This is the function I would like to call

fn persist(b: MyType, storage: &mut Vec<MyType>) -> FutureResult<MyType, hyper::Error> {

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.

struct MyTypeService {
    storage: Vec<MyType>

impl Service for MyTypeService {
    type Request = Request;
    type Response = Response;
    type Error = hyper::Error;
    type Future = Box<Future<Item = Self::Response, Error = Self::Error>>;

    fn call(&self, request: Request) -> Self::Future {
        match (request.method(), request.path()) {
            (&Get, "/foo") => {
            (&Put, "/foo") => {
                let future = request
                    .and_then(|x: MyType| persist(x, &mut self.storage))
            _ => {

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)

This thread discusses a similar issue.

1 Like

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.

   |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^ 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![]));
let address = "".parse().unwrap();
let server = hyper::server::Http::new()
    .bind(&address, move || Ok(MyTypeService {storage: store.clone()}))

Are you sure it’s not because domain::MyType isn’t Serialize?

MyType is actually a Bike :slight_smile: I thought I keep the domain out of this post in order not to distract.

#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct Bike {
    manufacturer: String,
    name: String,
    weight: f32,
    parts: Vec<Part>
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct Part {
    name: String,
    weight: f32

Those are the crates I am using

hyper = "0.11"
futures = "0.1"
mime = "0.3"
serde = "1.0"
serde_json = "1.0"
serde_derive = "1.0"

Hmm, something doesn’t add up: this type checks. Can you show more of the real code and the real error?

Weird. I enhanced you sample to print something in order to check the way I create the Rc/RefCell thingy. Its working just fine

I’ve just pushed my project to Github..

Thanks for your patience

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.

let future = request
                    .and_then(|x: Bike| {
                        persist(x, &mut self.repository.borrow_mut())

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
                    .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)
1 Like

Awesome. Thanks again. Now everything is working and I have to learn the details.

Slight change: the borrow_mut() variable has to be “let mut repo”

Oops, yes - fixed.

Feel free to ask questions about it.