1
1
- Feature Name: ` liballoc `
2
2
- Start Date: 2018-06-14
3
- - RFC PR:
3
+ - RFC PR: [ rust-lang/rfcs # 2480 ] ( https://github.com/rust-lang/rfcs/pull/2480 )
4
4
- Rust Issue: [ rust-lang/rust #27783 ] ( https://github.com/rust-lang/rust/issues/27783 )
5
5
6
6
# Summary
7
7
[ summary ] : #summary
8
8
9
- Stabilize the ` alloc ` crate, with a module structure matching ` std ` .
9
+ Stabilize the ` alloc ` crate.
10
10
11
11
This crate provides the subset of the standard library’s functionality that requires
12
- a global allocator (unlike the ` core ` crate) but not other operating system
13
- capabilities (unlike the ` std ` crate).
12
+ a global allocator (unlike the ` core ` crate) and an allocation error handler,
13
+ but not other operating system capabilities (unlike the ` std ` crate).
14
14
15
15
16
16
# Motivation
@@ -23,34 +23,49 @@ micro-controllers that don’t have an operating system at all, kernel-space cod
23
23
The ` #![no_std] ` attribute allows a crate to not link to ` std ` implicitly,
24
24
using ` core ` instead with only the subset of functionality that doesn’t have a runtime dependency.
25
25
26
- ## Use case 1: pushing ` no_std ` programs toward stable Rust
26
+ ## ` no_std ` with an allocator
27
27
28
- Programs (or ` staticlib ` s) that do not link ` std ` at all may still want to use ` Vec<T> `
29
- or other functionality that requires a memory allocator.
30
- Blockers for doing so on stable Rust are diminishing:
28
+ The ` core ` crate does not assume even the presence of heap memory,
29
+ and so it excludes standard library types like ` Vec<T> ` .
30
+ However some environments do have a heap memory allocator
31
+ (possibly as ` malloc ` and ` free ` C functions),
32
+ even if they don’t have files or threads
33
+ or something that could be called an operating system or kernel.
34
+ Or one could be defined [ in a Rust library] [ wee-alloc ]
35
+ ultimately backed by fixed-size static byte array.
31
36
32
- * [ The ` #[global_allocator] ` attribute] [ global_allocator ] to specify an allocator
33
- and remove the need for an operating-system-provided one is stable since Rust 1.28.
34
- * [ Tracking issue #51540 ] discusses how to stabilize a way to specify
35
- the handling of OOM (allocation failure) conditions when ` std ` is not available,
36
- instead of the unstable ` oom ` lang item.
37
+ An intermediate subset of the standard library smaller than “all of ` std ` ”
38
+ but larger than “only ` core ` ” can serve such environments.
37
39
38
- With this, the only allocation-related blocker is being able to import ` Vec ` in the first place.
39
- This RFC proposes stabilizing the current unstable way to do it: ` extern crate alloc; `
40
+ [ wee-alloc ] : https://github.com/rustwasm/wee_alloc
40
41
41
- [ global_allocator ] : https://doc.rust-lang.org/nightly/std/alloc/#the-global_allocator-attribute
42
- [ Tracking issue #51540 ] : https://github.com/rust-lang/rust/issues/51540
42
+ ## Libraries
43
+
44
+ In 2018 there is a [ coordinated push]
45
+ toward making ` no_std ` application compatible with Stable Rust.
46
+ As of this writing not all of that work is completed yet.
47
+ For example, [ ` #[panic_implementation] ` ] [ panic-impl ] is required for ` no_std ` but still unstable.
48
+ So it may seem that this RFC does not unlock anything new,
49
+ as ` no_std ` application still need to be on Nigthly anyway.
43
50
44
- ## Use case 2: making stable libraries ` no_std `
51
+ [ coordinated push ] : https://github.com/rust-lang-nursery/embedded-wg/issues/42
52
+ [ panic-impl ] : https://github.com/rust-lang/rust/issues/44489
45
53
46
- Even if a ` no_std ` program might still require other features that are still unstable,
47
- it is very common to use libraries from crates.io that have other users.
48
- Such a library might support stable Rust and use ` Vec<T> `
49
- (or something else that requires a memory allocator)
50
- but not other operating-sytem functionality.
54
+ The immediate impact can be found in the library ecosystem.
55
+ Many general-purpose libraries today are compatible with Stable Rust
56
+ and also have potential users who ask for them to be compatible with ` no_std ` environments.
51
57
52
- Today, making such a library possible to use without ` std ` without breaking stable users
53
- requires a compile-time flag:
58
+ For a library that is fundamentally about using for example TCP sockets or threads,
59
+ this may not be possible.
60
+
61
+ For a library that happens to only use parts of ` std ` that are also in ` core `
62
+ (and are willing to commit to keep doing so), this is relatively easy:
63
+ add ` #![no_std] ` to the crate, and change ` std:: ` in paths to ` core:: ` .
64
+
65
+ And here again, there is the intermediate case of a library that needs ` Vec<T> `
66
+ or something else that involves heap memory, but not other parts of ` std ` that are not in ` core ` .
67
+ Today, in order to not lose compatibility with Stable,
68
+ such a library needs to make compatibility with ` no_std ` an opt-in feature flag:
54
69
55
70
``` rust
56
71
#![no_std]
@@ -61,7 +76,11 @@ requires a compile-time flag:
61
76
use alloc :: vec :: Vec ;
62
77
```
63
78
64
- With this RFC, this can be simplified to:
79
+ But publishing a library that uses unstable features, even optionally,
80
+ comes with the expectation that it will be promptly updated whenever those features change.
81
+ Some maintainers are not willing to commit to this.
82
+
83
+ With this RFC, the library’s code can be simplified to:
65
84
66
85
``` rust
67
86
#![no_std]
@@ -71,9 +90,15 @@ extern crate alloc;
71
90
use alloc :: vec :: Vec ;
72
91
```
73
92
93
+ … and perhaps more importantly,
94
+ maintainers can rely on the stability promise made by the Rust project.
95
+
96
+
74
97
# Guide-level explanation
75
98
[ guide-level-explanation ] : #guide-level-explanation
76
99
100
+ ## For libraries
101
+
77
102
When using ` #![no_std] ` in a crate, that crate does not implicitly depend on ` std `
78
103
but depends on ` core ` instead. For example:
79
104
@@ -86,41 +111,105 @@ APIs that require a memory allocator are not available in `core`.
86
111
In order to use them, ` no_std ` Rust code must explicitly depend on the ` alloc ` crate:
87
112
88
113
``` rust
89
- extern crate alloc;
114
+ #[macro_use] extern crate alloc;
90
115
91
116
use core :: cell :: RefCell ;
92
117
use alloc :: rc :: Rc ;
93
118
```
94
119
120
+ Note: ` #[macro_use] ` imports the [ ` vec! ` ] and [ ` format! ` ] macros.
121
+
122
+ [ `vec!` ] : https://doc.rust-lang.org/alloc/macro.vec.html
123
+ [ `format!` ] : https://doc.rust-lang.org/alloc/macro.format.html
124
+
95
125
Like ` std ` and ` core ` , this dependency does not need to be declared in ` Cargo.toml `
96
126
since ` alloc ` is part of the standard library and distributed with Rust.
97
127
98
- The prelude (set of items that are implicitly in scope) for ` #![no_std] ` crates
128
+ The implicit prelude (set of items that are automatically in scope) for ` #![no_std] ` crates
99
129
does not assume the presence of the ` alloc ` crate, unlike the default prelude.
100
- So in such crates, items from ` alloc ` always need to be imported explicitly.
130
+ So such crates may need to import either that prelude or specific items explicitly.
101
131
For example:
102
132
103
133
``` rust
134
+ use alloc :: prelude :: * ;
135
+
136
+ // Or
137
+
138
+ use alloc :: string :: ToString ;
104
139
use alloc :: vec :: Vec ;
105
140
```
106
141
142
+ ## For programs¹
143
+
144
+ [ ¹] … and other roots of a dependency graph, such as ` staticlib ` s.
145
+
146
+ Compared to ` core ` , the ` alloc ` crate makes two additional requirements:
147
+
148
+ * A global heap memory allocator.
149
+
150
+ * An allocation error handler (that is not allowed to return).
151
+ This is called for example by ` Vec::push ` , whose own API is infallible,
152
+ when the allocator fails to allocate memory.
153
+
154
+ ` std ` provides both of these. So as long as it is present in the dependency graph,
155
+ nothing else is required even if some crates of the graph use ` alloc ` without ` std ` .
156
+
157
+ If ` std ` is not present they need to be defined explicitly,
158
+ somewhere in the dependency graph (not necessarily in the root crate).
159
+
160
+ * [ The ` #[global_allocator] ` attribute] [ global_allocator ] , on a ` static ` item
161
+ of a type that implements the ` GlobalAlloc ` trait,
162
+ defines the global allocator. It is stable in Rust 1.28.
163
+
164
+ * [ Tracking issue #51540 ] propose the ` #[alloc_error_handler] ` attribute
165
+ for a function with signature ` fn foo(_: Layout) -> ! ` .
166
+ As of this writing this attribute is implemented but unstable.
167
+
168
+ [ global_allocator ] : https://doc.rust-lang.org/nightly/std/alloc/#the-global_allocator-attribute
169
+ [ Tracking issue #51540 ] : https://github.com/rust-lang/rust/issues/51540
170
+
107
171
108
172
# Reference-level explanation
109
173
[ reference-level-explanation ] : #reference-level-explanation
110
174
111
175
The ` alloc ` crate already exists (marked unstable),
112
176
and every public API in it is already available in ` std ` .
113
177
114
- [ PR #51569 ] moves them around so that the module structure matches that of ` std ` ,
115
- and the public APIs become a subset:
116
- any path that starts with ` alloc:: ` should still be valid and point to the same item
178
+ Except for the ` alloc::prelude ` module, since [ PR #51569 ] the module structure is a subset
179
+ of that of ` std ` : every path that starts with ` alloc:: ` is still valid and point to the same item
117
180
after replacing that prefix with ` std:: ` (assuming both crates are available).
118
181
119
- All that remains is stabilizing the ` alloc ` crate itself and tweaking its doc-comment.
120
- (In particular, removing the “not intended for general usage” sentence
121
- and mention ` no_std ` instead.)
122
- Since it is the only remaining unstable crate tracked by [ tracking issue #27783 ] ,
123
- that issue can be closed after this RFC is implemented.
182
+ The concrete changes proposed by this RFC are:
183
+
184
+ * Stabilize ` extern crate alloc; `
185
+ (that is, change ` #![unstable] ` to ` #![stable] ` near the top of ` src/liballoc/lib.rs ` ).
186
+
187
+ * Stabilize the ` alloc::prelude ` module and its contents
188
+ (which is only re-exports of items that are themselves already stable).
189
+
190
+ * Stabilize the fact that the crate makes no more and no less than
191
+ the two requirements/assumptions of a global allocator and an allocation error handler
192
+ being provided for it, as described above.
193
+
194
+ The exact mechanism for [ providing the allocation error handler] [ Tracking issue #51540 ]
195
+ is not stabilized by this RFC.
196
+
197
+ In particular, this RFC proposes that the presence of a source of randomness
198
+ is * not* a requirement that the ` alloc ` crate can make.
199
+ This is contrary to what [ PR #51846 ] proposed,
200
+ and means that ` std::collections::hash_map::RandomState ` cannot be moved into ` alloc ` .
201
+
202
+ [ Tracking issue #27783 ] tracks “the ` std ` facade”:
203
+ crates whose contents are re-exported in ` std ` but also exist separately.
204
+ Other such crates have already been moved, merged, or stabilized,
205
+ such that ` alloc ` is the only remaining unstable one.
206
+ Therefore #27783 can serve as the tracking issue for this RFC
207
+ and can be closed once it is implemented.
208
+
209
+ [ PR #51569 ] : https://github.com/rust-lang/rust/pull/51569
210
+ [ PR #51846 ] : https://github.com/rust-lang/rust/pull/51846
211
+ [ Tracking issue #27783 ] : https://github.com/rust-lang/rust/issues/27783
212
+
124
213
125
214
The structure of the standard library is therefore:
126
215
@@ -134,8 +223,6 @@ The structure of the standard library is therefore:
134
223
* ` proc-macro ` : depends on parts of the compiler, typically only used at build-time
135
224
(in procedural macro crates or Cargo build scripts).
136
225
137
- [ PR #51569 ] : https://github.com/rust-lang/rust/pull/51569
138
- [ tracking issue #27783 ] : https://github.com/rust-lang/rust/issues/27783
139
226
140
227
141
228
# Drawbacks
@@ -148,22 +235,24 @@ for the standard library, given infinite time and resources.
148
235
149
236
In particular, could we have a single crate with some mechanism for selectively disabling
150
237
or enabling some of the crate’s components, depending on which runtime dependencies
151
- are available in targetted environments?
238
+ are available in targeted environments?
152
239
In that world, the ` no_std ` attribute and standard library crates other than ` std `
153
- would be unecessary .
240
+ would be unnecessary .
154
241
155
242
By stabilizing the ` alloc ` crate, we commit to having it − and its public API − exist “forever”.
156
243
157
244
158
245
# Rationale and alternatives
159
246
[ alternatives ] : #alternatives
160
247
248
+ ## Single-crate standard library
249
+
161
250
The ` core ` and the ` no_std ` attribute are already stable,
162
251
so in a sense it’s already too late for the “pure” version of the vision described above
163
252
where ` std ` really is the only standard library crate that exists.
164
253
165
254
It may still be [ desirable] to regroup the standard library into one crate,
166
- and it is proably still possible.
255
+ and it is probably still possible.
167
256
The ` core ` crate could be replaced with a set of ` pub use ` reexport
168
257
to maintained compatibility with existing users.
169
258
Whatever the eventual status is for ` core ` is,
@@ -174,10 +263,34 @@ While we want to leave the possibility open for it,
174
263
at the time of this writing there are no concrete plans
175
264
for implementing such a standard library crates unification any time soon.
176
265
So the only alternative to this RFC seems to be
177
- leaving heap allocation for ` no_std ` in unstable limbo for the forseeable future.
266
+ leaving heap allocation for ` no_std ` in unstable limbo for the foreseeable future.
178
267
179
268
[ desirable ] : https://aturon.github.io/2018/02/06/portability-vision/#the-vision
180
269
270
+ ## Require randomness
271
+
272
+ [ PR #51569 ] proposed adding a source of randomness to the other requirements
273
+ made by the ` alloc ` crate.
274
+ This would allow moving ` std::collections::hash_map::RandomState ` ,
275
+ and therefore ` HashMap ` (which has ` RandomState ` as a default type parameter),
276
+ into ` alloc ` .
277
+
278
+ This RFC chooses not to do this because it would make it difficult to use for example ` Vec<T> `
279
+ in environments where a source of randomness is not easily available.
280
+
281
+ I hope that the language will eventually make it possible to have ` HashMap ` in ` alloc `
282
+ without a default hasher type parameter, and have the same type in ` std ` with its current default.
283
+
284
+ Although I am not necessarily in favor
285
+ of continuing the increase of the number of crates in the standard library,
286
+ another solution for ` HashMap ` in ` no_std ` might be another intermediate crate
287
+ that depends on ` alloc ` and adds the randomness source requirement.
288
+
289
+ Additionally, with this RFC it should be possible to make https://crates.io/crates/hashmap_core
290
+ compatible with Stable Rust.
291
+ The downside of that crate is that although based on a copy of the same code,
292
+ it is a different type incompatible in the type system with ` std::collections::HashMap ` .
293
+
181
294
182
295
# Prior art
183
296
[ prior-art ] : #prior-art
@@ -202,3 +315,9 @@ It does provide a memory allocator through `malloc` and related functions, uncon
202
315
What really characterizes it is the assumption that a global allocator is available.
203
316
The name ` global_alloc ` was proposed.
204
317
(Although the crate doesn’t only contain the global allocator itself.)
318
+
319
+ * Should the ` alloc::prelude ` module be moved to ` alloc::prelude::v1 ` ?
320
+ This would make the ` alloc ` module structure a subset of ` std ` without exception.
321
+ However, since this prelude is not inserted automatically,
322
+ it is less likely that we’ll ever have a second version of it.
323
+ In that sense it is closer to ` std::io::prelude ` than ` std::prelude::v1 ` .
0 commit comments