Design of async Zigbee device discovery in discovery actor

I need a second opinion on the design of async discovery of Zigbee devices.

I have a discovery::Actor, which implements the actor model and receives messages, amongst others, those of Events.
If such an event is Event::DeviceJoined(address) the actor shall start the discovery of that device.

This involves several steps:

  1. Discovery of endpoints on the node.
  2. Discovery of descriptors for each of the endpoints.
  3. Discovery of a pre-dermined set of attributes for each endpoint.

Now, due to Zigbee being a fallible radio mesh networking protocol, each of these steps can fail.
So I want to have an option to retry each of the steps above until all properties are discovered.

I am facing several challenges while implementing this:

  1. The discovery of each device shall be non-blocking in the discovery::Actor's main loop.
  2. Steps 2 and 3 depend on step 1 having completed successfully.
  3. Steps 2 and 3 are independent and may be parallellized.
  4. Once any device discovery is completed, it shall forward the completely discovered device data to another actor.

Here's my current (WIP) approach:

Do you have some established patterns or tips on how I can achieve my set goals?

The pattern that immediately comes to mind would be using custompoll_foo() functions for at least steps 2 & 3 where a certain set of errors is reset to Poll::Pending.

Something along the lines of how Sockets reset blocking IO errors to Poll::Pending on poll_read_ready()etc. (A bit of an idea for that is here in futures-udp clear_ready() & poll_ready())

I'm interested to see how you get on with this lib - zigbee is about 1/3 of the way down my current todo list, so maybe I can just use yours when I get that far.

One request though: if you're creating a lib and there is any way to use futures-rs rather than tokio for the underlying foundations that guarantees to leave the choice of runtime to the app. (tokio sometimes embeds runtime-dependencies in fundamental types which means apps then have to struggle to use a different runtime of they want to for whatever reasons)