It would be great to have some part of std::io available in #![no_std] contexts, especially the core traits (Read, Write, etc).
Why alloc and not core?
Many parts of std::io explicitly rely on allocation: Error::new, Read::read_to_end, BufReader::with_capacity,... Migrating to a context where alloc is not available would require changing the items themselves, which is not acceptable ; or at least requires significantly more work.
What would be moved to alloc::io?
Everything possible. Once the first difficult points are solved, the rest should follow easily.
Of course, everything directly related to the OS (stdio, pipes, IsTerminal) would remain std-only.
The plan
This plan relies on externally implementable items (EII) (Tracking Issue for externally implementable items · Issue #125418 · rust-lang/rust · GitHub), whose implementation is still a draft at this point.
The main idea is to use unstable ones so alloc can declare and use them, and std can implement them.
Maybe we could get a first version earlier by doing an equivalent in the compiler directly, as for panic_handler and global_allocator, but this would require more work.
- Notably,
allocwould require EII to implement errno:last_os_error, errno classification, and errno messages. A default impl inallocwould return0,ErrorKind::Uncategorizedand"". - The other (but hidden) offender is
copy(), which has a specialization path depending on the OS (to enable stuff like usingsendfilewhere possible). Once again an EII can solve that.
The harder part is for types depending on the OS. There are two of them here:
IoSliceandIoSliceMut, which are guaranteed to be compatible with their OS equivalent. Fortunately, the same layout is used on all existing OS: a pointeur and ausize. If a new OS is added with another layout for theirreadv/writevequivalent, well, too bad for them.- The harder one is
RawOsError. This is a type alias to the raw OS error type, which happen to always bei32... except on UEFI. I see two workarounds here:- Make a breaking change to UEFI target. I don't know how unacceptable it is, nor if using
usizeis actually necessary or not. (cc @nicholasbishop @dvdhrm) - Accept having a
cfg(target_os)inalloc. This small violation is worth if it means havingioavailable inallocIMO.
- Make a breaking change to UEFI target. I don't know how unacceptable it is, nor if using
The last usage of std::sys is for DEFAULT_BUF_SIZE which is smaller for "espidf" target. We could normalize it if acceptable or use another cfg(target_os) here.
All of this seems really doable to me once EII is implemented.