66//! containing types for building each type of device path node.
77//!
88//! [`DevicePaths`]: DevicePath
9-
109pub use crate :: proto:: device_path:: device_path_gen:: build:: * ;
10+ use alloc:: boxed:: Box ;
11+ use alloc:: vec;
1112
1213use crate :: polyfill:: { maybe_uninit_slice_as_mut_ptr, maybe_uninit_slice_assume_init_ref} ;
1314use crate :: proto:: device_path:: { DevicePath , DevicePathNode } ;
@@ -16,11 +17,20 @@ use core::mem::MaybeUninit;
1617
1718#[ cfg( feature = "alloc" ) ]
1819use alloc:: vec:: Vec ;
20+ use core:: mem;
21+ use uefi:: boot;
22+ use uefi:: mem:: PoolAllocation ;
23+ use uefi:: proto:: device_path:: PoolDevicePath ;
24+ use uefi_raw:: table:: boot:: MemoryType ;
1925
2026/// A builder for [`DevicePaths`].
2127///
22- /// The builder can be constructed with either a fixed-length buffer or
23- /// (if the `alloc` feature is enabled) a `Vec`.
28+ /// The builder has multiple constructors affecting the ownership of the
29+ /// resulting device path:
30+ ///
31+ /// - [`DevicePathBuilder::with_buf`]
32+ /// - [`DevicePathBuilder::with_uefi_heap`]
33+ /// - [`DevicePathBuilder::with_rust_heap`]
2434///
2535/// Nodes are added via the [`push`] method. To construct a node, use one
2636/// of the structs in these submodules:
@@ -78,21 +88,27 @@ pub struct DevicePathBuilder<'a> {
7888}
7989
8090impl < ' a > DevicePathBuilder < ' a > {
81- /// Create a builder backed by a statically-sized buffer .
91+ /// Create a builder that will return [`BuiltDevicePath::Buf`] .
8292 pub const fn with_buf ( buf : & ' a mut [ MaybeUninit < u8 > ] ) -> Self {
8393 Self {
8494 storage : BuilderStorage :: Buf { buf, offset : 0 } ,
8595 }
8696 }
8797
88- /// Create a builder backed by a `Vec`.
89- ///
90- /// The `Vec` is cleared before use.
98+ /// Create a builder that will return [`BuiltDevicePath::UefiHeap`].
99+ pub fn with_uefi_heap ( ) -> Self {
100+ // TODO propagate result?
101+ let ptr = { boot:: allocate_pool ( MemoryType :: LOADER_DATA , 1 ) . unwrap ( ) } ;
102+ Self {
103+ storage : BuilderStorage :: UefiHeap ( PoolAllocation :: new ( ptr) ) ,
104+ }
105+ }
106+
107+ /// Create a builder that will return [`BuiltDevicePath::Boxed`].
91108 #[ cfg( feature = "alloc" ) ]
92- pub fn with_vec ( v : & ' a mut Vec < u8 > ) -> Self {
93- v. clear ( ) ;
109+ pub const fn with_rust_heap ( ) -> Self {
94110 Self {
95- storage : BuilderStorage :: Vec ( v ) ,
111+ storage : BuilderStorage :: Boxed ( vec :: Vec :: new ( ) ) ,
96112 }
97113 }
98114
@@ -114,8 +130,11 @@ impl<'a> DevicePathBuilder<'a> {
114130 ) ;
115131 * offset += node_size;
116132 }
133+ BuiltDevicePath :: UefiHeap ( _pool) => {
134+ todo ! ( )
135+ }
117136 #[ cfg( feature = "alloc" ) ]
118- BuilderStorage :: Vec ( vec) => {
137+ BuilderStorage :: Boxed ( vec) => {
119138 let old_size = vec. len ( ) ;
120139 vec. reserve ( node_size) ;
121140 let buf = & mut vec. spare_capacity_mut ( ) [ ..node_size] ;
@@ -129,24 +148,33 @@ impl<'a> DevicePathBuilder<'a> {
129148 Ok ( self )
130149 }
131150
132- /// Add an [`END_ENTIRE`] node and return the resulting [`DevicePath`].
151+ // todo extend method (multiple push)
152+
153+ /// Add an [`END_ENTIRE`] node and return [`BuiltDevicePath`], depending
154+ /// on the chosen builder strategy.
133155 ///
134156 /// This method consumes the builder.
135157 ///
136158 /// [`END_ENTIRE`]: uefi::proto::device_path::DeviceSubType::END_ENTIRE
137- pub fn finalize ( self ) -> Result < & ' a DevicePath , BuildError > {
159+ pub fn finalize ( self ) -> Result < BuiltDevicePath < ' a > , BuildError > {
138160 let this = self . push ( & end:: Entire ) ?;
139161
140- let data : & [ u8 ] = match & this. storage {
162+ match this. storage {
141163 BuilderStorage :: Buf { buf, offset } => unsafe {
142- maybe_uninit_slice_assume_init_ref ( & buf[ ..* offset] )
164+ let data = maybe_uninit_slice_assume_init_ref ( & buf[ ..offset] ) ;
165+ let ptr: * const ( ) = data. as_ptr ( ) . cast ( ) ;
166+ let path = & * ptr_meta:: from_raw_parts ( ptr, data. len ( ) ) ;
167+ Ok ( BuiltDevicePath :: Buf ( path) )
143168 } ,
169+ BuilderStorage :: UefiHeap ( pool) => Ok ( BuiltDevicePath :: UefiHeap ( PoolDevicePath ( pool) ) ) ,
144170 #[ cfg( feature = "alloc" ) ]
145- BuilderStorage :: Vec ( vec) => vec,
146- } ;
147-
148- let ptr: * const ( ) = data. as_ptr ( ) . cast ( ) ;
149- Ok ( unsafe { & * ptr_meta:: from_raw_parts ( ptr, data. len ( ) ) } )
171+ BuilderStorage :: Boxed ( vec) => {
172+ let data = vec. into_boxed_slice ( ) ;
173+ // SAFETY: Same layout, trivially safe.
174+ let device_path = unsafe { mem:: transmute ( data) } ;
175+ Ok ( BuiltDevicePath :: Boxed ( device_path) )
176+ }
177+ }
150178 }
151179}
152180
@@ -158,8 +186,23 @@ enum BuilderStorage<'a> {
158186 offset : usize ,
159187 } ,
160188
189+ UefiHeap ( PoolAllocation ) ,
190+
191+ #[ cfg( feature = "alloc" ) ]
192+ Boxed ( Vec < u8 > ) ,
193+ }
194+
195+ /// The device path that is build by [`DevicePathBuilder`].
196+ ///
197+ /// This directly depends on [`BuilderStorage`].
198+ pub enum BuiltDevicePath < ' a > {
199+ /// Returns a reference to the provided buffer ([`BuilderStorage::Boxed`]).
200+ Buf ( & ' a DevicePath ) ,
201+ /// Owned value on the UEFI heap.
202+ UefiHeap ( PoolDevicePath ) ,
161203 #[ cfg( feature = "alloc" ) ]
162- Vec ( & ' a mut Vec < u8 > ) ,
204+ /// Boxed value on the Rust heap a reference to the provided buffer ([`BuilderStorage::Boxed`]).
205+ Boxed ( Box < DevicePath > ) ,
163206}
164207
165208/// Error type used by [`DevicePathBuilder`].
@@ -254,7 +297,7 @@ mod tests {
254297 assert ! ( acpi:: AdrSlice :: new( & [ ] ) . is_none( ) ) ;
255298
256299 let mut v = Vec :: new ( ) ;
257- let path = DevicePathBuilder :: with_vec ( & mut v)
300+ let path = DevicePathBuilder :: with_rust_heap ( & mut v)
258301 . push ( & acpi:: Adr {
259302 adr : acpi:: AdrSlice :: new ( & [ 1 , 2 ] ) . unwrap ( ) ,
260303 } ) ?
@@ -282,7 +325,7 @@ mod tests {
282325 #[ test]
283326 fn test_acpi_expanded ( ) -> Result < ( ) , BuildError > {
284327 let mut v = Vec :: new ( ) ;
285- let path = DevicePathBuilder :: with_vec ( & mut v)
328+ let path = DevicePathBuilder :: with_rust_heap ( & mut v)
286329 . push ( & acpi:: Expanded {
287330 hid : 1 ,
288331 uid : 2 ,
@@ -334,7 +377,7 @@ mod tests {
334377 fn test_messaging_rest_service ( ) -> Result < ( ) , BuildError > {
335378 let mut v = Vec :: new ( ) ;
336379 let vendor_guid = guid ! ( "a1005a90-6591-4596-9bab-1c4249a6d4ff" ) ;
337- let path = DevicePathBuilder :: with_vec ( & mut v)
380+ let path = DevicePathBuilder :: with_rust_heap ( & mut v)
338381 . push ( & messaging:: RestService {
339382 service_type : RestServiceType :: REDFISH ,
340383 access_mode : RestServiceAccessMode :: IN_BAND ,
@@ -390,7 +433,7 @@ mod tests {
390433 fn test_build_with_packed_node ( ) -> Result < ( ) , BuildError > {
391434 // Build a path with both a statically-sized and DST nodes.
392435 let mut v = Vec :: new ( ) ;
393- let path1 = DevicePathBuilder :: with_vec ( & mut v)
436+ let path1 = DevicePathBuilder :: with_rust_heap ( & mut v)
394437 . push ( & acpi:: Acpi {
395438 hid : 0x41d0_0a03 ,
396439 uid : 0x0000_0000 ,
@@ -404,7 +447,7 @@ mod tests {
404447 // Create a second path by copying in the packed nodes from the
405448 // first path.
406449 let mut v = Vec :: new ( ) ;
407- let mut builder = DevicePathBuilder :: with_vec ( & mut v) ;
450+ let mut builder = DevicePathBuilder :: with_rust_heap ( & mut v) ;
408451 for node in path1. node_iter ( ) {
409452 builder = builder. push ( & node) ?;
410453 }
@@ -492,7 +535,7 @@ mod tests {
492535 #[ test]
493536 fn test_ipv4_configuration_example ( ) -> Result < ( ) , BuildError > {
494537 let mut v = Vec :: new ( ) ;
495- let path = DevicePathBuilder :: with_vec ( & mut v)
538+ let path = DevicePathBuilder :: with_rust_heap ( & mut v)
496539 . push ( & acpi:: Acpi {
497540 hid : 0x41d0_0a03 ,
498541 uid : 0x0000_0000 ,
0 commit comments