futures-rs
futures-rs copied to clipboard
no_std support for futures-io
Inspired by @Ericson2314's comment on a portability-wg issue about allocation-less std::io::Error
I decided to attempt a two-layered approach to Async{Read,Write}
allowing supporting no_std
targets with most of the futures-io
and futures-util::io
adaptors.
The main change required is a second set of traits (CoreAsync{Read,Write}
) which have an associated error type instead of using std::io::Error
, the Async{Read,Write}
traits are then implemented on top of these traits where CoreAsync{Read,Write}::Error: Into<std::io::Error>
.
One difficulty is that some of the more important adaptors (e.g. futures-util::io::ReadExact
) re-use error variants from std::io::Error
, my first attempt at working around this limitation is to force the underlying error type to provide at least the two variants that the adaptors require. This seems a bit messy, I'm unsure if there's a much nicer solution to this.
My main goal with this was to be able to use these adaptors with types from the embedded-hal
library for non-blocking serial connections, via the nb
library. I have an example of this compiling now, but I'll have to wait till I'm at work tomorrow to try and get it running on real hardware.
Links to the changes:
I'm creating this issue now to get feedback on whether this is something that might be supported by the core futures
library at some point. I really would like to avoid splitting the ecosystem between std
and no_std
Futures, e.g. I'm likely to be looking at using/building a non-blocking CoAP library, and am hoping to be able to make it work with both std
and no_std
environments without much effort in the library itself.
And finally got round to using this on some real hardware, it works perfectly (although, integrating task notification into HAL layers without impacting non-futures
use of them is stil an issue).
Thanks @Nemo157 for taking on this work! I strongly agree with your overall goals.
I'd really like to see if we can somehow finagle io::Error
to work in core
as a general solution to this problem. I will push on that with the libs team.
Is there any blockers on this? I really wish there is some Read
/Write
traits accepted by the ecosystem (especially async). Otherwise most of the no_std
bail out to core::fmt::Write
, which is limited by str
constrains or make their own traits.
Also since 0.3 picks up some nightly features (pin
and arbitrary_self_types
) maybe we should also use associated_type_defaults
instead of supertrait approach, making default error type std::io::Error
if std
feature enabled, so that we don't introduce 2 traits for the same thing, making documentation and implementation on top of this traits much cleaner.
It would be really awesome if you could somehow write your embedded code as async functions, and then have some clever executor setup the necessary interrupts and call wfi
when there's nothing to do. You could possibly end up with code as good (for power usage) as hand-written but with all the embedded details abstracted. Would be very cool.
I don't believe this is something we'll be able to tackle without support from upstream, since I think it's important that these traits mirror the upstream std::io::Read/Write
counterparts. I'm open to suggestions here, though, if anyone has ideas about how to avoid this restriction!
@cramertj Not everything can be implemented for no_std for io, but most of it can now thanks to https://github.com/jethrogb/rust-core_io.