use crate::{read_le_bytes, GPTError, Result, GUID};
mod attrs;
pub use attrs::Attributes;
pub struct GPTPartHeader<T = DefaultGPTTypeGuid, A = Attributes>
where
T: GPTTypeGuid,
{
pub type_guid: T,
pub guid: GUID,
pub start_lba: u64,
pub end_lba: u64,
pub attrs: A,
pub name: [u16; 36],
#[cfg(any(feature = "alloc", doc))]
pub name_str: alloc::string::String,
}
impl<T, A> GPTPartHeader<T, A>
where
T: GPTTypeGuid,
GPTError: From<<T as TryFrom<[u8; 16]>>::Error>,
A: TryFrom<u64>,
GPTError: From<<A as TryFrom<u64>>::Error>,
{
pub fn parse(buf: &[u8]) -> Result<Self> {
let type_guid: [u8; 16] = read_le_bytes!(buf, 0..16);
let type_guid: T = type_guid.try_into()?;
let guid = read_le_bytes!(buf, 16..32);
let start_lba = read_le_bytes!(buf, u64, 32..40);
let end_lba = read_le_bytes!(buf, u64, 40..48);
let attrs = read_le_bytes!(buf, u64, 48..56);
let attrs = attrs.try_into()?;
let name_in: [u8; 72] = read_le_bytes!(buf, 56..128);
let mut name = [0; 36];
for x in 0..36 {
name[x] = u16::from_le_bytes([name_in[x * 2], name_in[x * 2 + 1]]);
}
#[cfg(feature = "alloc")]
let name_str = {
let len = (0..36).take_while(|&i| name[i] != 0).count();
alloc::string::String::from_utf16_lossy(&name[..len])
};
Ok(Self {
type_guid,
guid,
start_lba,
end_lba,
attrs,
name,
#[cfg(feature = "alloc")]
name_str,
})
}
}
impl<T, A> core::fmt::Debug for GPTPartHeader<T, A>
where
T: GPTTypeGuid + core::fmt::Debug,
A: core::fmt::Debug,
{
#[cfg(feature = "alloc")]
fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
fmt.debug_struct("GptPartHeader")
.field("type_guid", &self.type_guid)
.field("guid", &self.guid)
.field("start_lba", &self.start_lba)
.field("end_lba", &self.end_lba)
.field("attrs", &self.attrs)
.field("name", &self.name_str)
.finish()
}
#[cfg(not(feature = "alloc"))]
fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let len = (0..36).take_while(|&i| self.name[i] != 0).count();
fmt.debug_struct("GptPartHeader")
.field("type_guid", &self.type_guid)
.field("guid", &self.guid)
.field("start_lba", &self.start_lba)
.field("end_lba", &self.end_lba)
.field("attrs", &self.attrs)
.field("name", &&self.name[..len])
.finish()
}
}
pub trait GPTTypeGuid: TryFrom<[u8; 16]> + TryInto<[u8; 16]> {
}
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub enum DefaultGPTTypeGuid {
Unused,
ESP,
LegacyMBR,
Unknown(GUID),
}
impl From<[u8; 16]> for DefaultGPTTypeGuid {
fn from(value: [u8; 16]) -> Self {
let value = GUID::from(value);
value.into()
}
}
impl From<DefaultGPTTypeGuid> for [u8; 16] {
fn from(t: DefaultGPTTypeGuid) -> Self {
let guid: GUID = t.into();
guid.into()
}
}
impl From<DefaultGPTTypeGuid> for GUID {
fn from(t: DefaultGPTTypeGuid) -> Self {
match t {
DefaultGPTTypeGuid::Unused => GUID::UNUSED,
DefaultGPTTypeGuid::ESP => GUID::ESP,
DefaultGPTTypeGuid::LegacyMBR => GUID::LEGACY_MBR,
DefaultGPTTypeGuid::Unknown(v) => v,
}
}
}
impl From<GUID> for DefaultGPTTypeGuid {
fn from(value: GUID) -> Self {
match value {
GUID::UNUSED => DefaultGPTTypeGuid::Unused,
GUID::ESP => DefaultGPTTypeGuid::ESP,
GUID::LEGACY_MBR => DefaultGPTTypeGuid::LegacyMBR,
v => DefaultGPTTypeGuid::Unknown(v),
}
}
}
impl GPTTypeGuid for DefaultGPTTypeGuid {}
impl GPTTypeGuid for GUID {}
#[cfg(test)]
mod test {
use super::{DefaultGPTTypeGuid, GUID};
#[test]
fn eq_guid_default_partition_type() {
let lhs = DefaultGPTTypeGuid::ESP;
let rhs: DefaultGPTTypeGuid = GUID::ESP.into();
assert_eq!(lhs, rhs);
}
#[test]
fn guid_default_partition_type_into_guid() {
let lhs: GUID = DefaultGPTTypeGuid::Unused.into();
assert_eq!(lhs, GUID::UNUSED);
let lhs: GUID = DefaultGPTTypeGuid::ESP.into();
assert_eq!(lhs, GUID::ESP);
let lhs: GUID = DefaultGPTTypeGuid::LegacyMBR.into();
assert_eq!(lhs, GUID::LEGACY_MBR);
let guid: GUID = "6FCC8240-3985-4840-901F-A05E7FD9B69D".parse().unwrap();
let lhs: GUID = DefaultGPTTypeGuid::Unknown(guid).into();
assert_eq!(lhs, guid);
}
#[test]
fn guid_default_partition_type_from_guid() {
let lhs: DefaultGPTTypeGuid = GUID::UNUSED.into();
assert_eq!(lhs, DefaultGPTTypeGuid::Unused);
let lhs: DefaultGPTTypeGuid = GUID::ESP.into();
assert_eq!(lhs, DefaultGPTTypeGuid::ESP);
let lhs: DefaultGPTTypeGuid = GUID::LEGACY_MBR.into();
assert_eq!(lhs, DefaultGPTTypeGuid::LegacyMBR);
let guid: GUID = "6FCC8240-3985-4840-901F-A05E7FD9B69D".parse().unwrap();
let lhs: DefaultGPTTypeGuid = guid.into();
assert_eq!(lhs, DefaultGPTTypeGuid::Unknown(guid));
}
}