multiboot2/
boot_loader_name.rs1use crate::tag::TagHeader;
4use crate::{StringError, TagType, parse_slice_as_string};
5use core::fmt::{Debug, Formatter};
6use core::mem;
7use multiboot2_common::{MaybeDynSized, Tag};
8#[cfg(feature = "builder")]
9use {alloc::boxed::Box, multiboot2_common::new_boxed};
10
11#[derive(ptr_meta::Pointee, PartialEq, Eq, PartialOrd, Ord, Hash)]
13#[repr(C, align(8))]
14pub struct BootLoaderNameTag {
15 header: TagHeader,
16 name: [u8],
18}
19
20impl BootLoaderNameTag {
21 #[cfg(feature = "builder")]
23 #[must_use]
24 pub fn new(name: &str) -> Box<Self> {
25 let header = TagHeader::new(Self::ID, 0);
26 let bytes = name.as_bytes();
27 if bytes.ends_with(&[0]) {
28 new_boxed(header, &[bytes])
29 } else {
30 new_boxed(header, &[bytes, &[0]])
31 }
32 }
33
34 #[must_use]
36 pub fn typ(&self) -> TagType {
37 self.header.typ.into()
38 }
39
40 #[must_use]
42 pub const fn size(&self) -> usize {
43 self.header.size as usize
44 }
45
46 pub fn name(&self) -> Result<&str, StringError> {
64 parse_slice_as_string(&self.name)
65 }
66}
67
68impl Debug for BootLoaderNameTag {
69 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
70 f.debug_struct("BootLoaderNameTag")
71 .field("typ", &self.header.typ)
72 .field("size", &self.header.size)
73 .field("name", &self.name())
74 .finish()
75 }
76}
77
78impl MaybeDynSized for BootLoaderNameTag {
79 type Header = TagHeader;
80
81 const BASE_SIZE: usize = mem::size_of::<TagHeader>();
82
83 fn dst_len(header: &TagHeader) -> usize {
84 assert!(header.size as usize >= Self::BASE_SIZE);
85 header.size as usize - Self::BASE_SIZE
86 }
87}
88
89impl Tag for BootLoaderNameTag {
90 type IDType = TagType;
91
92 const ID: TagType = TagType::BootLoaderName;
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98 use crate::GenericInfoTag;
99 use core::borrow::Borrow;
100 use multiboot2_common::test_utils::AlignedBytes;
101
102 #[rustfmt::skip]
103 fn get_bytes() -> AlignedBytes<16> {
104 AlignedBytes::new([
105 TagType::BootLoaderName.val() as u8, 0, 0, 0,
106 14, 0, 0, 0,
107 b'h', b'e', b'l', b'l', b'o', b'\0',
108 0, 0
110 ])
111 }
112
113 #[test]
115 fn test_parse_str() {
116 let bytes = get_bytes();
117 let tag = GenericInfoTag::ref_from_slice(bytes.borrow()).unwrap();
118 let tag = tag.cast::<BootLoaderNameTag>();
119 assert_eq!(tag.header.typ, TagType::BootLoaderName);
120 assert_eq!(tag.name(), Ok("hello"));
121 }
122
123 #[test]
125 #[cfg(feature = "builder")]
126 fn test_build_str() {
127 let tag = BootLoaderNameTag::new("hello");
128 let bytes = tag.as_bytes().as_ref();
129 let bytes = &bytes[..tag.header.size as usize];
130 assert_eq!(bytes, &get_bytes()[..tag.header.size as usize]);
131 assert_eq!(tag.name(), Ok("hello"));
132
133 let tag = BootLoaderNameTag::new("hello\0");
135 let bytes = tag.as_bytes().as_ref();
136 let bytes = &bytes[..tag.header.size as usize];
137 assert_eq!(bytes, &get_bytes()[..tag.header.size as usize]);
138 assert_eq!(tag.name(), Ok("hello"));
139
140 let tag = BootLoaderNameTag::new("AbCdEfGhUjK YEAH");
142 assert_eq!(tag.name(), Ok("AbCdEfGhUjK YEAH"));
143 let tag = BootLoaderNameTag::new("AbCdEfGhUjK YEAH".repeat(42).as_str());
144 assert_eq!(tag.name(), Ok("AbCdEfGhUjK YEAH".repeat(42).as_str()));
145 }
146}