Skip to content

Commit 3a2540e

Browse files
committed
rust: import upstream alloc crate
This is a subset of the Rust standard library `alloc` crate, version 1.62.0, licensed under "Apache-2.0 OR MIT", from: https://github.com/rust-lang/rust/tree/1.62.0/library/alloc/src The files are copied as-is, with no modifications whatsoever (not even adding the SPDX identifiers). For copyright details, please see: https://github.com/rust-lang/rust/blob/1.62.0/COPYRIGHT The next patch modifies these files as needed for use within the kernel. This patch split allows reviewers to double-check the import and to clearly see the differences introduced. Vendoring `alloc`, at least for the moment, allows us to have fallible allocations support (i.e. the `try_*` versions of methods which return a `Result` instead of panicking) early on. It also gives a bit more freedom to experiment with new interfaces and to iterate quickly. Eventually, the goal is to have everything the kernel needs in upstream `alloc` and drop it from the kernel tree. For a summary of work on `alloc` happening upstream, please see: #408 Co-developed-by: Alex Gaynor <[email protected]> Signed-off-by: Alex Gaynor <[email protected]> Co-developed-by: Wedson Almeida Filho <[email protected]> Signed-off-by: Wedson Almeida Filho <[email protected]> Signed-off-by: Miguel Ojeda <[email protected]>
1 parent c4fcf3f commit 3a2540e

22 files changed

+14960
-0
lines changed

rust/alloc/alloc.rs

+438
Large diffs are not rendered by default.

rust/alloc/borrow.rs

+496
Large diffs are not rendered by default.

rust/alloc/boxed.rs

+2,024
Large diffs are not rendered by default.

rust/alloc/boxed/thin.rs

+215
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
// Based on
2+
// https://github.com/matthieu-m/rfc2580/blob/b58d1d3cba0d4b5e859d3617ea2d0943aaa31329/examples/thin.rs
3+
// by matthieu-m
4+
use crate::alloc::{self, Layout, LayoutError};
5+
use core::fmt::{self, Debug, Display, Formatter};
6+
use core::marker::{PhantomData, Unsize};
7+
use core::mem;
8+
use core::ops::{Deref, DerefMut};
9+
use core::ptr::Pointee;
10+
use core::ptr::{self, NonNull};
11+
12+
/// ThinBox.
13+
///
14+
/// A thin pointer for heap allocation, regardless of T.
15+
///
16+
/// # Examples
17+
///
18+
/// ```
19+
/// #![feature(thin_box)]
20+
/// use std::boxed::ThinBox;
21+
///
22+
/// let five = ThinBox::new(5);
23+
/// let thin_slice = ThinBox::<[i32]>::new_unsize([1, 2, 3, 4]);
24+
///
25+
/// use std::mem::{size_of, size_of_val};
26+
/// let size_of_ptr = size_of::<*const ()>();
27+
/// assert_eq!(size_of_ptr, size_of_val(&five));
28+
/// assert_eq!(size_of_ptr, size_of_val(&thin_slice));
29+
/// ```
30+
#[unstable(feature = "thin_box", issue = "92791")]
31+
pub struct ThinBox<T: ?Sized> {
32+
ptr: WithHeader<<T as Pointee>::Metadata>,
33+
_marker: PhantomData<T>,
34+
}
35+
36+
#[unstable(feature = "thin_box", issue = "92791")]
37+
impl<T> ThinBox<T> {
38+
/// Moves a type to the heap with its `Metadata` stored in the heap allocation instead of on
39+
/// the stack.
40+
///
41+
/// # Examples
42+
///
43+
/// ```
44+
/// #![feature(thin_box)]
45+
/// use std::boxed::ThinBox;
46+
///
47+
/// let five = ThinBox::new(5);
48+
/// ```
49+
#[cfg(not(no_global_oom_handling))]
50+
pub fn new(value: T) -> Self {
51+
let meta = ptr::metadata(&value);
52+
let ptr = WithHeader::new(meta, value);
53+
ThinBox { ptr, _marker: PhantomData }
54+
}
55+
}
56+
57+
#[unstable(feature = "thin_box", issue = "92791")]
58+
impl<Dyn: ?Sized> ThinBox<Dyn> {
59+
/// Moves a type to the heap with its `Metadata` stored in the heap allocation instead of on
60+
/// the stack.
61+
///
62+
/// # Examples
63+
///
64+
/// ```
65+
/// #![feature(thin_box)]
66+
/// use std::boxed::ThinBox;
67+
///
68+
/// let thin_slice = ThinBox::<[i32]>::new_unsize([1, 2, 3, 4]);
69+
/// ```
70+
#[cfg(not(no_global_oom_handling))]
71+
pub fn new_unsize<T>(value: T) -> Self
72+
where
73+
T: Unsize<Dyn>,
74+
{
75+
let meta = ptr::metadata(&value as &Dyn);
76+
let ptr = WithHeader::new(meta, value);
77+
ThinBox { ptr, _marker: PhantomData }
78+
}
79+
}
80+
81+
#[unstable(feature = "thin_box", issue = "92791")]
82+
impl<T: ?Sized + Debug> Debug for ThinBox<T> {
83+
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
84+
Debug::fmt(self.deref(), f)
85+
}
86+
}
87+
88+
#[unstable(feature = "thin_box", issue = "92791")]
89+
impl<T: ?Sized + Display> Display for ThinBox<T> {
90+
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
91+
Display::fmt(self.deref(), f)
92+
}
93+
}
94+
95+
#[unstable(feature = "thin_box", issue = "92791")]
96+
impl<T: ?Sized> Deref for ThinBox<T> {
97+
type Target = T;
98+
99+
fn deref(&self) -> &T {
100+
let value = self.data();
101+
let metadata = self.meta();
102+
let pointer = ptr::from_raw_parts(value as *const (), metadata);
103+
unsafe { &*pointer }
104+
}
105+
}
106+
107+
#[unstable(feature = "thin_box", issue = "92791")]
108+
impl<T: ?Sized> DerefMut for ThinBox<T> {
109+
fn deref_mut(&mut self) -> &mut T {
110+
let value = self.data();
111+
let metadata = self.meta();
112+
let pointer = ptr::from_raw_parts_mut::<T>(value as *mut (), metadata);
113+
unsafe { &mut *pointer }
114+
}
115+
}
116+
117+
#[unstable(feature = "thin_box", issue = "92791")]
118+
impl<T: ?Sized> Drop for ThinBox<T> {
119+
fn drop(&mut self) {
120+
unsafe {
121+
let value = self.deref_mut();
122+
let value = value as *mut T;
123+
self.ptr.drop::<T>(value);
124+
}
125+
}
126+
}
127+
128+
#[unstable(feature = "thin_box", issue = "92791")]
129+
impl<T: ?Sized> ThinBox<T> {
130+
fn meta(&self) -> <T as Pointee>::Metadata {
131+
// Safety:
132+
// - NonNull and valid.
133+
unsafe { *self.ptr.header() }
134+
}
135+
136+
fn data(&self) -> *mut u8 {
137+
self.ptr.value()
138+
}
139+
}
140+
141+
/// A pointer to type-erased data, guaranteed to have a header `H` before the pointed-to location.
142+
struct WithHeader<H>(NonNull<u8>, PhantomData<H>);
143+
144+
impl<H> WithHeader<H> {
145+
#[cfg(not(no_global_oom_handling))]
146+
fn new<T>(header: H, value: T) -> WithHeader<H> {
147+
let value_layout = Layout::new::<T>();
148+
let Ok((layout, value_offset)) = Self::alloc_layout(value_layout) else {
149+
// We pass an empty layout here because we do not know which layout caused the
150+
// arithmetic overflow in `Layout::extend` and `handle_alloc_error` takes `Layout` as
151+
// its argument rather than `Result<Layout, LayoutError>`, also this function has been
152+
// stable since 1.28 ._.
153+
//
154+
// On the other hand, look at this gorgeous turbofish!
155+
alloc::handle_alloc_error(Layout::new::<()>());
156+
};
157+
158+
unsafe {
159+
let ptr = alloc::alloc(layout);
160+
161+
if ptr.is_null() {
162+
alloc::handle_alloc_error(layout);
163+
}
164+
// Safety:
165+
// - The size is at least `aligned_header_size`.
166+
let ptr = ptr.add(value_offset) as *mut _;
167+
168+
let ptr = NonNull::new_unchecked(ptr);
169+
170+
let result = WithHeader(ptr, PhantomData);
171+
ptr::write(result.header(), header);
172+
ptr::write(result.value().cast(), value);
173+
174+
result
175+
}
176+
}
177+
178+
// Safety:
179+
// - Assumes that `value` can be dereferenced.
180+
unsafe fn drop<T: ?Sized>(&self, value: *mut T) {
181+
unsafe {
182+
// SAFETY: Layout must have been computable if we're in drop
183+
let (layout, value_offset) =
184+
Self::alloc_layout(Layout::for_value_raw(value)).unwrap_unchecked();
185+
186+
ptr::drop_in_place::<T>(value);
187+
// We only drop the value because the Pointee trait requires that the metadata is copy
188+
// aka trivially droppable
189+
alloc::dealloc(self.0.as_ptr().sub(value_offset), layout);
190+
}
191+
}
192+
193+
fn header(&self) -> *mut H {
194+
// Safety:
195+
// - At least `size_of::<H>()` bytes are allocated ahead of the pointer.
196+
// - We know that H will be aligned because the middle pointer is aligned to the greater
197+
// of the alignment of the header and the data and the header size includes the padding
198+
// needed to align the header. Subtracting the header size from the aligned data pointer
199+
// will always result in an aligned header pointer, it just may not point to the
200+
// beginning of the allocation.
201+
unsafe { self.0.as_ptr().sub(Self::header_size()) as *mut H }
202+
}
203+
204+
fn value(&self) -> *mut u8 {
205+
self.0.as_ptr()
206+
}
207+
208+
const fn header_size() -> usize {
209+
mem::size_of::<H>()
210+
}
211+
212+
fn alloc_layout(value_layout: Layout) -> Result<(Layout, usize), LayoutError> {
213+
Layout::new::<H>().extend(value_layout)
214+
}
215+
}

rust/alloc/collections/mod.rs

+154
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
//! Collection types.
2+
3+
#![stable(feature = "rust1", since = "1.0.0")]
4+
5+
#[cfg(not(no_global_oom_handling))]
6+
pub mod binary_heap;
7+
#[cfg(not(no_global_oom_handling))]
8+
mod btree;
9+
#[cfg(not(no_global_oom_handling))]
10+
pub mod linked_list;
11+
#[cfg(not(no_global_oom_handling))]
12+
pub mod vec_deque;
13+
14+
#[cfg(not(no_global_oom_handling))]
15+
#[stable(feature = "rust1", since = "1.0.0")]
16+
pub mod btree_map {
17+
//! An ordered map based on a B-Tree.
18+
#[stable(feature = "rust1", since = "1.0.0")]
19+
pub use super::btree::map::*;
20+
}
21+
22+
#[cfg(not(no_global_oom_handling))]
23+
#[stable(feature = "rust1", since = "1.0.0")]
24+
pub mod btree_set {
25+
//! An ordered set based on a B-Tree.
26+
#[stable(feature = "rust1", since = "1.0.0")]
27+
pub use super::btree::set::*;
28+
}
29+
30+
#[cfg(not(no_global_oom_handling))]
31+
#[stable(feature = "rust1", since = "1.0.0")]
32+
#[doc(no_inline)]
33+
pub use binary_heap::BinaryHeap;
34+
35+
#[cfg(not(no_global_oom_handling))]
36+
#[stable(feature = "rust1", since = "1.0.0")]
37+
#[doc(no_inline)]
38+
pub use btree_map::BTreeMap;
39+
40+
#[cfg(not(no_global_oom_handling))]
41+
#[stable(feature = "rust1", since = "1.0.0")]
42+
#[doc(no_inline)]
43+
pub use btree_set::BTreeSet;
44+
45+
#[cfg(not(no_global_oom_handling))]
46+
#[stable(feature = "rust1", since = "1.0.0")]
47+
#[doc(no_inline)]
48+
pub use linked_list::LinkedList;
49+
50+
#[cfg(not(no_global_oom_handling))]
51+
#[stable(feature = "rust1", since = "1.0.0")]
52+
#[doc(no_inline)]
53+
pub use vec_deque::VecDeque;
54+
55+
use crate::alloc::{Layout, LayoutError};
56+
use core::fmt::Display;
57+
58+
/// The error type for `try_reserve` methods.
59+
#[derive(Clone, PartialEq, Eq, Debug)]
60+
#[stable(feature = "try_reserve", since = "1.57.0")]
61+
pub struct TryReserveError {
62+
kind: TryReserveErrorKind,
63+
}
64+
65+
impl TryReserveError {
66+
/// Details about the allocation that caused the error
67+
#[inline]
68+
#[must_use]
69+
#[unstable(
70+
feature = "try_reserve_kind",
71+
reason = "Uncertain how much info should be exposed",
72+
issue = "48043"
73+
)]
74+
pub fn kind(&self) -> TryReserveErrorKind {
75+
self.kind.clone()
76+
}
77+
}
78+
79+
/// Details of the allocation that caused a `TryReserveError`
80+
#[derive(Clone, PartialEq, Eq, Debug)]
81+
#[unstable(
82+
feature = "try_reserve_kind",
83+
reason = "Uncertain how much info should be exposed",
84+
issue = "48043"
85+
)]
86+
pub enum TryReserveErrorKind {
87+
/// Error due to the computed capacity exceeding the collection's maximum
88+
/// (usually `isize::MAX` bytes).
89+
CapacityOverflow,
90+
91+
/// The memory allocator returned an error
92+
AllocError {
93+
/// The layout of allocation request that failed
94+
layout: Layout,
95+
96+
#[doc(hidden)]
97+
#[unstable(
98+
feature = "container_error_extra",
99+
issue = "none",
100+
reason = "\
101+
Enable exposing the allocator’s custom error value \
102+
if an associated type is added in the future: \
103+
https://github.com/rust-lang/wg-allocators/issues/23"
104+
)]
105+
non_exhaustive: (),
106+
},
107+
}
108+
109+
#[unstable(
110+
feature = "try_reserve_kind",
111+
reason = "Uncertain how much info should be exposed",
112+
issue = "48043"
113+
)]
114+
impl From<TryReserveErrorKind> for TryReserveError {
115+
#[inline]
116+
fn from(kind: TryReserveErrorKind) -> Self {
117+
Self { kind }
118+
}
119+
}
120+
121+
#[unstable(feature = "try_reserve_kind", reason = "new API", issue = "48043")]
122+
impl From<LayoutError> for TryReserveErrorKind {
123+
/// Always evaluates to [`TryReserveErrorKind::CapacityOverflow`].
124+
#[inline]
125+
fn from(_: LayoutError) -> Self {
126+
TryReserveErrorKind::CapacityOverflow
127+
}
128+
}
129+
130+
#[stable(feature = "try_reserve", since = "1.57.0")]
131+
impl Display for TryReserveError {
132+
fn fmt(
133+
&self,
134+
fmt: &mut core::fmt::Formatter<'_>,
135+
) -> core::result::Result<(), core::fmt::Error> {
136+
fmt.write_str("memory allocation failed")?;
137+
let reason = match self.kind {
138+
TryReserveErrorKind::CapacityOverflow => {
139+
" because the computed capacity exceeded the collection's maximum"
140+
}
141+
TryReserveErrorKind::AllocError { .. } => {
142+
" because the memory allocator returned a error"
143+
}
144+
};
145+
fmt.write_str(reason)
146+
}
147+
}
148+
149+
/// An intermediate trait for specialization of `Extend`.
150+
#[doc(hidden)]
151+
trait SpecExtend<I: IntoIterator> {
152+
/// Extends `self` with the contents of the given iterator.
153+
fn spec_extend(&mut self, iter: I);
154+
}

0 commit comments

Comments
 (0)