I’ve been trying to get my feet wet with futures in rust, and followed various online tutorials and examples. Starting from a pretty typical “chat server” example, I ended up with code like this.
Most of the examples make sense as they are structured and they are illustrating a basic skeleton, but as I try to move code out into libraries/out of a single main function, I wonder if I’m using the proper abstractions at the boundaries. This code is still a toy example, but I am trying to understand how to evolve simple implementations into bigger projects. I have looked at the tokio chat server, as well as other similar examples.
The particular set up here is a chat server where clients connect via websockets. I then introduced concepts such as:
Hubwhich is effectively a registry of connected
Clients, although includes things such as an internal
Streamwhich sends heart beats, etc.
Clientwhich represent each websocket connection.
hub module (what one might pull out to a library if this were more than a toy example), I wanted to avoid directly relying on
tokio, so code that originally might have directly called
tokio::spawn I wanted to instead have return
Stream objects, so the
main fn could handle dispatching them onto the
tokio runtime instead.
But code like here feels somewhat forced, and took some poking and prodding to land on. Effectively I am mapping an incoming
Stream into a
Futures, and passing that
Stream back out to
main, where it can be
In another case, for this
Drop impl, to avoid a
spawn I am instead doing
Ultimately, I wonder if I’m following intended usage for
Futures. Or am I shoehorning in the wrong patterns/concepts? For example, the “consume
Futures” pattern was somewhat motivated in my mind as analogous to iterating over a collection and
- Is returning
impl Futurethe appropriate abstraction at a library boundary (where I don’t want to e.g.
tokio::spawninternally to the library)?
- Is it ok to simply
wait()in cases such as a
- Would a more ergonomic approach be to implement
Futurefor types such as
I don’t know if I should be comfortable using
spawn more liberally/this sort of design ends up placing too much work within a task and reducing the potential of using
hub_loop definition in particular I am concerned about; by trying to pipeline both the consumer and producer aspects, am I introducing unnecessary serialization or something similar?