Skip to content

Commit 9e7bbfa

Browse files
BennoLossinojeda
authored andcommitted
rust: alloc: introduce ArrayLayout
When allocating memory for arrays using allocators, the `Layout::array` function is typically used. It returns a result, since the given size might be too big. However, `Vec` and its iterators store their allocated capacity and thus they already did check that the size is not too big. The `ArrayLayout` type provides this exact behavior, as it can be infallibly converted into a `Layout`. Instead of a `usize` capacity, `Vec` and other similar array-storing types can use `ArrayLayout` instead. Reviewed-by: Gary Guo <gary@garyguo.net> Signed-off-by: Benno Lossin <benno.lossin@proton.me> Signed-off-by: Danilo Krummrich <dakr@kernel.org> Link: https://lore.kernel.org/r/20241004154149.93856-16-dakr@kernel.org [ Formatted a few comments. - Miguel ] Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
1 parent e1044c2 commit 9e7bbfa

File tree

2 files changed

+92
-0
lines changed

2 files changed

+92
-0
lines changed

rust/kernel/alloc.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#[cfg(not(any(test, testlib)))]
66
pub mod allocator;
77
pub mod kbox;
8+
pub mod layout;
89
pub mod vec_ext;
910

1011
#[cfg(any(test, testlib))]

rust/kernel/alloc/layout.rs

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
//! Memory layout.
4+
//!
5+
//! Custom layout types extending or improving [`Layout`].
6+
7+
use core::{alloc::Layout, marker::PhantomData};
8+
9+
/// Error when constructing an [`ArrayLayout`].
10+
pub struct LayoutError;
11+
12+
/// A layout for an array `[T; n]`.
13+
///
14+
/// # Invariants
15+
///
16+
/// - `len * size_of::<T>() <= isize::MAX`.
17+
pub struct ArrayLayout<T> {
18+
len: usize,
19+
_phantom: PhantomData<fn() -> T>,
20+
}
21+
22+
impl<T> Clone for ArrayLayout<T> {
23+
fn clone(&self) -> Self {
24+
*self
25+
}
26+
}
27+
impl<T> Copy for ArrayLayout<T> {}
28+
29+
const ISIZE_MAX: usize = isize::MAX as usize;
30+
31+
impl<T> ArrayLayout<T> {
32+
/// Creates a new layout for `[T; 0]`.
33+
pub const fn empty() -> Self {
34+
// INVARIANT: `0 * size_of::<T>() <= isize::MAX`.
35+
Self {
36+
len: 0,
37+
_phantom: PhantomData,
38+
}
39+
}
40+
41+
/// Creates a new layout for `[T; len]`.
42+
///
43+
/// # Errors
44+
///
45+
/// When `len * size_of::<T>()` overflows or when `len * size_of::<T>() > isize::MAX`.
46+
pub const fn new(len: usize) -> Result<Self, LayoutError> {
47+
match len.checked_mul(core::mem::size_of::<T>()) {
48+
Some(len) if len <= ISIZE_MAX => {
49+
// INVARIANT: We checked above that `len * size_of::<T>() <= isize::MAX`.
50+
Ok(Self {
51+
len,
52+
_phantom: PhantomData,
53+
})
54+
}
55+
_ => Err(LayoutError),
56+
}
57+
}
58+
59+
/// Creates a new layout for `[T; len]`.
60+
///
61+
/// # Safety
62+
///
63+
/// `len` must be a value, for which `len * size_of::<T>() <= isize::MAX` is true.
64+
pub unsafe fn new_unchecked(len: usize) -> Self {
65+
// INVARIANT: By the safety requirements of this function
66+
// `len * size_of::<T>() <= isize::MAX`.
67+
Self {
68+
len,
69+
_phantom: PhantomData,
70+
}
71+
}
72+
73+
/// Returns the number of array elements represented by this layout.
74+
pub const fn len(&self) -> usize {
75+
self.len
76+
}
77+
78+
/// Returns `true` when no array elements are represented by this layout.
79+
pub const fn is_empty(&self) -> bool {
80+
self.len == 0
81+
}
82+
}
83+
84+
impl<T> From<ArrayLayout<T>> for Layout {
85+
fn from(value: ArrayLayout<T>) -> Self {
86+
let res = Layout::array::<T>(value.len);
87+
// SAFETY: By the type invariant of `ArrayLayout` we have
88+
// `len * size_of::<T>() <= isize::MAX` and thus the result must be `Ok`.
89+
unsafe { res.unwrap_unchecked() }
90+
}
91+
}

0 commit comments

Comments
 (0)