|  | @@ -7,6 +7,7 @@ use crate::{
 | 
	
		
			
				|  |  |      MemoryMapTag, ModuleTag, RsdpV1Tag, RsdpV2Tag, SmbiosTag, TagTrait, TagType,
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  use alloc::vec::Vec;
 | 
	
		
			
				|  |  | +use core::fmt::{Display, Formatter};
 | 
	
		
			
				|  |  |  use core::mem::size_of;
 | 
	
		
			
				|  |  |  use core::ops::Deref;
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -41,142 +42,71 @@ impl Deref for BootInformationBytes {
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +type SerializedTag = Vec<u8>;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/// Error that indicates a tag was added multiple times that is not allowed to
 | 
	
		
			
				|  |  | +/// be there multiple times.
 | 
	
		
			
				|  |  | +#[derive(Debug)]
 | 
	
		
			
				|  |  | +pub struct RedundantTagError(TagType);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +impl Display for RedundantTagError {
 | 
	
		
			
				|  |  | +    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
 | 
	
		
			
				|  |  | +        write!(f, "{:?}", self)
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#[cfg(feature = "unstable")]
 | 
	
		
			
				|  |  | +impl core::error::Error for RedundantTagError {}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  /// Builder to construct a valid Multiboot2 information dynamically at runtime.
 | 
	
		
			
				|  |  |  /// The tags will appear in the order of their corresponding enumeration,
 | 
	
		
			
				|  |  |  /// except for the END tag.
 | 
	
		
			
				|  |  |  #[derive(Debug, PartialEq, Eq)]
 | 
	
		
			
				|  |  | -pub struct InformationBuilder {
 | 
	
		
			
				|  |  | -    basic_memory_info_tag: Option<BasicMemoryInfoTag>,
 | 
	
		
			
				|  |  | -    boot_loader_name_tag: Option<BoxedDst<BootLoaderNameTag>>,
 | 
	
		
			
				|  |  | -    command_line_tag: Option<BoxedDst<CommandLineTag>>,
 | 
	
		
			
				|  |  | -    efi_boot_services_not_exited_tag: Option<EFIBootServicesNotExitedTag>,
 | 
	
		
			
				|  |  | -    efi_image_handle32: Option<EFIImageHandle32Tag>,
 | 
	
		
			
				|  |  | -    efi_image_handle64: Option<EFIImageHandle64Tag>,
 | 
	
		
			
				|  |  | -    efi_memory_map_tag: Option<BoxedDst<EFIMemoryMapTag>>,
 | 
	
		
			
				|  |  | -    elf_sections_tag: Option<BoxedDst<ElfSectionsTag>>,
 | 
	
		
			
				|  |  | -    framebuffer_tag: Option<BoxedDst<FramebufferTag>>,
 | 
	
		
			
				|  |  | -    image_load_addr: Option<ImageLoadPhysAddrTag>,
 | 
	
		
			
				|  |  | -    memory_map_tag: Option<BoxedDst<MemoryMapTag>>,
 | 
	
		
			
				|  |  | -    module_tags: Vec<BoxedDst<ModuleTag>>,
 | 
	
		
			
				|  |  | -    efisdt32_tag: Option<EFISdt32Tag>,
 | 
	
		
			
				|  |  | -    efisdt64_tag: Option<EFISdt64Tag>,
 | 
	
		
			
				|  |  | -    rsdp_v1_tag: Option<RsdpV1Tag>,
 | 
	
		
			
				|  |  | -    rsdp_v2_tag: Option<RsdpV2Tag>,
 | 
	
		
			
				|  |  | -    smbios_tags: Vec<BoxedDst<SmbiosTag>>,
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | +pub struct InformationBuilder(Vec<(TagType, SerializedTag)>);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  impl InformationBuilder {
 | 
	
		
			
				|  |  | +    /// Creates a new builder.
 | 
	
		
			
				|  |  |      pub const fn new() -> Self {
 | 
	
		
			
				|  |  | -        Self {
 | 
	
		
			
				|  |  | -            basic_memory_info_tag: None,
 | 
	
		
			
				|  |  | -            boot_loader_name_tag: None,
 | 
	
		
			
				|  |  | -            command_line_tag: None,
 | 
	
		
			
				|  |  | -            efisdt32_tag: None,
 | 
	
		
			
				|  |  | -            efisdt64_tag: None,
 | 
	
		
			
				|  |  | -            efi_boot_services_not_exited_tag: None,
 | 
	
		
			
				|  |  | -            efi_image_handle32: None,
 | 
	
		
			
				|  |  | -            efi_image_handle64: None,
 | 
	
		
			
				|  |  | -            efi_memory_map_tag: None,
 | 
	
		
			
				|  |  | -            elf_sections_tag: None,
 | 
	
		
			
				|  |  | -            framebuffer_tag: None,
 | 
	
		
			
				|  |  | -            image_load_addr: None,
 | 
	
		
			
				|  |  | -            memory_map_tag: None,
 | 
	
		
			
				|  |  | -            module_tags: Vec::new(),
 | 
	
		
			
				|  |  | -            rsdp_v1_tag: None,
 | 
	
		
			
				|  |  | -            rsdp_v2_tag: None,
 | 
	
		
			
				|  |  | -            smbios_tags: Vec::new(),
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | +        Self(Vec::new())
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    /// Returns the size, if the value is a multiple of 8 or returns
 | 
	
		
			
				|  |  | -    /// the next number that is a multiple of 8. With this, one can
 | 
	
		
			
				|  |  | -    /// easily calculate the size of a Multiboot2 header, where
 | 
	
		
			
				|  |  | -    /// all the tags are 8-byte aligned.
 | 
	
		
			
				|  |  | +    /// Returns the provided number or the next multiple of 8. This is helpful
 | 
	
		
			
				|  |  | +    /// to ensure that the following tag starts at a 8-byte aligned boundary.
 | 
	
		
			
				|  |  |      const fn size_or_up_aligned(size: usize) -> usize {
 | 
	
		
			
				|  |  |          (size + 7) & !7
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /// Returns the expected length of the boot information, when the
 | 
	
		
			
				|  |  | -    /// [`Self::build`]-method gets called.
 | 
	
		
			
				|  |  | +    /// [`Self::build`]-method is called. This function assumes that the begin
 | 
	
		
			
				|  |  | +    /// of the boot information is 8-byte aligned and automatically adds padding
 | 
	
		
			
				|  |  | +    /// between tags to ensure that each tag is 8-byte aligned.
 | 
	
		
			
				|  |  |      pub fn expected_len(&self) -> usize {
 | 
	
		
			
				|  |  | -        let base_len = size_of::<BootInformationHeader>();
 | 
	
		
			
				|  |  | -        // size_or_up_aligned not required, because length is 16 and the
 | 
	
		
			
				|  |  | -        // begin is 8 byte aligned => first tag automatically 8 byte aligned
 | 
	
		
			
				|  |  | -        let mut len = Self::size_or_up_aligned(base_len);
 | 
	
		
			
				|  |  | -        if let Some(tag) = &self.basic_memory_info_tag {
 | 
	
		
			
				|  |  | -            // we use size_or_up_aligned, because each tag will start at an 8 byte aligned address
 | 
	
		
			
				|  |  | -            len += Self::size_or_up_aligned(tag.size())
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        if let Some(tag) = &self.boot_loader_name_tag {
 | 
	
		
			
				|  |  | -            len += Self::size_or_up_aligned(tag.size())
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        if let Some(tag) = &self.command_line_tag {
 | 
	
		
			
				|  |  | -            len += Self::size_or_up_aligned(tag.size())
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        if let Some(tag) = &self.efisdt32_tag {
 | 
	
		
			
				|  |  | -            len += Self::size_or_up_aligned(tag.size())
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        if let Some(tag) = &self.efisdt64_tag {
 | 
	
		
			
				|  |  | -            len += Self::size_or_up_aligned(tag.size())
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        if let Some(tag) = &self.efi_boot_services_not_exited_tag {
 | 
	
		
			
				|  |  | -            len += Self::size_or_up_aligned(tag.size())
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        if let Some(tag) = &self.efi_image_handle32 {
 | 
	
		
			
				|  |  | -            len += Self::size_or_up_aligned(tag.size())
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        if let Some(tag) = &self.efi_image_handle64 {
 | 
	
		
			
				|  |  | -            len += Self::size_or_up_aligned(tag.size())
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        if let Some(tag) = &self.efi_memory_map_tag {
 | 
	
		
			
				|  |  | -            len += Self::size_or_up_aligned(tag.size())
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        if let Some(tag) = &self.elf_sections_tag {
 | 
	
		
			
				|  |  | -            len += Self::size_or_up_aligned(tag.size())
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        if let Some(tag) = &self.framebuffer_tag {
 | 
	
		
			
				|  |  | -            len += Self::size_or_up_aligned(tag.size())
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        if let Some(tag) = &self.image_load_addr {
 | 
	
		
			
				|  |  | -            len += Self::size_or_up_aligned(tag.size())
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        if let Some(tag) = &self.memory_map_tag {
 | 
	
		
			
				|  |  | -            len += Self::size_or_up_aligned(tag.size())
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        for tag in &self.module_tags {
 | 
	
		
			
				|  |  | -            len += Self::size_or_up_aligned(tag.size())
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        if let Some(tag) = &self.rsdp_v1_tag {
 | 
	
		
			
				|  |  | -            len += Self::size_or_up_aligned(tag.size())
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        if let Some(tag) = &self.rsdp_v2_tag {
 | 
	
		
			
				|  |  | -            len += Self::size_or_up_aligned(tag.size())
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        for tag in &self.smbios_tags {
 | 
	
		
			
				|  |  | -            len += Self::size_or_up_aligned(tag.size())
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        // only here size_or_up_aligned is not important, because it is the last tag
 | 
	
		
			
				|  |  | -        len += size_of::<EndTag>();
 | 
	
		
			
				|  |  | -        len
 | 
	
		
			
				|  |  | +        let tag_size_iter = self.0.iter().map(|(_, bytes)| bytes.len());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        let payload_tags_size = tag_size_iter.fold(0, |acc, tag_size| {
 | 
	
		
			
				|  |  | +            // size_or_up_aligned: make sure next tag is 8-byte aligned
 | 
	
		
			
				|  |  | +            acc + Self::size_or_up_aligned(tag_size)
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        size_of::<BootInformationHeader>() + payload_tags_size + size_of::<EndTag>()
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /// Adds the bytes of a tag to the final Multiboot2 information byte vector.
 | 
	
		
			
				|  |  | -    fn build_add_tag<T: TagTrait + ?Sized>(dest: &mut Vec<u8>, source: &T) {
 | 
	
		
			
				|  |  | -        let vec_next_write_ptr = unsafe { dest.as_ptr().add(dest.len()) };
 | 
	
		
			
				|  |  | +    fn build_add_tag(dest_buf: &mut Vec<u8>, tag_serialized: &[u8], tag_type: TagType) {
 | 
	
		
			
				|  |  | +        let vec_next_write_ptr = unsafe { dest_buf.as_ptr().add(dest_buf.len()) };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |          // At this point, the alignment is guaranteed. If not, something is
 | 
	
		
			
				|  |  |          // broken fundamentally.
 | 
	
		
			
				|  |  |          assert_eq!(vec_next_write_ptr.align_offset(8), 0);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        dest.extend(source.as_bytes());
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        let is_end_tag = source.as_base_tag().typ == TagType::End;
 | 
	
		
			
				|  |  | +        dest_buf.extend(tag_serialized);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        if !is_end_tag {
 | 
	
		
			
				|  |  | -            let size = source.size();
 | 
	
		
			
				|  |  | +        if tag_type != TagType::End {
 | 
	
		
			
				|  |  | +            let size = tag_serialized.len();
 | 
	
		
			
				|  |  |              let size_to_8_align = Self::size_or_up_aligned(size);
 | 
	
		
			
				|  |  |              let size_to_8_align_diff = size_to_8_align - size;
 | 
	
		
			
				|  |  |              // fill zeroes so that next data block is 8-byte aligned
 | 
	
		
			
				|  |  | -            dest.extend([0].repeat(size_to_8_align_diff));
 | 
	
		
			
				|  |  | +            dest_buf.extend([0].repeat(size_to_8_align_diff));
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -207,7 +137,11 @@ impl InformationBuilder {
 | 
	
		
			
				|  |  |          // -----------------------------------------------
 | 
	
		
			
				|  |  |          // PHASE 2/2: Add Tags
 | 
	
		
			
				|  |  |          bytes.extend(BootInformationHeader::new(self.expected_len() as u32).as_bytes());
 | 
	
		
			
				|  |  | -        self.build_add_tags(&mut bytes);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        for (tag_type, tag_serialized) in self.0 {
 | 
	
		
			
				|  |  | +            Self::build_add_tag(&mut bytes, tag_serialized.as_slice(), tag_type)
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        Self::build_add_tag(&mut bytes, EndTag::default().as_bytes(), TagType::End);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          assert_eq!(
 | 
	
		
			
				|  |  |              alloc_ptr,
 | 
	
	
		
			
				|  | @@ -227,166 +161,127 @@ impl InformationBuilder {
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    /// Helper method that adds all the tags to the given vector.
 | 
	
		
			
				|  |  | -    fn build_add_tags(&self, bytes: &mut Vec<u8>) {
 | 
	
		
			
				|  |  | -        if let Some(tag) = self.basic_memory_info_tag.as_ref() {
 | 
	
		
			
				|  |  | -            Self::build_add_tag(bytes, tag)
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        if let Some(tag) = self.boot_loader_name_tag.as_ref() {
 | 
	
		
			
				|  |  | -            Self::build_add_tag(bytes, &**tag)
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        if let Some(tag) = self.command_line_tag.as_ref() {
 | 
	
		
			
				|  |  | -            Self::build_add_tag(bytes, &**tag)
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        if let Some(tag) = self.efisdt32_tag.as_ref() {
 | 
	
		
			
				|  |  | -            Self::build_add_tag(bytes, tag)
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        if let Some(tag) = self.efisdt64_tag.as_ref() {
 | 
	
		
			
				|  |  | -            Self::build_add_tag(bytes, tag)
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        if let Some(tag) = self.efi_boot_services_not_exited_tag.as_ref() {
 | 
	
		
			
				|  |  | -            Self::build_add_tag(bytes, tag)
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        if let Some(tag) = self.efi_image_handle32.as_ref() {
 | 
	
		
			
				|  |  | -            Self::build_add_tag(bytes, tag)
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        if let Some(tag) = self.efi_image_handle64.as_ref() {
 | 
	
		
			
				|  |  | -            Self::build_add_tag(bytes, tag)
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        if let Some(tag) = self.efi_memory_map_tag.as_ref() {
 | 
	
		
			
				|  |  | -            Self::build_add_tag(bytes, &**tag)
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        if let Some(tag) = self.elf_sections_tag.as_ref() {
 | 
	
		
			
				|  |  | -            Self::build_add_tag(bytes, &**tag)
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        if let Some(tag) = self.framebuffer_tag.as_ref() {
 | 
	
		
			
				|  |  | -            Self::build_add_tag(bytes, &**tag)
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        if let Some(tag) = self.image_load_addr.as_ref() {
 | 
	
		
			
				|  |  | -            Self::build_add_tag(bytes, tag)
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        if let Some(tag) = self.memory_map_tag.as_ref() {
 | 
	
		
			
				|  |  | -            Self::build_add_tag(bytes, &**tag)
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        for tag in &self.module_tags {
 | 
	
		
			
				|  |  | -            Self::build_add_tag(bytes, &**tag)
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        if let Some(tag) = self.rsdp_v1_tag.as_ref() {
 | 
	
		
			
				|  |  | -            Self::build_add_tag(bytes, tag)
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        if let Some(tag) = self.rsdp_v2_tag.as_ref() {
 | 
	
		
			
				|  |  | -            Self::build_add_tag(bytes, tag)
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        for tag in &self.smbios_tags {
 | 
	
		
			
				|  |  | -            Self::build_add_tag(bytes, &**tag)
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        Self::build_add_tag(bytes, &EndTag::default());
 | 
	
		
			
				|  |  | +    /// Adds a arbitrary tag that implements [`TagTrait`] to the builder. Only
 | 
	
		
			
				|  |  | +    /// [`TagType::Module`] and [`TagType::Custom`] are allowed to occur
 | 
	
		
			
				|  |  | +    /// multiple times. For other tags, this function returns an error.
 | 
	
		
			
				|  |  | +    ///
 | 
	
		
			
				|  |  | +    /// It is not required to manually add the [`TagType::End`] tag.
 | 
	
		
			
				|  |  | +    ///
 | 
	
		
			
				|  |  | +    /// The tags of the boot information will be ordered naturally, i.e., by
 | 
	
		
			
				|  |  | +    /// their numeric ID.
 | 
	
		
			
				|  |  | +    pub fn add_tag<T: TagTrait + ?Sized>(mut self, tag: &T) -> Result<Self, RedundantTagError> {
 | 
	
		
			
				|  |  | +        // not required to do this manually
 | 
	
		
			
				|  |  | +        if T::ID == TagType::End {
 | 
	
		
			
				|  |  | +            return Ok(self);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        let is_redundant_tag = self
 | 
	
		
			
				|  |  | +            .0
 | 
	
		
			
				|  |  | +            .iter()
 | 
	
		
			
				|  |  | +            .map(|(typ, _)| *typ)
 | 
	
		
			
				|  |  | +            .any(|typ| typ == T::ID && !Self::tag_is_allowed_multiple_times(typ));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        if is_redundant_tag {
 | 
	
		
			
				|  |  | +            log::debug!(
 | 
	
		
			
				|  |  | +                "Can't add tag of type {:?}. Only Module tags and Custom tags are allowed to appear multiple times.",
 | 
	
		
			
				|  |  | +                T::ID
 | 
	
		
			
				|  |  | +            );
 | 
	
		
			
				|  |  | +            return Err(RedundantTagError(T::ID));
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        self.0.push((T::ID, tag.as_bytes().to_vec()));
 | 
	
		
			
				|  |  | +        self.0.sort_by_key(|(typ, _)| *typ);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        Ok(self)
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /// Adds a 'basic memory information' tag (represented by [`BasicMemoryInfoTag`]) to the builder.
 | 
	
		
			
				|  |  | -    pub fn basic_memory_info_tag(mut self, basic_memory_info_tag: BasicMemoryInfoTag) -> Self {
 | 
	
		
			
				|  |  | -        self.basic_memory_info_tag = Some(basic_memory_info_tag);
 | 
	
		
			
				|  |  | -        self
 | 
	
		
			
				|  |  | +    pub fn basic_memory_info_tag(self, tag: BasicMemoryInfoTag) -> Self {
 | 
	
		
			
				|  |  | +        self.add_tag(&tag).unwrap()
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /// Adds a 'bootloader name' tag (represented by [`BootLoaderNameTag`]) to the builder.
 | 
	
		
			
				|  |  | -    pub fn bootloader_name_tag(
 | 
	
		
			
				|  |  | -        mut self,
 | 
	
		
			
				|  |  | -        boot_loader_name_tag: BoxedDst<BootLoaderNameTag>,
 | 
	
		
			
				|  |  | -    ) -> Self {
 | 
	
		
			
				|  |  | -        self.boot_loader_name_tag = Some(boot_loader_name_tag);
 | 
	
		
			
				|  |  | -        self
 | 
	
		
			
				|  |  | +    pub fn bootloader_name_tag(self, tag: BoxedDst<BootLoaderNameTag>) -> Self {
 | 
	
		
			
				|  |  | +        self.add_tag(&*tag).unwrap()
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /// Adds a 'command line' tag (represented by [`CommandLineTag`]) to the builder.
 | 
	
		
			
				|  |  | -    pub fn command_line_tag(mut self, command_line_tag: BoxedDst<CommandLineTag>) -> Self {
 | 
	
		
			
				|  |  | -        self.command_line_tag = Some(command_line_tag);
 | 
	
		
			
				|  |  | -        self
 | 
	
		
			
				|  |  | +    pub fn command_line_tag(self, tag: BoxedDst<CommandLineTag>) -> Self {
 | 
	
		
			
				|  |  | +        self.add_tag(&*tag).unwrap()
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /// Adds a 'EFI 32-bit system table pointer' tag (represented by [`EFISdt32Tag`]) to the builder.
 | 
	
		
			
				|  |  | -    pub fn efisdt32_tag(mut self, efisdt32: EFISdt32Tag) -> Self {
 | 
	
		
			
				|  |  | -        self.efisdt32_tag = Some(efisdt32);
 | 
	
		
			
				|  |  | -        self
 | 
	
		
			
				|  |  | +    pub fn efisdt32_tag(self, tag: EFISdt32Tag) -> Self {
 | 
	
		
			
				|  |  | +        self.add_tag(&tag).unwrap()
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /// Adds a 'EFI 64-bit system table pointer' tag (represented by [`EFISdt64Tag`]) to the builder.
 | 
	
		
			
				|  |  | -    pub fn efisdt64_tag(mut self, efisdt64: EFISdt64Tag) -> Self {
 | 
	
		
			
				|  |  | -        self.efisdt64_tag = Some(efisdt64);
 | 
	
		
			
				|  |  | -        self
 | 
	
		
			
				|  |  | +    pub fn efisdt64_tag(self, tag: EFISdt64Tag) -> Self {
 | 
	
		
			
				|  |  | +        self.add_tag(&tag).unwrap()
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /// Adds a 'EFI boot services not terminated' tag (represented by [`EFIBootServicesNotExitedTag`]) to the builder.
 | 
	
		
			
				|  |  | -    pub fn efi_boot_services_not_exited_tag(mut self) -> Self {
 | 
	
		
			
				|  |  | -        self.efi_boot_services_not_exited_tag = Some(EFIBootServicesNotExitedTag::new());
 | 
	
		
			
				|  |  | -        self
 | 
	
		
			
				|  |  | +    pub fn efi_boot_services_not_exited_tag(self) -> Self {
 | 
	
		
			
				|  |  | +        self.add_tag(&EFIBootServicesNotExitedTag::new()).unwrap()
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /// Adds a 'EFI 32-bit image handle pointer' tag (represented by [`EFIImageHandle32Tag`]) to the builder.
 | 
	
		
			
				|  |  | -    pub fn efi_image_handle32(mut self, efi_image_handle32: EFIImageHandle32Tag) -> Self {
 | 
	
		
			
				|  |  | -        self.efi_image_handle32 = Some(efi_image_handle32);
 | 
	
		
			
				|  |  | -        self
 | 
	
		
			
				|  |  | +    pub fn efi_image_handle32(self, tag: EFIImageHandle32Tag) -> Self {
 | 
	
		
			
				|  |  | +        self.add_tag(&tag).unwrap()
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /// Adds a 'EFI 64-bit image handle pointer' tag (represented by [`EFIImageHandle64Tag`]) to the builder.
 | 
	
		
			
				|  |  | -    pub fn efi_image_handle64(mut self, efi_image_handle64: EFIImageHandle64Tag) -> Self {
 | 
	
		
			
				|  |  | -        self.efi_image_handle64 = Some(efi_image_handle64);
 | 
	
		
			
				|  |  | -        self
 | 
	
		
			
				|  |  | +    pub fn efi_image_handle64(self, tag: EFIImageHandle64Tag) -> Self {
 | 
	
		
			
				|  |  | +        self.add_tag(&tag).unwrap()
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /// Adds a 'EFI Memory map' tag (represented by [`EFIMemoryMapTag`]) to the builder.
 | 
	
		
			
				|  |  | -    pub fn efi_memory_map_tag(mut self, efi_memory_map_tag: BoxedDst<EFIMemoryMapTag>) -> Self {
 | 
	
		
			
				|  |  | -        self.efi_memory_map_tag = Some(efi_memory_map_tag);
 | 
	
		
			
				|  |  | -        self
 | 
	
		
			
				|  |  | +    pub fn efi_memory_map_tag(self, tag: BoxedDst<EFIMemoryMapTag>) -> Self {
 | 
	
		
			
				|  |  | +        self.add_tag(&*tag).unwrap()
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /// Adds a 'ELF-Symbols' tag (represented by [`ElfSectionsTag`]) to the builder.
 | 
	
		
			
				|  |  | -    pub fn elf_sections_tag(mut self, elf_sections_tag: BoxedDst<ElfSectionsTag>) -> Self {
 | 
	
		
			
				|  |  | -        self.elf_sections_tag = Some(elf_sections_tag);
 | 
	
		
			
				|  |  | -        self
 | 
	
		
			
				|  |  | +    pub fn elf_sections_tag(self, tag: BoxedDst<ElfSectionsTag>) -> Self {
 | 
	
		
			
				|  |  | +        self.add_tag(&*tag).unwrap()
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /// Adds a 'Framebuffer info' tag (represented by [`FramebufferTag`]) to the builder.
 | 
	
		
			
				|  |  | -    pub fn framebuffer_tag(mut self, framebuffer_tag: BoxedDst<FramebufferTag>) -> Self {
 | 
	
		
			
				|  |  | -        self.framebuffer_tag = Some(framebuffer_tag);
 | 
	
		
			
				|  |  | -        self
 | 
	
		
			
				|  |  | +    pub fn framebuffer_tag(self, tag: BoxedDst<FramebufferTag>) -> Self {
 | 
	
		
			
				|  |  | +        self.add_tag(&*tag).unwrap()
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /// Adds a 'Image load base physical address' tag (represented by [`ImageLoadPhysAddrTag`]) to the builder.
 | 
	
		
			
				|  |  | -    pub fn image_load_addr(mut self, image_load_addr: ImageLoadPhysAddrTag) -> Self {
 | 
	
		
			
				|  |  | -        self.image_load_addr = Some(image_load_addr);
 | 
	
		
			
				|  |  | -        self
 | 
	
		
			
				|  |  | +    pub fn image_load_addr(self, tag: ImageLoadPhysAddrTag) -> Self {
 | 
	
		
			
				|  |  | +        self.add_tag(&tag).unwrap()
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /// Adds a (*none EFI*) 'memory map' tag (represented by [`MemoryMapTag`]) to the builder.
 | 
	
		
			
				|  |  | -    pub fn memory_map_tag(mut self, memory_map_tag: BoxedDst<MemoryMapTag>) -> Self {
 | 
	
		
			
				|  |  | -        self.memory_map_tag = Some(memory_map_tag);
 | 
	
		
			
				|  |  | -        self
 | 
	
		
			
				|  |  | +    pub fn memory_map_tag(self, tag: BoxedDst<MemoryMapTag>) -> Self {
 | 
	
		
			
				|  |  | +        self.add_tag(&*tag).unwrap()
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /// Adds a 'Modules' tag (represented by [`ModuleTag`]) to the builder.
 | 
	
		
			
				|  |  |      /// This tag can occur multiple times in boot information.
 | 
	
		
			
				|  |  | -    pub fn add_module_tag(mut self, module_tag: BoxedDst<ModuleTag>) -> Self {
 | 
	
		
			
				|  |  | -        self.module_tags.push(module_tag);
 | 
	
		
			
				|  |  | -        self
 | 
	
		
			
				|  |  | +    pub fn add_module_tag(self, tag: BoxedDst<ModuleTag>) -> Self {
 | 
	
		
			
				|  |  | +        self.add_tag(&*tag).unwrap()
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /// Adds a 'ACPI old RSDP' tag (represented by [`RsdpV1Tag`]) to the builder.
 | 
	
		
			
				|  |  | -    pub fn rsdp_v1_tag(mut self, rsdp_v1_tag: RsdpV1Tag) -> Self {
 | 
	
		
			
				|  |  | -        self.rsdp_v1_tag = Some(rsdp_v1_tag);
 | 
	
		
			
				|  |  | -        self
 | 
	
		
			
				|  |  | +    pub fn rsdp_v1_tag(self, tag: RsdpV1Tag) -> Self {
 | 
	
		
			
				|  |  | +        self.add_tag(&tag).unwrap()
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /// Adds a 'ACPI new RSDP' tag (represented by [`RsdpV2Tag`]) to the builder.
 | 
	
		
			
				|  |  | -    pub fn rsdp_v2_tag(mut self, rsdp_v2_tag: RsdpV2Tag) -> Self {
 | 
	
		
			
				|  |  | -        self.rsdp_v2_tag = Some(rsdp_v2_tag);
 | 
	
		
			
				|  |  | -        self
 | 
	
		
			
				|  |  | +    pub fn rsdp_v2_tag(self, tag: RsdpV2Tag) -> Self {
 | 
	
		
			
				|  |  | +        self.add_tag(&tag).unwrap()
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /// Adds a 'SMBIOS tables' tag (represented by [`SmbiosTag`]) to the builder.
 | 
	
		
			
				|  |  | -    pub fn add_smbios_tag(mut self, smbios_tag: BoxedDst<SmbiosTag>) -> Self {
 | 
	
		
			
				|  |  | -        self.smbios_tags.push(smbios_tag);
 | 
	
		
			
				|  |  | -        self
 | 
	
		
			
				|  |  | +    pub fn smbios_tag(self, tag: BoxedDst<SmbiosTag>) -> Self {
 | 
	
		
			
				|  |  | +        self.add_tag(&*tag).unwrap()
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    fn tag_is_allowed_multiple_times(tag_type: TagType) -> bool {
 | 
	
		
			
				|  |  | +        matches!(tag_type, TagType::Module | TagType::Custom(_))
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 |