Skip to content

Commit 2b64a42

Browse files
committed
multiboot2: builder: add Error type to new add_tag method
1 parent 3956403 commit 2b64a42

File tree

1 file changed

+55
-35
lines changed

1 file changed

+55
-35
lines changed

multiboot2/src/builder/information.rs

+55-35
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use crate::{
77
MemoryMapTag, ModuleTag, RsdpV1Tag, RsdpV2Tag, SmbiosTag, TagTrait, TagType,
88
};
99
use alloc::vec::Vec;
10+
use core::fmt::{Display, Formatter};
1011
use core::mem::size_of;
1112
use core::ops::Deref;
1213

@@ -41,13 +42,30 @@ impl Deref for BootInformationBytes {
4142
}
4243
}
4344

45+
type SerializedTag = Vec<u8>;
46+
47+
/// Error that indicates a tag was added multiple times that is not allowed to
48+
/// be there multiple times.
49+
#[derive(Debug)]
50+
pub struct RedundantTagError(TagType);
51+
52+
impl Display for RedundantTagError {
53+
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
54+
write!(f, "{:?}", self)
55+
}
56+
}
57+
58+
#[cfg(feature = "unstable")]
59+
impl core::error::Error for RedundantTagError {}
60+
4461
/// Builder to construct a valid Multiboot2 information dynamically at runtime.
4562
/// The tags will appear in the order of their corresponding enumeration,
4663
/// except for the END tag.
4764
#[derive(Debug, PartialEq, Eq)]
48-
pub struct InformationBuilder(Vec<(TagType, Vec<u8> /* Serialized tag */)>);
65+
pub struct InformationBuilder(Vec<(TagType, SerializedTag)>);
4966

5067
impl InformationBuilder {
68+
/// Creates a new builder.
5169
pub const fn new() -> Self {
5270
Self(Vec::new())
5371
}
@@ -144,124 +162,126 @@ impl InformationBuilder {
144162
}
145163

146164
/// Adds a arbitrary tag that implements [`TagTrait`] to the builder. Only
147-
/// [`TagType::Module`] and [`TagType::Custom`] are allowed to appear
165+
/// [`TagType::Module`] and [`TagType::Custom`] are allowed to occur
148166
/// multiple times. For other tags, this function returns an error.
149167
///
150-
/// The tags of the boot information will be ordered naturally by their
151-
/// numeric ID.
152-
///
153168
/// It is not required to manually add the [`TagType::End`] tag.
154-
pub fn add_tag<T: TagTrait + ?Sized>(mut self, tag: &T) -> Self {
169+
///
170+
/// The tags of the boot information will be ordered naturally, i.e., by
171+
/// their numeric ID.
172+
pub fn add_tag<T: TagTrait + ?Sized>(mut self, tag: &T) -> Result<Self, RedundantTagError> {
155173
// not required to do this manually
156174
if T::ID == TagType::End {
157-
return self;
175+
return Ok(self);
158176
}
159177

160-
if self
178+
let is_redundant_tag = self
161179
.0
162180
.iter()
163181
.map(|(typ, _)| *typ)
164-
.any(|typ| typ == T::ID && !Self::tag_is_allowed_multiple_times(typ))
165-
{
166-
// TODO return Result
167-
panic!("Can't add tag of type {:?}. Only Module tags and Custom tags are allowed to appear multiple times.", T::ID);
182+
.any(|typ| typ == T::ID && !Self::tag_is_allowed_multiple_times(typ));
183+
184+
if is_redundant_tag {
185+
log::debug!(
186+
"Can't add tag of type {:?}. Only Module tags and Custom tags are allowed to appear multiple times.",
187+
T::ID
188+
);
189+
return Err(RedundantTagError(T::ID));
168190
}
169191
self.0.push((T::ID, tag.as_bytes().to_vec()));
170192
self.0.sort_by_key(|(typ, _)| *typ);
171-
self
193+
194+
Ok(self)
172195
}
173196

174197
/// Adds a 'basic memory information' tag (represented by [`BasicMemoryInfoTag`]) to the builder.
175198
pub fn basic_memory_info_tag(self, tag: BasicMemoryInfoTag) -> Self {
176-
self.add_tag(&tag)
199+
self.add_tag(&tag).unwrap()
177200
}
178201

179202
/// Adds a 'bootloader name' tag (represented by [`BootLoaderNameTag`]) to the builder.
180203
pub fn bootloader_name_tag(self, tag: BoxedDst<BootLoaderNameTag>) -> Self {
181-
self.add_tag(&*tag)
204+
self.add_tag(&*tag).unwrap()
182205
}
183206

184207
/// Adds a 'command line' tag (represented by [`CommandLineTag`]) to the builder.
185208
pub fn command_line_tag(self, tag: BoxedDst<CommandLineTag>) -> Self {
186-
self.add_tag(&*tag)
209+
self.add_tag(&*tag).unwrap()
187210
}
188211

189212
/// Adds a 'EFI 32-bit system table pointer' tag (represented by [`EFISdt32Tag`]) to the builder.
190213
pub fn efisdt32_tag(self, tag: EFISdt32Tag) -> Self {
191-
self.add_tag(&tag)
214+
self.add_tag(&tag).unwrap()
192215
}
193216

194217
/// Adds a 'EFI 64-bit system table pointer' tag (represented by [`EFISdt64Tag`]) to the builder.
195218
pub fn efisdt64_tag(self, tag: EFISdt64Tag) -> Self {
196-
self.add_tag(&tag)
219+
self.add_tag(&tag).unwrap()
197220
}
198221

199222
/// Adds a 'EFI boot services not terminated' tag (represented by [`EFIBootServicesNotExitedTag`]) to the builder.
200223
pub fn efi_boot_services_not_exited_tag(self) -> Self {
201-
self.add_tag(&EFIBootServicesNotExitedTag::new())
224+
self.add_tag(&EFIBootServicesNotExitedTag::new()).unwrap()
202225
}
203226

204227
/// Adds a 'EFI 32-bit image handle pointer' tag (represented by [`EFIImageHandle32Tag`]) to the builder.
205228
pub fn efi_image_handle32(self, tag: EFIImageHandle32Tag) -> Self {
206-
self.add_tag(&tag)
229+
self.add_tag(&tag).unwrap()
207230
}
208231

209232
/// Adds a 'EFI 64-bit image handle pointer' tag (represented by [`EFIImageHandle64Tag`]) to the builder.
210233
pub fn efi_image_handle64(self, tag: EFIImageHandle64Tag) -> Self {
211-
self.add_tag(&tag)
234+
self.add_tag(&tag).unwrap()
212235
}
213236

214237
/// Adds a 'EFI Memory map' tag (represented by [`EFIMemoryMapTag`]) to the builder.
215238
pub fn efi_memory_map_tag(self, tag: BoxedDst<EFIMemoryMapTag>) -> Self {
216-
self.add_tag(&*tag)
239+
self.add_tag(&*tag).unwrap()
217240
}
218241

219242
/// Adds a 'ELF-Symbols' tag (represented by [`ElfSectionsTag`]) to the builder.
220243
pub fn elf_sections_tag(self, tag: BoxedDst<ElfSectionsTag>) -> Self {
221-
self.add_tag(&*tag)
244+
self.add_tag(&*tag).unwrap()
222245
}
223246

224247
/// Adds a 'Framebuffer info' tag (represented by [`FramebufferTag`]) to the builder.
225248
pub fn framebuffer_tag(self, tag: BoxedDst<FramebufferTag>) -> Self {
226-
self.add_tag(&*tag)
249+
self.add_tag(&*tag).unwrap()
227250
}
228251

229252
/// Adds a 'Image load base physical address' tag (represented by [`ImageLoadPhysAddrTag`]) to the builder.
230253
pub fn image_load_addr(self, tag: ImageLoadPhysAddrTag) -> Self {
231-
self.add_tag(&tag)
254+
self.add_tag(&tag).unwrap()
232255
}
233256

234257
/// Adds a (*none EFI*) 'memory map' tag (represented by [`MemoryMapTag`]) to the builder.
235258
pub fn memory_map_tag(self, tag: BoxedDst<MemoryMapTag>) -> Self {
236-
self.add_tag(&*tag)
259+
self.add_tag(&*tag).unwrap()
237260
}
238261

239262
/// Adds a 'Modules' tag (represented by [`ModuleTag`]) to the builder.
240263
/// This tag can occur multiple times in boot information.
241264
pub fn add_module_tag(self, tag: BoxedDst<ModuleTag>) -> Self {
242-
self.add_tag(&*tag)
265+
self.add_tag(&*tag).unwrap()
243266
}
244267

245268
/// Adds a 'ACPI old RSDP' tag (represented by [`RsdpV1Tag`]) to the builder.
246269
pub fn rsdp_v1_tag(self, tag: RsdpV1Tag) -> Self {
247-
self.add_tag(&tag)
270+
self.add_tag(&tag).unwrap()
248271
}
249272

250273
/// Adds a 'ACPI new RSDP' tag (represented by [`RsdpV2Tag`]) to the builder.
251274
pub fn rsdp_v2_tag(self, tag: RsdpV2Tag) -> Self {
252-
self.add_tag(&tag)
275+
self.add_tag(&tag).unwrap()
253276
}
254277

255278
/// Adds a 'SMBIOS tables' tag (represented by [`SmbiosTag`]) to the builder.
256-
pub fn add_smbios_tag(self, tag: BoxedDst<SmbiosTag>) -> Self {
257-
self.add_tag(&*tag)
279+
pub fn smbios_tag(self, tag: BoxedDst<SmbiosTag>) -> Self {
280+
self.add_tag(&*tag).unwrap()
258281
}
259282

260283
fn tag_is_allowed_multiple_times(tag_type: TagType) -> bool {
261-
matches!(
262-
tag_type,
263-
TagType::Module | TagType::Smbios | TagType::Custom(_)
264-
)
284+
matches!(tag_type, TagType::Module | TagType::Custom(_))
265285
}
266286
}
267287

0 commit comments

Comments
 (0)