Skip to content

ACP: Introduce alloc::io #755

@a1phyr

Description

@a1phyr

Proposal

Problem statement

It would be great for OS-independent parts of std::io to be usable in alloc.

Motivating examples or use cases

std::io is a very useful abstraction, but unfortunately it is not available in no_std contexts, even though most of std::io do not depend directly on the underlying OS.

Today, OS-independent crates that use IO traits have the choice between using an alternative but incompatible implementation, such as embedded-io and not supporting no_std.

Solution sketch

The idea of this proposal is to move all OS-independent parts of std::io to alloc: traits, Cursor, Empty, Sink, buffering wrappers, etc. All OS-dependent functions and types will of course stay in std: stdio and pipes.

Unfortunately, some core items in std::io actually depend on the OS under the hood: Error (and unstable RawErrorType), IoSlice, IoSliceMut and copy. This is why this move has not been done earlier. The rest can easily be moved as it doesn't depend on anything else that is not already in alloc.

Here is the proposed plan for these:

  • Error and RawErrorType: move them to alloc, while keeping RawErrorType perma-unstable in alloc (for use in std). Creating Error from raw OS errors would only be possible in std, which is possible thanks to incoherent impls. When creating an Error from a raw OS error, std provides alloc with callbacks to decode them (could be replaced with externally implementable items).
  • IoSlice and IoSliceMut are even easier, as they only depend on the OS for their exact layout: io_vec on Unix, WSABUF on Windows, etc. We can just have their definition in alloc, with a fallback for platform where the layout doesn't matter.
  • copy has specialization paths depending on the OS (eg using sendfile or splice). In alloc, copy would only have the generic path, while std would keep the specialized one. Such difference between standard crate in not new, it already exists with eg panic!.

Note that this proposal makes extra care to not expose anything OS-dependent to alloc users, only keeping that internal or perma-unstable for std; and to avoid linking to anything in alloc, as there are only structure definitions.
I understand that adding OS-dependent code to alloc is quite controversial, but I think that having alloc::io is worth the change.

A PR that successfully moves Error, IoSlice and IoSliceMut to alloc can be found at rust-lang/rust#152918.

Alternatives

Possible future work

  • Try to move some parts of io to core instead of alloc.
    This will probably be quite difficult as Read directly depends on Vec.

  • Compatibility with #[cfg(no_global_oom_handling)]
    This should be possible for most of alloc::io to handle OOM errors through io::Error, though some PR in this direction has already been rejected (Handle OOM when writing to Vec rust#148024).

Links and related work

Tracking issue: rust-lang/rust#48331
Prior try to move Error to core (not alloc): rust-lang/rust#116685
Current PR for OS-specific parts: rust-lang/rust#152918
https://internals.rust-lang.org/t/a-plan-to-move-most-of-std-io-to-alloc/23678

Many #![no_std] crates reimplementing std::io:

What happens now?

This issue contains an API change proposal (or ACP) and is part of the libs-api team feature lifecycle. Once this issue is filed, the libs-api team will review open proposals as capability becomes available. Current response times do not have a clear estimate, but may be up to several months.

Possible responses

The libs team may respond in various different ways. First, the team will consider the problem (this doesn't require any concrete solution or alternatives to have been proposed):

  • We think this problem seems worth solving, and the standard library might be the right place to solve it.
  • We think that this probably doesn't belong in the standard library.

Second, if there's a concrete solution:

  • We think this specific solution looks roughly right, approved, you or someone else should implement this. (Further review will still happen on the subsequent implementation PR.)
  • We're not sure this is the right solution, and the alternatives or other materials don't give us enough information to be sure about that. Here are some questions we have that aren't answered, or rough ideas about alternatives we'd want to see discussed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    ACP-acceptedAPI Change Proposal is accepted (seconded with no objections)T-libs-apiapi-change-proposalA proposal to add or alter unstable APIs in the standard libraries

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions