use crate::{HeaderTagFlag, HeaderTagHeader, HeaderTagType};
use multiboot2_common::{MaybeDynSized, Tag};
multiboot2_common::raw_type! {
pub struct ConsoleHeaderTagFlagsRaw(u32);
pub enum ConsoleHeaderTagFlags {
ConsoleRequired = 1,
EgaTextSupported = 2,
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C, align(8))]
pub struct ConsoleHeaderTag {
header: HeaderTagHeader,
console_flags: ConsoleHeaderTagFlagsRaw,
}
impl ConsoleHeaderTag {
#[must_use]
pub const fn new(flags: HeaderTagFlag, console_flags: ConsoleHeaderTagFlags) -> Self {
let header =
HeaderTagHeader::new(HeaderTagType::ConsoleFlags, flags, Self::BASE_SIZE as u32);
Self {
header,
console_flags: ConsoleHeaderTagFlagsRaw::new(console_flags.val()),
}
}
#[must_use]
pub const fn typ(&self) -> HeaderTagType {
self.header.typ()
}
#[must_use]
pub const fn flags(&self) -> HeaderTagFlag {
self.header.flags()
}
#[must_use]
pub const fn size(&self) -> u32 {
self.header.size()
}
#[must_use]
pub const fn console_flags(&self) -> ConsoleHeaderTagFlags {
ConsoleHeaderTagFlags::from_val(self.console_flags.get())
}
}
unsafe impl MaybeDynSized for ConsoleHeaderTag {
type Header = HeaderTagHeader;
const BASE_SIZE: usize = size_of::<HeaderTagHeader>() + size_of::<u32>();
}
impl Tag for ConsoleHeaderTag {
type IDType = HeaderTagType;
const ID: HeaderTagType = HeaderTagType::ConsoleFlags;
}
#[cfg(test)]
mod tests {
use super::*;
use crate::GenericHeaderTag;
use core::borrow::Borrow;
use multiboot2_common::test_utils::AlignedBytes;
#[test]
fn console_flags_match_spec_values() {
assert_eq!(ConsoleHeaderTagFlags::ConsoleRequired.val(), 1);
assert_eq!(ConsoleHeaderTagFlags::EgaTextSupported.val(), 2);
}
#[test]
fn unknown_console_flags_are_not_ub() {
#[rustfmt::skip]
let bytes = AlignedBytes::new([
4, 0,
0, 0,
12, 0, 0, 0,
3, 0, 0, 0,
0, 0, 0, 0,
]);
let tag = GenericHeaderTag::ref_from_slice(bytes.borrow())
.unwrap()
.cast::<ConsoleHeaderTag>();
assert_eq!(tag.console_flags(), ConsoleHeaderTagFlags::Custom(3));
}
}