Skip to content

Commit 2e83331

Browse files
committed
Add read_entry_boxed_in and get_boxed_info_in that use the allocator_api.
This commit adds a new `unsafe_alloc` feature that enhances existing functions with `allocator_api`-flavored allocators. Both functions will work with stable and nightly Rust.
1 parent 01b27af commit 2e83331

File tree

7 files changed

+144
-15
lines changed

7 files changed

+144
-15
lines changed

CHANGELOG.md

+22-2
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,39 @@
11
# Changelog
22

33
## uefi - [Unreleased]
4+
5+
### Added
46
- Implementations for the trait `EqStrUntilNul` now allow `?Sized` inputs. This means that
57
you can write `some_cstr16.eq_str_until_nul("test")` instead of
68
`some_cstr16.eq_str_until_nul(&"test")` now.
79
- Added `TryFrom<core::ffi::CStr>` implementation for `CStr8`.
810
- Added `Directory::read_entry_boxed` which works similar to `File::get_boxed_info`. This allows
9-
easier iteration over the entries in a directory.
11+
easier iteration over the entries in a directory. (requires the **alloc** feature)
12+
- Added `Directory::read_entry_boxed_in` and `File::get_boxed_info_in` that use the `allocator_api`
13+
feature. (requires the **unstable_alloc** feature)
1014
- Added an `core::error::Error` implementation for `Error` to ease
11-
integration with error-handling crates.
15+
integration with error-handling crates. (requires the **unstable** feature)
16+
17+
### Changed
18+
19+
### Removed
1220

1321
## uefi-macros - [Unreleased]
1422

23+
### Added
24+
25+
### Changed
26+
27+
### Removed
28+
1529
## uefi-services - [Unreleased]
1630

31+
### Added
32+
33+
### Changed
34+
35+
### Removed
36+
1737
## uefi - 0.18.0 (2022-11-15)
1838

1939
### Added

uefi-test-runner/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ publish = false
66
edition = "2021"
77

88
[dependencies]
9-
uefi = { path = "../uefi", features = ['alloc'] }
9+
uefi = { path = "../uefi", features = ["alloc", "unstable_alloc"] }
1010
uefi-services = { path = "../uefi-services" }
1111

1212
log = { version = "0.4.17", default-features = false }

uefi/Cargo.toml

+4
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,11 @@ logger = []
1919
# were observed on the VirtualBox UEFI implementation (see uefi-rs#121).
2020
# In those cases, this feature can be excluded by removing the default features.
2121
panic-on-logger-errors = []
22+
# Enables all generic functionality that requires unstable Rust language features. To use
23+
# features behind this feature gate, you usually need a nightly toolchain.
2224
unstable = []
25+
# Like the `unstable` feature but specific to `alloc`-related functionality.
26+
unstable_alloc = ["unstable", "alloc"]
2327

2428
[dependencies]
2529
bitflags = "1.3.1"

uefi/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
#![feature(ptr_metadata)]
6363
#![cfg_attr(feature = "alloc", feature(vec_into_raw_parts))]
6464
#![cfg_attr(feature = "unstable", feature(error_in_core))]
65+
#![cfg_attr(feature = "unstable_alloc", feature(allocator_api))]
6566
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
6667
#![no_std]
6768
// Enable some additional warnings and lints.

uefi/src/mem.rs

+56-8
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,19 @@
22
33
use crate::ResultExt;
44
use crate::{Result, Status};
5-
use ::alloc::{alloc, boxed::Box};
5+
use ::alloc::boxed::Box;
66
use core::alloc::Layout;
77
use core::fmt::Debug;
88
use core::slice;
99
use uefi::data_types::Align;
1010
use uefi::Error;
1111

12+
#[cfg(not(feature = "unstable_alloc"))]
13+
use ::alloc::alloc::{alloc, dealloc};
14+
15+
#[cfg(feature = "unstable_alloc")]
16+
use {core::alloc::Allocator, core::ptr::NonNull};
17+
1218
/// Helper to return owned versions of certain UEFI data structures on the heap in a [`Box`]. This
1319
/// function is intended to wrap low-level UEFI functions of this crate that
1420
/// - can consume an empty buffer without a panic to get the required buffer size in the errors
@@ -17,12 +23,24 @@ use uefi::Error;
1723
/// buffer size is sufficient, and
1824
/// - return a mutable typed reference that points to the same memory as the input buffer on
1925
/// success.
26+
///
27+
/// # Feature `unstable_alloc`
28+
/// By default, this feature works with Rust's default allocation mechanism. If you activate the
29+
/// `unstable_alloc`-feature, it uses the `allocator_api` instead. In that case, the function takes
30+
/// an additional parameter describing the specify allocator. You can use [`alloc::alloc::Global`]
31+
/// as default.
2032
pub fn make_boxed<
2133
'a,
34+
// The UEFI data structure.
2235
Data: Align + ?Sized + Debug + 'a,
2336
F: FnMut(&'a mut [u8]) -> Result<&'a mut Data, Option<usize>>,
37+
#[cfg(feature = "unstable_alloc")] A: Allocator,
2438
>(
39+
// A function to read the UEFI data structure into a provided buffer.
2540
mut fetch_data_fn: F,
41+
#[cfg(feature = "unstable_alloc")]
42+
// Allocator of the `allocator_api` feature. You can use `Global` as default.
43+
allocator: A,
2644
) -> Result<Box<Data>> {
2745
let required_size = match fetch_data_fn(&mut []).map_err(Error::split) {
2846
// This is the expected case: the empty buffer passed in is too
@@ -40,13 +58,23 @@ pub fn make_boxed<
4058
.unwrap()
4159
.pad_to_align();
4260

43-
// Allocate the buffer.
44-
let heap_buf: *mut u8 = unsafe {
45-
let ptr = alloc::alloc(layout);
46-
if ptr.is_null() {
47-
return Err(Status::OUT_OF_RESOURCES.into());
61+
// Allocate the buffer on the heap.
62+
let heap_buf: *mut u8 = {
63+
#[cfg(not(feature = "unstable_alloc"))]
64+
{
65+
let ptr = unsafe { alloc(layout) };
66+
if ptr.is_null() {
67+
return Err(Status::OUT_OF_RESOURCES.into());
68+
}
69+
ptr
4870
}
49-
ptr
71+
72+
#[cfg(feature = "unstable_alloc")]
73+
allocator
74+
.allocate(layout)
75+
.map_err(|_| <Status as Into<Error>>::into(Status::OUT_OF_RESOURCES))?
76+
.as_ptr()
77+
.cast::<u8>()
5078
};
5179

5280
// Read the data into the provided buffer.
@@ -59,7 +87,14 @@ pub fn make_boxed<
5987
let data: &mut Data = match data {
6088
Ok(data) => data,
6189
Err(err) => {
62-
unsafe { alloc::dealloc(heap_buf, layout) };
90+
#[cfg(not(feature = "unstable_alloc"))]
91+
unsafe {
92+
dealloc(heap_buf, layout)
93+
};
94+
#[cfg(feature = "unstable_alloc")]
95+
unsafe {
96+
allocator.deallocate(NonNull::new(heap_buf).unwrap(), layout)
97+
}
6398
return Err(err);
6499
}
65100
};
@@ -73,6 +108,8 @@ pub fn make_boxed<
73108
mod tests {
74109
use super::*;
75110
use crate::ResultExt;
111+
#[cfg(feature = "unstable_alloc")]
112+
use alloc::alloc::Global;
76113
use core::mem::{align_of, size_of};
77114

78115
/// Some simple dummy type to test [`make_boxed`].
@@ -169,11 +206,22 @@ mod tests {
169206
#[test]
170207
fn test_make_boxed_utility() {
171208
let fetch_data_fn = |buf| uefi_function_stub_read(buf);
209+
210+
#[cfg(not(feature = "unstable_alloc"))]
172211
let data: Box<SomeData> = make_boxed(fetch_data_fn).unwrap();
212+
213+
#[cfg(feature = "unstable_alloc")]
214+
let data: Box<SomeData> = make_boxed(fetch_data_fn, Global).unwrap();
173215
assert_eq!(&data.0, &[1, 2, 3, 4]);
174216

175217
let fetch_data_fn = |buf| uefi_function_stub_read(buf);
218+
219+
#[cfg(not(feature = "unstable_alloc"))]
176220
let data: Box<SomeDataAlign16> = make_boxed(fetch_data_fn).unwrap();
221+
222+
#[cfg(feature = "unstable_alloc")]
223+
let data: Box<SomeDataAlign16> = make_boxed(fetch_data_fn, Global).unwrap();
224+
177225
assert_eq!(&data.0 .0, &[1, 2, 3, 4]);
178226
}
179227
}

uefi/src/proto/media/file/dir.rs

+43-3
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ use super::{File, FileHandle, FileInfo, FromUefi, RegularFile};
22
use crate::data_types::Align;
33
use crate::Result;
44
use core::ffi::c_void;
5-
65
#[cfg(feature = "alloc")]
76
use {crate::mem::make_boxed, alloc::boxed::Box};
87

8+
#[cfg(feature = "unstable_alloc")]
9+
use {alloc::alloc::Global, core::alloc::Allocator};
10+
911
/// A `FileHandle` that is also a directory.
1012
///
1113
/// Use `File::into_type` or `Directory::new` to create a `Directory`. In
@@ -61,8 +63,7 @@ impl Directory {
6163
})
6264
}
6365

64-
/// Wrapper around [`Self::read_entry`] that returns an owned copy of the data. It has the same
65-
/// implications and requirements. On failure, the payload of `Err` is `()´.
66+
/// Wrapper around [`Self::read_entry_boxed_in`] that uses the [`Global`] allocator.
6667
#[cfg(feature = "alloc")]
6768
pub fn read_entry_boxed(&mut self) -> Result<Option<Box<FileInfo>>> {
6869
let read_entry_res = self.read_entry(&mut []);
@@ -79,7 +80,46 @@ impl Directory {
7980
maybe_info.expect("Should have more entries")
8081
})
8182
};
83+
84+
#[cfg(not(feature = "unstable_alloc"))]
85+
let file_info = make_boxed::<FileInfo, _>(fetch_data_fn)?;
86+
87+
#[cfg(feature = "unstable_alloc")]
88+
let file_info = make_boxed::<FileInfo, _, _>(fetch_data_fn, Global)?;
89+
90+
Ok(Some(file_info))
91+
}
92+
93+
/// Wrapper around [`Self::read_entry`] that returns an owned copy of the data. It has the same
94+
/// implications and requirements. On failure, the payload of `Err` is `()´.
95+
///
96+
/// It allows to use a custom allocator via the `allocator_api` feature.
97+
#[cfg(feature = "unstable_alloc")]
98+
pub fn read_entry_boxed_in<A: Allocator>(
99+
&mut self,
100+
allocator: A,
101+
) -> Result<Option<Box<FileInfo>>> {
102+
let read_entry_res = self.read_entry(&mut []);
103+
104+
// If no more entries are available, return early.
105+
if let Ok(None) = read_entry_res {
106+
return Ok(None);
107+
}
108+
109+
let fetch_data_fn = |buf| {
110+
self.read_entry(buf)
111+
// this is safe, as above, we checked that there are more entries
112+
.map(|maybe_info: Option<&mut FileInfo>| {
113+
maybe_info.expect("Should have more entries")
114+
})
115+
};
116+
117+
#[cfg(not(feature = "unstable_alloc"))]
82118
let file_info = make_boxed::<FileInfo, _>(fetch_data_fn)?;
119+
120+
#[cfg(feature = "unstable_alloc")]
121+
let file_info = make_boxed::<FileInfo, _, A>(fetch_data_fn, allocator)?;
122+
83123
Ok(Some(file_info))
84124
}
85125

uefi/src/proto/media/file/mod.rs

+17-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ use core::ffi::c_void;
1616
use core::fmt::Debug;
1717
use core::mem;
1818
use core::ptr;
19+
#[cfg(feature = "unstable_alloc")]
20+
use {alloc::alloc::Global, core::alloc::Allocator};
1921
#[cfg(feature = "alloc")]
2022
use {alloc::boxed::Box, uefi::mem::make_boxed};
2123

@@ -161,11 +163,25 @@ pub trait File: Sized {
161163
(self.imp().flush)(self.imp()).into()
162164
}
163165

166+
/// Wrapper around [`Self::get_boxed_info_in`] that uses the [`Global`] allocator.
164167
#[cfg(feature = "alloc")]
165-
/// Read the dynamically allocated info for a file.
166168
fn get_boxed_info<Info: FileProtocolInfo + ?Sized + Debug>(&mut self) -> Result<Box<Info>> {
167169
let fetch_data_fn = |buf| self.get_info::<Info>(buf);
170+
#[cfg(not(feature = "unstable_alloc"))]
168171
let file_info = make_boxed::<Info, _>(fetch_data_fn)?;
172+
#[cfg(feature = "unstable_alloc")]
173+
let file_info = make_boxed::<Info, _, _>(fetch_data_fn, Global)?;
174+
Ok(file_info)
175+
}
176+
177+
/// Read the dynamically allocated info for a file.
178+
#[cfg(feature = "unstable_alloc")]
179+
fn get_boxed_info_in<Info: FileProtocolInfo + ?Sized + Debug, A: Allocator>(
180+
&mut self,
181+
allocator: A,
182+
) -> Result<Box<Info>> {
183+
let fetch_data_fn = |buf| self.get_info::<Info>(buf);
184+
let file_info = make_boxed::<Info, _, A>(fetch_data_fn, allocator)?;
169185
Ok(file_info)
170186
}
171187

0 commit comments

Comments
 (0)