22
33use crate :: ResultExt ;
44use crate :: { Result , Status } ;
5- use :: alloc:: { alloc , boxed:: Box } ;
5+ use :: alloc:: boxed:: Box ;
66use core:: alloc:: Layout ;
77use core:: fmt:: Debug ;
88use core:: slice;
99use uefi:: data_types:: Align ;
1010use 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.
2032pub 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<
73108mod 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}
0 commit comments