[Pre-Pre-RFC] Box, String, and Vec preludes for no_std environments


#1
  • What do I want? Box, String, and Vec in the prelude!
  • Where do I want it? no_std!

Now that the new allocators API has been merged, and now that it seems Box, String, Vec will remain in liballoc, I’d like to talk about something else I think would be immensely helpful for no_std users in a “no OS features but I do have a heap” environments: getting Box, String, and Vec into the prelude.

I work in 2 completely distinct no_std environments with heaps (SGX and a proprietary HSM environment). And while it’s a bit hard to operate this way right now (with the new allocator API, it involves copying and pasting much of heap.rs from std), having access to alloc makes our code much more ergonomic and gives us access to a wider range of crates in the Rust ecosystem.

That said, supporting no_std in downstream crates is still rather difficult. I’ve submitted PRs to dozens of crates to add no_std support with varying degrees of success (and when I can’t upstream my patches, operate off forks, which is certainly less than ideal).

As an example, here is a PR I submitted to the bytes crate:

https://github.com/carllerche/bytes/pull/135

I originally had support for alloc-dependent features in that PR, but after some discussion, split those parts out into a separate PR:

https://github.com/carllerche/bytes/pull/153

Much of the contention in the PR comments was around supporting nightly-specific functionality in the crate. I certainly admit my original PR was rife with it, but in the followup in #153 managed to pare it down considerably. Still, I wish it could be cleaner.

My solution for Box, String, and Vec was to add a nightly cargo feature along with an internal prelude module within the crate, which would pull in Box, String, and Vec from liballoc in no_std environments, and add the following to the top of every module which referenced them anywhere:

#[allow(unused_imports)]
use prelude::*;

I don’t find this solution to be particularly ergonomic, especially since this needs to happen in every module of every crate that wants to use Box, String, or Vec in no_std environments.

What I really want is something like this:

#![cfg_attr(all(not(feature = "std"), feature = "nightly"), feature(alloc_prelude))]

…where alloc_prelude is my proposed pre-pre-RFC hypothetical feature. What would this do? Add Box, String, and Vec to core::prelude or thereabouts, sourced from liballoc. In many cases I don’t want to or care to reference ::alloc directly, all I’m really trying to get to are Box, String, and Vec.

This would reduce the unstable/nightly-specific errata for leveraging Box, String, and Vec from the crate-by-crate module-by-module specific boilerplate down to a single line. I think this would make it MUCH easier to port crates that allocate memory over to no_std land.

As a no_std user, this has by far been my biggest struggle with the environment. I believe a feature like this would go a long way towards making it easier to use crates which allocate in no_std environments.


#2

If you are okay with using unstable features, you can do the same thing that libstd and libcore do.

// This should be in the crate root, maybe under cfg.
#[allow(unused)]
#[prelude_import]
use prelude::*;

This will reduce the boilerplate from “once in a module” to “once in a crate”.


#3

Nice! Thanks for the tip, that’s certainly much more ergonomic than what I was doing. Will give it a try…