Best pattern for async update of self object?


#1

I have got a struct (Adapter for reference purposes).

struct Adapter {
    field: i32
}

It’s methods issue async requests using hyper client. Sometimes, I need to update internal fields of the Adapter depending on responses received for the issued by itself requests. It means I need to access self in one of the closures on futures::then(). This is not allowed as self may not live long enough, unless the Adapter instance is static. I do not have it static, because it is created after some validation and interaction on start.

I have found another option is to do something like the following:

struct AdapterImpl {
    field: i32
}
struct Adapter {
    internal: Rc<RefCell<AdapterImpl>>
}

This way I can obtained Rc pointer to the implementation of self before constructing future chain and move it to the closure, where I do borrow or borrow_mut on the RefCell self object to access or mutate it in async code. I heard that RefCell is a sign of code smell, but I can not think of another way of solving the problem.

Is the approach, I am taking, the best practice? Or am I doing something wrong?


#2

This is a good and common approach for this. I cringe a bit whenever I use RefCell but the Rc<RefCell<...>> duo is virtually required when using futures.

Another approach is to move self itself into the future, and then get it back when the future resolves.


#3

Could you please post a sketch of code how to do this.? I do not understand how to get it back.


#4

A good example is the StreamFuture in the futures crate. This is a future that’s returned when you call some_stream.into_future(), and into_future() consumes self. The Future impl for StreamFuture yields the underlying stream back in success and error cases: https://docs.rs/futures/0.1.17/futures/stream/struct.StreamFuture.html#impl-Future.

So this approach works well if you own (or can take ownership) of a value that you intend to move into a future. That future should then yield back the value via its Item and Error associated types, which will allow the caller/user to get ownership back.


#5

Very nice! Thanks