22
33//! Utilities for creating new [`DevicePaths`].
44//!
5- //! This module contains [`DevicePathBuilder`], as well as submodules
6- //! containing types for building each type of device path node.
5+ //! This module provides builders to construct device paths, as well as
6+ //! submodules containing types for building each type of device path node.
7+ //!
8+ //! - [`DevicePathBuilder`] to construct device paths into pre-allocated buffers
9+ //! - [`OwnedDevicePathBuilder`] for construction on the Rust heap
710//!
811//! [`DevicePaths`]: DevicePath
912
@@ -15,7 +18,10 @@ use core::fmt::{self, Display, Formatter};
1518use core:: mem:: MaybeUninit ;
1619
1720#[ cfg( feature = "alloc" ) ]
18- use alloc:: vec:: Vec ;
21+ use {
22+ alloc:: { boxed:: Box , vec:: Vec } ,
23+ core:: mem,
24+ } ;
1925
2026/// A builder for [`DevicePaths`].
2127///
@@ -74,14 +80,14 @@ use alloc::vec::Vec;
7480/// ```
7581#[ derive( Debug ) ]
7682pub struct DevicePathBuilder < ' a > {
77- storage : BuilderStorage < ' a > ,
83+ storage : BuilderStorageRef < ' a > ,
7884}
7985
8086impl < ' a > DevicePathBuilder < ' a > {
8187 /// Create a builder backed by a statically-sized buffer.
8288 pub const fn with_buf ( buf : & ' a mut [ MaybeUninit < u8 > ] ) -> Self {
8389 Self {
84- storage : BuilderStorage :: Buf { buf, offset : 0 } ,
90+ storage : BuilderStorageRef :: Buf { buf, offset : 0 } ,
8591 }
8692 }
8793
@@ -92,7 +98,7 @@ impl<'a> DevicePathBuilder<'a> {
9298 pub fn with_vec ( v : & ' a mut Vec < u8 > ) -> Self {
9399 v. clear ( ) ;
94100 Self {
95- storage : BuilderStorage :: Vec ( v) ,
101+ storage : BuilderStorageRef :: Vec ( v) ,
96102 }
97103 }
98104
@@ -107,15 +113,15 @@ impl<'a> DevicePathBuilder<'a> {
107113 let node_size = usize:: from ( node. size_in_bytes ( ) ?) ;
108114
109115 match & mut self . storage {
110- BuilderStorage :: Buf { buf, offset } => {
116+ BuilderStorageRef :: Buf { buf, offset } => {
111117 node. write_data (
112118 buf. get_mut ( * offset..* offset + node_size)
113119 . ok_or ( BuildError :: BufferTooSmall ) ?,
114120 ) ;
115121 * offset += node_size;
116122 }
117123 #[ cfg( feature = "alloc" ) ]
118- BuilderStorage :: Vec ( vec) => {
124+ BuilderStorageRef :: Vec ( vec) => {
119125 let old_size = vec. len ( ) ;
120126 vec. reserve ( node_size) ;
121127 let buf = & mut vec. spare_capacity_mut ( ) [ ..node_size] ;
@@ -138,11 +144,11 @@ impl<'a> DevicePathBuilder<'a> {
138144 let this = self . push ( & end:: Entire ) ?;
139145
140146 let data: & [ u8 ] = match & this. storage {
141- BuilderStorage :: Buf { buf, offset } => unsafe {
147+ BuilderStorageRef :: Buf { buf, offset } => unsafe {
142148 maybe_uninit_slice_assume_init_ref ( & buf[ ..* offset] )
143149 } ,
144150 #[ cfg( feature = "alloc" ) ]
145- BuilderStorage :: Vec ( vec) => vec,
151+ BuilderStorageRef :: Vec ( vec) => vec,
146152 } ;
147153
148154 let ptr: * const ( ) = data. as_ptr ( ) . cast ( ) ;
@@ -152,7 +158,7 @@ impl<'a> DevicePathBuilder<'a> {
152158
153159/// Reference to the backup storage for [`DevicePathBuilder`]
154160#[ derive( Debug ) ]
155- enum BuilderStorage < ' a > {
161+ enum BuilderStorageRef < ' a > {
156162 Buf {
157163 buf : & ' a mut [ MaybeUninit < u8 > ] ,
158164 offset : usize ,
@@ -194,6 +200,58 @@ impl Display for BuildError {
194200
195201impl core:: error:: Error for BuildError { }
196202
203+ /// Variant of [`DevicePathBuilder`] to construct a boxed [`DevicePath`].
204+ ///
205+ /// Using this builder is equivalent to calling [`DevicePath::to_boxed`] on a
206+ /// device path constructed by the normal builder.
207+ #[ derive( Debug ) ]
208+ #[ cfg( feature = "alloc" ) ]
209+ pub struct OwnedDevicePathBuilder {
210+ vec : Vec < u8 > ,
211+ }
212+
213+ #[ cfg( feature = "alloc" ) ]
214+ impl OwnedDevicePathBuilder {
215+ /// Creates a new builder.
216+ pub fn new ( ) -> Self {
217+ let vec = Vec :: new ( ) ;
218+ Self { vec }
219+ }
220+
221+ /// Add a node to the device path.
222+ ///
223+ /// An error will be returned if an [`END_ENTIRE`] node is passed to
224+ /// this function, as that node will be added when [`Self::finalize`] is
225+ /// called.
226+ ///
227+ /// [`END_ENTIRE`]: uefi::proto::device_path::DeviceSubType::END_ENTIRE
228+ pub fn push ( mut self , node : & dyn BuildNode ) -> Result < Self , BuildError > {
229+ let node_size = usize:: from ( node. size_in_bytes ( ) ?) ;
230+
231+ let old_size = self . vec . len ( ) ;
232+ self . vec . reserve ( node_size) ;
233+ let buf = & mut self . vec . spare_capacity_mut ( ) [ ..node_size] ;
234+ node. write_data ( buf) ;
235+ unsafe {
236+ self . vec . set_len ( old_size + node_size) ;
237+ }
238+ Ok ( self )
239+ }
240+
241+ /// Add an [`END_ENTIRE`] node and return the resulting [`DevicePath`].
242+ ///
243+ /// This method consumes the builder.
244+ ///
245+ /// [`END_ENTIRE`]: uefi::proto::device_path::DeviceSubType::END_ENTIRE
246+ pub fn finalize ( self ) -> Result < Box < DevicePath > , BuildError > {
247+ let this = self . push ( & end:: Entire ) ?;
248+ let boxed = this. vec . into_boxed_slice ( ) ;
249+ // SAFETY: This is safe as a DevicePath has the same layout.
250+ let dvp = unsafe { mem:: transmute ( boxed) } ;
251+ Ok ( dvp)
252+ }
253+ }
254+
197255/// Trait for types that can be used to build a node via
198256/// [`DevicePathBuilder::push`].
199257///
0 commit comments