multiboot2_header/
information_request.rs1use crate::{HeaderTagFlag, HeaderTagHeader, HeaderTagType};
2use crate::{MbiTagType, MbiTagTypeRaw};
3use core::fmt;
4use core::fmt::{Debug, Formatter};
5#[cfg(feature = "builder")]
6use multiboot2_common::new_boxed;
7use multiboot2_common::{MaybeDynSized, Tag};
8#[cfg(feature = "builder")]
9use {alloc::boxed::Box, alloc::vec::Vec};
10
11#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, ptr_meta::Pointee)]
14#[repr(C, align(8))]
15pub struct InformationRequestHeaderTag {
16 header: HeaderTagHeader,
17 requests: [MbiTagTypeRaw],
18}
19
20impl InformationRequestHeaderTag {
21 #[cfg(feature = "builder")]
23 #[must_use]
24 pub fn new(flags: HeaderTagFlag, requests: &[MbiTagType]) -> Box<Self> {
25 let header = HeaderTagHeader::new(HeaderTagType::InformationRequest, flags, 0);
26 let requests = requests
27 .iter()
28 .flat_map(|request| request.val().to_ne_bytes())
29 .collect::<Vec<_>>();
30 new_boxed(header, &[requests.as_slice()])
31 }
32
33 #[must_use]
35 pub const fn typ(&self) -> HeaderTagType {
36 self.header.typ()
37 }
38
39 #[must_use]
41 pub const fn flags(&self) -> HeaderTagFlag {
42 self.header.flags()
43 }
44
45 #[must_use]
47 pub const fn size(&self) -> u32 {
48 self.header.size()
49 }
50
51 pub fn requests(&self) -> impl Iterator<Item = MbiTagType> + '_ {
53 self.requests.iter().map(|&raw| MbiTagType::from(raw))
54 }
55}
56
57struct RequestsDebug<'a>(&'a InformationRequestHeaderTag);
60
61impl Debug for RequestsDebug<'_> {
62 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
63 f.debug_list().entries(self.0.requests()).finish()
64 }
65}
66
67impl Debug for InformationRequestHeaderTag {
68 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
69 f.debug_struct("InformationRequestHeaderTag")
70 .field("type", &self.typ())
71 .field("flags", &self.flags())
72 .field("size", &self.size())
73 .field("requests", &RequestsDebug(self))
74 .finish()
75 }
76}
77
78unsafe impl MaybeDynSized for InformationRequestHeaderTag {
81 type Header = HeaderTagHeader;
82
83 const BASE_SIZE: usize = size_of::<HeaderTagHeader>();
84
85 fn dst_len(header: &Self::Header) -> Self::Metadata {
86 assert!(header.size() as usize >= Self::BASE_SIZE);
87 let dst_size = header.size() as usize - Self::BASE_SIZE;
88 assert_eq!(dst_size % size_of::<MbiTagTypeRaw>(), 0);
89 dst_size / size_of::<MbiTagTypeRaw>()
90 }
91}
92
93impl Tag for InformationRequestHeaderTag {
94 type IDType = HeaderTagType;
95 const ID: HeaderTagType = HeaderTagType::InformationRequest;
96}
97
98#[cfg(test)]
99#[cfg(feature = "builder")]
100mod tests {
101 use super::*;
102
103 #[test]
104 #[should_panic]
105 fn dst_len_rejects_undersized_header() {
106 let header = HeaderTagHeader::new(
107 HeaderTagType::InformationRequest,
108 HeaderTagFlag::Optional,
109 4,
110 );
111 let _ = <InformationRequestHeaderTag as MaybeDynSized>::dst_len(&header);
112 }
113
114 #[test]
115 fn creation() {
116 let requests = [
117 MbiTagType::Cmdline,
118 MbiTagType::BootLoaderName,
119 MbiTagType::Module,
120 MbiTagType::BasicMeminfo,
121 MbiTagType::Bootdev,
122 MbiTagType::Mmap,
123 MbiTagType::Vbe,
124 MbiTagType::Framebuffer,
125 MbiTagType::ElfSections,
126 MbiTagType::Apm,
127 MbiTagType::Efi32,
128 MbiTagType::Efi64,
129 MbiTagType::Smbios,
130 MbiTagType::AcpiV1,
131 MbiTagType::AcpiV2,
132 MbiTagType::Network,
133 MbiTagType::EfiMmap,
134 MbiTagType::EfiBs,
135 MbiTagType::Efi32Ih,
136 MbiTagType::Efi64Ih,
137 MbiTagType::LoadBaseAddr,
138 MbiTagType::Custom(0x1337),
139 ];
140 let ir = InformationRequestHeaderTag::new(HeaderTagFlag::Optional, &requests);
142 assert!(ir.requests().eq(requests.iter().copied()));
143 }
144}