Skip to content

Commit d6b5811

Browse files
committed
new builder lol
1 parent 859cfc3 commit d6b5811

File tree

2 files changed

+73
-12
lines changed

2 files changed

+73
-12
lines changed

uefi-test-runner/src/proto/shell.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
// SPDX-License-Identifier: MIT OR Apache-2.0
22

3-
use uefi::boot::ScopedProtocol;
3+
use uefi::boot::{OpenProtocolAttributes, OpenProtocolParams, ScopedProtocol};
4+
use uefi::proto::device_path::DevicePath;
5+
use uefi::proto::device_path::text::{AllowShortcuts, DisplayOnly};
46
use uefi::proto::shell::Shell;
57
use uefi::{Error, Status, boot, cstr16};
8+
use uefi_raw::protocol::shell::ShellProtocol;
69

710
/// Test `current_dir()` and `set_current_dir()`
811
pub fn test_current_dir(shell: &ScopedProtocol<Shell>) {

uefi/src/proto/device_path/build.rs

Lines changed: 69 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@
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};
1518
use 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)]
7682
pub struct DevicePathBuilder<'a> {
77-
storage: BuilderStorage<'a>,
83+
storage: BuilderStorageRef<'a>,
7884
}
7985

8086
impl<'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

195201
impl 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

Comments
 (0)