use crate::{Tag, TagTrait, TagTypeId};
use core::fmt::{Debug, Formatter};
use core::mem::size_of;
use core::str::Utf8Error;
#[cfg(feature = "builder")]
use {
crate::builder::traits::StructAsBytes, crate::builder::BoxedDst, crate::TagType,
alloc::vec::Vec,
};
const METADATA_SIZE: usize = size_of::<TagTypeId>() + size_of::<u32>();
#[derive(ptr_meta::Pointee, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
pub struct BootLoaderNameTag {
typ: TagTypeId,
size: u32,
name: [u8],
}
impl BootLoaderNameTag {
#[cfg(feature = "builder")]
pub fn new(name: &str) -> BoxedDst<Self> {
let mut bytes: Vec<_> = name.bytes().collect();
if !bytes.ends_with(&[0]) {
bytes.push(0);
}
BoxedDst::new(TagType::BootLoaderName, &bytes)
}
pub fn name(&self) -> Result<&str, Utf8Error> {
Tag::get_dst_str_slice(&self.name)
}
}
impl Debug for BootLoaderNameTag {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.debug_struct("BootLoaderNameTag")
.field("typ", &{ self.typ })
.field("size", &{ self.size })
.field("name", &self.name())
.finish()
}
}
impl TagTrait for BootLoaderNameTag {
fn dst_size(base_tag: &Tag) -> usize {
assert!(base_tag.size as usize >= METADATA_SIZE);
base_tag.size as usize - METADATA_SIZE
}
}
#[cfg(feature = "builder")]
impl StructAsBytes for BootLoaderNameTag {
fn byte_size(&self) -> usize {
self.size.try_into().unwrap()
}
}
#[cfg(test)]
mod tests {
use crate::{BootLoaderNameTag, Tag, TagType};
const MSG: &str = "hello";
fn get_bytes() -> std::vec::Vec<u8> {
let size = (4 + 4 + MSG.as_bytes().len() + 1) as u32;
[
&((TagType::BootLoaderName.val()).to_le_bytes()),
&size.to_le_bytes(),
MSG.as_bytes(),
&[0],
]
.iter()
.flat_map(|bytes| bytes.iter())
.copied()
.collect()
}
#[test]
#[cfg_attr(miri, ignore)]
fn test_parse_str() {
let tag = get_bytes();
let tag = unsafe { &*tag.as_ptr().cast::<Tag>() };
let tag = tag.cast_tag::<BootLoaderNameTag>();
assert_eq!({ tag.typ }, TagType::BootLoaderName);
assert_eq!(tag.name().expect("must be valid UTF-8"), MSG);
}
#[test]
#[cfg(feature = "builder")]
fn test_build_str() {
use crate::builder::traits::StructAsBytes;
let tag = BootLoaderNameTag::new(MSG);
let bytes = tag.struct_as_bytes();
assert_eq!(bytes, get_bytes());
assert_eq!(tag.name(), Ok(MSG));
let tag = BootLoaderNameTag::new("AbCdEfGhUjK YEAH");
assert_eq!(tag.name(), Ok("AbCdEfGhUjK YEAH"));
let tag = BootLoaderNameTag::new("AbCdEfGhUjK YEAH".repeat(42).as_str());
assert_eq!(tag.name(), Ok("AbCdEfGhUjK YEAH".repeat(42).as_str()));
}
}