use crate::error::EfiError;
use r_efi::efi;
const EXPECTED_HEX_CHARS: usize = 32;
const DASH_POSITIONS: [usize; 4] = [8, 12, 16, 20];
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum GuidError {
InvalidLength {
expected: usize,
actual: usize,
},
InvalidHexCharacter {
position: usize,
character: char,
},
}
impl core::fmt::Display for GuidError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
GuidError::InvalidLength { expected, actual } => {
write!(f, "Invalid GUID length: expected {expected} hex characters, found {actual}")
}
GuidError::InvalidHexCharacter { position, character } => {
write!(f, "Invalid hex character '{character}' at position {position}")
}
}
}
}
impl core::error::Error for GuidError {}
impl From<GuidError> for EfiError {
fn from(_: GuidError) -> Self {
EfiError::InvalidParameter
}
}
#[derive(Clone, PartialOrd)]
pub enum Guid<'a> {
Borrowed(&'a efi::Guid),
Owned(efi::Guid),
}
pub type OwnedGuid = Guid<'static>;
#[repr(transparent)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct BinaryGuid(pub efi::Guid);
impl BinaryGuid {
pub const fn from_fields(d1: u32, d2: u16, d3: u16, d4: u8, d5: u8, d6: &[u8; 6]) -> Self {
Self(efi::Guid::from_fields(d1, d2, d3, d4, d5, d6))
}
pub const fn from_bytes(bytes: &[u8; 16]) -> Self {
Self(efi::Guid::from_bytes(bytes))
}
pub const fn try_from_string(s: &str) -> core::result::Result<BinaryGuid, GuidError> {
match guid_from_str(s) {
Ok(g) => Ok(BinaryGuid(g)),
Err(e) => Err(e),
}
}
pub const fn from_string(s: &str) -> BinaryGuid {
match Self::try_from_string(s) {
Ok(guid) => guid,
Err(_) => panic!("Invalid GUID string"),
}
}
pub fn to_canonical_string(&self) -> [char; EXPECTED_HEX_CHARS] {
self.as_guid().to_canonical_string()
}
pub fn as_guid(&self) -> Guid<'_> {
Guid::Borrowed(&self.0)
}
pub fn to_owned_guid(&self) -> OwnedGuid {
Guid::Owned(self.0)
}
pub fn as_bytes(&self) -> &[u8; 16] {
self.0.as_bytes()
}
pub fn as_fields(&self) -> (u32, u16, u16, u8, u8, &[u8; 6]) {
self.0.as_fields()
}
pub const fn into_inner(&self) -> efi::Guid {
self.0
}
pub const fn as_efi_guid(&self) -> &efi::Guid {
&self.0
}
pub fn as_mut_efi_guid(&mut self) -> &mut efi::Guid {
&mut self.0
}
}
impl From<efi::Guid> for BinaryGuid {
fn from(guid: efi::Guid) -> Self {
Self(guid)
}
}
impl From<&efi::Guid> for BinaryGuid {
fn from(guid: &efi::Guid) -> Self {
Self(*guid)
}
}
impl From<BinaryGuid> for efi::Guid {
fn from(guid: BinaryGuid) -> Self {
guid.0
}
}
impl From<&BinaryGuid> for efi::Guid {
fn from(guid: &BinaryGuid) -> Self {
guid.0
}
}
impl<'a> From<&'a BinaryGuid> for Guid<'a> {
fn from(guid: &'a BinaryGuid) -> Self {
Guid::Borrowed(&guid.0)
}
}
impl From<BinaryGuid> for OwnedGuid {
fn from(guid: BinaryGuid) -> Self {
Guid::Owned(guid.0)
}
}
impl From<OwnedGuid> for BinaryGuid {
fn from(guid: OwnedGuid) -> Self {
Self(guid.to_efi_guid())
}
}
impl core::ops::Deref for BinaryGuid {
type Target = efi::Guid;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl core::ops::DerefMut for BinaryGuid {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl PartialEq<efi::Guid> for BinaryGuid {
fn eq(&self, other: &efi::Guid) -> bool {
self.0 == *other
}
}
impl PartialEq<BinaryGuid> for efi::Guid {
fn eq(&self, other: &BinaryGuid) -> bool {
*self == other.0
}
}
impl<'a> PartialEq<Guid<'a>> for BinaryGuid {
fn eq(&self, other: &Guid<'a>) -> bool {
self.0 == other.to_efi_guid()
}
}
impl<'a> PartialEq<BinaryGuid> for Guid<'a> {
fn eq(&self, other: &BinaryGuid) -> bool {
self.to_efi_guid() == other.0
}
}
impl core::fmt::Display for BinaryGuid {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.as_guid().fmt(f)
}
}
impl<'a> Guid<'a> {
pub fn from_ref(guid: &'a efi::Guid) -> Self {
Self::Borrowed(guid)
}
pub fn from_bytes(bytes: &[u8; 16]) -> OwnedGuid {
let efi_guid = efi::Guid::from_bytes(bytes);
OwnedGuid::Owned(efi_guid)
}
pub fn as_bytes(&self) -> [u8; 16] {
match self {
Self::Borrowed(guid) => *guid.as_bytes(),
Self::Owned(guid) => *guid.as_bytes(),
}
}
pub fn as_fields(&self) -> (u32, u16, u16, u8, u8, &[u8; 6]) {
match self {
Self::Borrowed(guid) => guid.as_fields(),
Self::Owned(guid) => guid.as_fields(),
}
}
pub fn to_efi_guid(&self) -> efi::Guid {
match self {
Self::Borrowed(guid) => **guid,
Self::Owned(guid) => *guid,
}
}
fn to_canonical_string(&self) -> [char; EXPECTED_HEX_CHARS] {
let (time_low, time_mid, time_hi_and_version, clk_seq_hi_res, clk_seq_low, node) = match self {
Self::Borrowed(guid) => guid.as_fields(),
Self::Owned(guid) => guid.as_fields(),
};
let mut result = [' '; EXPECTED_HEX_CHARS];
let mut pos = 0;
let mut add_hex = |value: u32, digits: usize| {
for i in (0..digits).rev() {
let nibble = ((value >> (i * 4)) & 0xF) as u8;
result[pos] = match nibble {
0..=9 => (b'0' + nibble) as char,
10..=15 => (b'A' + nibble - 10) as char,
_ => unreachable!(),
};
pos += 1;
}
};
add_hex(time_low, 8);
add_hex(time_mid as u32, 4);
add_hex(time_hi_and_version as u32, 4);
add_hex(clk_seq_hi_res as u32, 2);
add_hex(clk_seq_low as u32, 2);
for &byte in node.iter() {
add_hex(byte as u32, 2);
}
result
}
}
impl OwnedGuid {
pub const fn from_fields(
time_low: u32,
time_mid: u16,
time_hi_and_version: u16,
clk_seq_hi_res: u8,
clk_seq_low: u8,
node: [u8; 6],
) -> Self {
let efi_guid =
efi::Guid::from_fields(time_low, time_mid, time_hi_and_version, clk_seq_hi_res, clk_seq_low, &node);
Guid::Owned(efi_guid)
}
pub const ZERO: OwnedGuid = Self::from_fields(0, 0, 0, 0, 0, [0; 6]);
pub const fn try_from_string(s: &str) -> core::result::Result<OwnedGuid, GuidError> {
match guid_from_str(s) {
Ok(g) => Ok(OwnedGuid::Owned(g)),
Err(e) => Err(e),
}
}
pub const fn from_string(s: &str) -> OwnedGuid {
match Self::try_from_string(s) {
Ok(guid) => guid,
Err(_) => panic!("Invalid GUID string"),
}
}
}
impl core::fmt::Display for Guid<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let hex_chars = self.to_canonical_string();
for (i, &c) in hex_chars.iter().enumerate() {
if DASH_POSITIONS.contains(&i) {
write!(f, "-")?;
}
write!(f, "{}", c)?;
}
Ok(())
}
}
impl core::fmt::Debug for Guid<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", self)
}
}
impl PartialEq for Guid<'_> {
fn eq(&self, other: &Self) -> bool {
self.as_bytes() == other.as_bytes()
}
}
impl Eq for Guid<'_> {}
impl Ord for Guid<'_> {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.as_bytes().cmp(&other.as_bytes())
}
}
impl<'a> From<&'a efi::Guid> for Guid<'a> {
fn from(guid: &'a efi::Guid) -> Self {
Self::Borrowed(guid)
}
}
impl From<efi::Guid> for OwnedGuid {
fn from(guid: efi::Guid) -> Self {
Self::Owned(guid)
}
}
impl<'a> TryFrom<&'a str> for OwnedGuid {
type Error = GuidError;
fn try_from(s: &'a str) -> core::result::Result<Self, Self::Error> {
OwnedGuid::try_from_string(s)
}
}
macro_rules! parse_hex {
($chars:expr, $i:expr, $count:expr, $ty:ty) => {{
let mut value: $ty = 0;
let mut j = 0;
while j < $count {
let idx = $i + j;
value |= (char_to_val($chars[idx]) as $ty) << (4 * (($count - 1 - j) as u32));
j += 1;
}
value
}};
}
const fn guid_from_str(s: &str) -> core::result::Result<r_efi::efi::Guid, GuidError> {
let mut chars = [' '; EXPECTED_HEX_CHARS];
let mut char_count = 0;
let bytes = s.as_bytes();
let mut i = 0;
while i < s.len() {
if bytes[i] == b'-' || bytes[i].is_ascii_whitespace() {
i += 1;
continue;
}
if char_count >= EXPECTED_HEX_CHARS {
return Err(GuidError::InvalidLength { expected: EXPECTED_HEX_CHARS, actual: char_count + 1 });
}
if !bytes[i].is_ascii_hexdigit() {
return Err(GuidError::InvalidHexCharacter { position: i, character: bytes[i] as char });
}
chars[char_count] = bytes[i] as char;
char_count += 1;
i += 1;
}
if char_count != EXPECTED_HEX_CHARS {
return Err(GuidError::InvalidLength { expected: EXPECTED_HEX_CHARS, actual: char_count });
}
let time_low = parse_hex!(chars, 0, 8, u32);
let time_mid = parse_hex!(chars, 8, 4, u16);
let time_hi_and_version = parse_hex!(chars, 12, 4, u16);
let clk_seq_hi_res = parse_hex!(chars, 16, 2, u8);
let clk_seq_low = parse_hex!(chars, 18, 2, u8);
let node = [
parse_hex!(chars, 20, 2, u8),
parse_hex!(chars, 22, 2, u8),
parse_hex!(chars, 24, 2, u8),
parse_hex!(chars, 26, 2, u8),
parse_hex!(chars, 28, 2, u8),
parse_hex!(chars, 30, 2, u8),
];
Ok(r_efi::efi::Guid::from_fields(time_low, time_mid, time_hi_and_version, clk_seq_hi_res, clk_seq_low, &node))
}
const fn char_to_val(c: char) -> u8 {
match c {
'0'..='9' => c as u8 - b'0',
'a'..='f' => c as u8 - b'a' + 10,
'A'..='F' => c as u8 - b'A' + 10,
_ => panic!("Invalid hex character"),
}
}
#[cfg(test)]
#[coverage(off)]
mod tests {
use super::*;
use core::mem::{align_of, size_of};
use r_efi::base as r_efi_base;
const TEST_GUID_FIELDS: (u32, u16, u16, u8, u8, &[u8; 6]) =
(0x550e8400, 0xe29b, 0x41d4, 0xa7, 0x16, &[0x44, 0x66, 0x55, 0x44, 0x00, 0x00]);
const TEST_GUID_STRING: &str = "550e8400-e29b-41d4-a716-446655440000";
const TEST_GUID_STRING_UPPER: &str = "550E8400-E29B-41D4-A716-446655440000";
const TEST_GUID_STRING_NO_DASHES: &str = "550e8400e29b41d4a716446655440000";
const TEST_GUID_STRING_MIXED: &str = "550E8400-e29b-41D4-A716-446655440000";
fn create_test_r_efi_guid() -> r_efi_base::Guid {
let (time_low, time_mid, time_hi_and_version, clk_seq_hi_res, clk_seq_low, node) = TEST_GUID_FIELDS;
r_efi_base::Guid::from_fields(time_low, time_mid, time_hi_and_version, clk_seq_hi_res, clk_seq_low, node)
}
#[test]
fn memory_layout_compatible_with_r_efi_guid() {
let r_efi_guid = create_test_r_efi_guid();
let patina_guid = Guid::from_ref(&r_efi_guid);
assert_eq!(size_of::<r_efi_base::Guid>(), 16);
if let Guid::Borrowed(guid_ref) = patina_guid {
assert_eq!(guid_ref.as_bytes(), r_efi_guid.as_bytes());
assert_eq!(guid_ref.as_fields(), r_efi_guid.as_fields());
}
}
#[test]
fn memory_compatibility_and_size() {
let r_efi_guid = create_test_r_efi_guid();
let patina_guid_from_ref = Guid::from_ref(&r_efi_guid);
let patina_guid_from_string = OwnedGuid::from_string(TEST_GUID_STRING);
assert_eq!(patina_guid_from_ref.as_bytes().len(), 16);
assert_eq!(patina_guid_from_string.as_bytes().len(), 16);
assert_eq!(patina_guid_from_ref.as_bytes(), patina_guid_from_string.as_bytes());
assert_eq!(patina_guid_from_ref.as_bytes(), *r_efi_guid.as_bytes());
assert_eq!(patina_guid_from_string.as_bytes(), *r_efi_guid.as_bytes());
match patina_guid_from_string {
Guid::Owned(guid) => {
assert_eq!(size_of::<efi::Guid>(), 16);
assert_eq!(guid.as_fields(), TEST_GUID_FIELDS);
}
_ => panic!("Expected Owned variant"),
}
let bytes_from_patina = patina_guid_from_ref.as_bytes();
let roundtrip_r_efi = r_efi::efi::Guid::from_bytes(&bytes_from_patina);
assert_eq!(roundtrip_r_efi.as_bytes(), r_efi_guid.as_bytes());
}
#[test]
fn patina_guid_roundtrip_consistency() {
let original_string_guid = OwnedGuid::from_string(TEST_GUID_STRING);
let display_string = format!("{}", original_string_guid);
let roundtrip_guid = OwnedGuid::from_string(&display_string);
assert_eq!(original_string_guid.as_bytes(), roundtrip_guid.as_bytes());
assert_eq!(original_string_guid, roundtrip_guid);
let r_efi_guid = create_test_r_efi_guid();
let ref_guid = Guid::from_ref(&r_efi_guid);
let ref_display = format!("{}", ref_guid);
let bytes_guid = OwnedGuid::from_string(&ref_display);
assert_eq!(ref_guid.as_bytes(), bytes_guid.as_bytes());
assert_eq!(ref_guid, bytes_guid);
}
#[test]
fn patina_guid_api_methods() {
let test_guid = OwnedGuid::from_string(TEST_GUID_STRING);
let r_efi_guid = create_test_r_efi_guid();
let ref_guid: Guid<'static> = r_efi_guid.into();
let bytes_from_string = test_guid.as_bytes();
let bytes_from_ref = ref_guid.as_bytes();
assert_eq!(bytes_from_string.len(), 16);
assert_eq!(bytes_from_ref.len(), 16);
assert_eq!(bytes_from_string, bytes_from_ref);
let display_from_string = format!("{}", test_guid);
let display_from_ref = format!("{}", ref_guid);
assert_eq!(display_from_string, display_from_ref);
assert_eq!(display_from_string, TEST_GUID_STRING_UPPER);
}
#[test]
fn patina_guid_memory_efficiency() {
let patina_guid = OwnedGuid::from_string(TEST_GUID_STRING);
let bytes1 = patina_guid.as_bytes();
let bytes2 = patina_guid.as_bytes();
assert_eq!(bytes1, bytes2);
let r_efi_guid = create_test_r_efi_guid();
let ref_guid = Guid::from_ref(&r_efi_guid);
assert_eq!(patina_guid.as_bytes(), ref_guid.as_bytes());
let guid_size = 16; let patina_size = size_of::<OwnedGuid>();
assert!(
patina_size <= guid_size + 8,
"Patina GUID size ({}) is within expected limits ({})",
patina_size,
guid_size
);
}
#[test]
fn patina_guid_variant_behavior() {
let r_efi_guid = create_test_r_efi_guid();
let ref_guid = Guid::from_ref(&r_efi_guid);
match ref_guid {
Guid::Borrowed(_) => {}
_ => panic!("Expected Borrowed variant"),
}
let bytes_guid = OwnedGuid::from_string(TEST_GUID_STRING);
match bytes_guid {
Guid::Owned(_) => {}
_ => panic!("Expected Owned variant"),
}
assert_eq!(ref_guid.as_bytes(), bytes_guid.as_bytes());
assert_eq!(ref_guid, bytes_guid);
assert_eq!(format!("{}", ref_guid), format!("{}", bytes_guid));
let ref_guid_clone = ref_guid.clone();
let bytes_guid_clone = bytes_guid.clone();
assert_eq!(ref_guid, ref_guid_clone);
assert_eq!(bytes_guid, bytes_guid_clone);
let debug_ref = format!("{:?}", ref_guid);
let debug_bytes = format!("{:?}", bytes_guid);
assert_eq!(debug_ref, debug_bytes);
assert_eq!(debug_ref, TEST_GUID_STRING_UPPER);
}
#[test]
fn test_owned_guid_from_string_construction_failure_panic() {
let invalid_guid_str = "invalid-guid-string";
let result = std::panic::catch_unwind(|| {
OwnedGuid::from_string(invalid_guid_str);
});
assert!(result.is_err_and(|e| e.downcast_ref::<&'static str>() == Some(&"Invalid GUID string")));
}
#[test]
fn from_ref_construction() {
let r_efi_guid = create_test_r_efi_guid();
let guid = Guid::from_ref(&r_efi_guid);
match guid {
Guid::Borrowed(guid_ref) => {
assert_eq!(guid_ref.as_fields(), TEST_GUID_FIELDS);
}
_ => panic!("Expected Borrowed variant"),
}
}
#[test]
fn try_from_string_valid() {
let test_cases = [TEST_GUID_STRING, TEST_GUID_STRING_UPPER, TEST_GUID_STRING_NO_DASHES, TEST_GUID_STRING_MIXED];
for input in test_cases {
let result = OwnedGuid::try_from_string(input);
assert!(result.is_ok(), "Failed to parse valid GUID string: {}", input);
match result.unwrap() {
Guid::Owned(_) => {}
_ => panic!("Expected Owned variant"),
}
}
}
#[test]
fn try_from_string_invalid_length() {
let invalid_cases =
[("550e8400-e29b-41d4-a716-4466554400", 30), ("", 0), ("550e8400-e29b-41d4-a716-44665544000000", 34)];
for (input, _expected_count) in invalid_cases {
let result = OwnedGuid::try_from_string(input);
assert!(result.is_err(), "Should have failed for invalid length: {}", input);
match result.unwrap_err() {
GuidError::InvalidLength { .. } => {}
other => panic!("Expected InvalidLength error for: {}, got: {:?}", input, other),
}
}
}
#[test]
fn try_from_string_invalid_mixed_cases() {
let invalid_cases = ["too-short", "not-a-guid-at-all"];
for input in invalid_cases {
let result = OwnedGuid::try_from_string(input);
assert!(result.is_err(), "Should have failed for invalid input: {}", input);
}
}
#[test]
fn try_from_string_invalid_characters() {
let invalid_cases =
["550e8400-e29b-41d4-a716-44665544000g", "not-a-guid-at-all", "550e8400-e29b-41d4-a716-44665544000z"];
for input in invalid_cases {
let result = OwnedGuid::try_from_string(input);
assert!(result.is_err(), "Should have failed for invalid character: {}", input);
match result.unwrap_err() {
GuidError::InvalidHexCharacter { .. } => {}
_ => panic!("Expected InvalidHexCharacter error for: {}", input),
}
}
}
#[test]
fn try_from_trait_implementations() {
let r_efi_guid = create_test_r_efi_guid();
let guid_from_ref: Guid = (&r_efi_guid).into();
let guid_from_string_result: core::result::Result<OwnedGuid, GuidError> = TEST_GUID_STRING.try_into();
assert!(guid_from_string_result.is_ok());
let guid_from_string = guid_from_string_result.unwrap();
assert!(matches!(guid_from_ref, Guid::Borrowed(_)));
assert!(matches!(guid_from_string, Guid::Owned(_)));
}
#[test]
fn display_from_ref() {
let r_efi_guid = create_test_r_efi_guid();
let guid = Guid::from_ref(&r_efi_guid);
let display_string = format!("{}", guid);
assert_eq!(display_string, TEST_GUID_STRING_UPPER);
}
#[test]
fn display_from_valid_string() {
let test_cases = [TEST_GUID_STRING, TEST_GUID_STRING_UPPER, TEST_GUID_STRING_NO_DASHES, TEST_GUID_STRING_MIXED];
for input in test_cases {
let guid = OwnedGuid::try_from_string(input).expect("Valid GUID string should parse");
let display_string = format!("{}", guid);
assert_eq!(display_string, TEST_GUID_STRING_UPPER);
}
}
#[test]
fn debug_format() {
let r_efi_guid = create_test_r_efi_guid();
let guid = Guid::from_ref(&r_efi_guid);
let debug_string = format!("{:?}", guid);
assert_eq!(debug_string, TEST_GUID_STRING_UPPER);
}
#[test]
fn equality_same_variants() {
let r_efi_guid = create_test_r_efi_guid();
let guid1 = Guid::from_ref(&r_efi_guid);
let guid2 = Guid::from_ref(&r_efi_guid);
assert_eq!(guid1, guid2);
let guid3 = OwnedGuid::from_string(TEST_GUID_STRING);
let guid4 = OwnedGuid::from_string(TEST_GUID_STRING);
assert_eq!(guid3, guid4);
}
#[test]
fn equality_different_variants() {
let r_efi_guid = create_test_r_efi_guid();
let guid_from_ref = Guid::from_ref(&r_efi_guid);
let test_cases = [TEST_GUID_STRING, TEST_GUID_STRING_UPPER, TEST_GUID_STRING_NO_DASHES, TEST_GUID_STRING_MIXED];
for input in test_cases {
let guid_from_string = OwnedGuid::from_string(input);
assert_eq!(guid_from_ref, guid_from_string, "Failed for input: {}", input);
}
}
#[test]
fn inequality_different_guids() {
let r_efi_guid1 = create_test_r_efi_guid();
let r_efi_guid2 = r_efi_base::Guid::from_fields(
0x12345678,
0x1234,
0x5678,
0x90,
0xab,
&[0xcd, 0xef, 0x12, 0x34, 0x56, 0x78],
);
let guid1 = Guid::from_ref(&r_efi_guid1);
let guid2 = Guid::from_ref(&r_efi_guid2);
assert_ne!(guid1, guid2);
}
#[test]
fn canonical_string_conversion() {
let r_efi_guid = create_test_r_efi_guid();
let guid_from_ref = Guid::from_ref(&r_efi_guid);
let guid_from_string = OwnedGuid::from_string(TEST_GUID_STRING_MIXED);
let canonical1 = guid_from_ref.to_canonical_string();
let canonical2 = guid_from_string.to_canonical_string();
assert_eq!(canonical1, canonical2);
}
#[test]
fn clone_functionality() {
let r_efi_guid = create_test_r_efi_guid();
let guid1 = Guid::from_ref(&r_efi_guid);
let guid2 = guid1.clone();
assert_eq!(guid1, guid2);
let guid3 = OwnedGuid::from_string(TEST_GUID_STRING);
let guid4 = guid3.clone();
assert_eq!(guid3, guid4);
}
#[test]
fn r_efi_guid_fields_consistency() {
let r_efi_guid = create_test_r_efi_guid();
let fields = r_efi_guid.as_fields();
assert_eq!(fields, TEST_GUID_FIELDS);
let bytes = r_efi_guid.as_bytes();
let reconstructed = r_efi_base::Guid::from_bytes(bytes);
assert_eq!(reconstructed.as_fields(), TEST_GUID_FIELDS);
}
#[test]
fn whitespace_handling() {
let spaced_guid = " 550e8400-e29b-41d4-a716-446655440000 ";
let guid = OwnedGuid::try_from_string(spaced_guid).expect("Should handle whitespace");
assert_eq!(format!("{}", guid), TEST_GUID_STRING_UPPER);
}
#[test]
fn error_conversion_to_efi_error() {
let error = GuidError::InvalidLength { expected: 32, actual: 30 };
let efi_error: EfiError = error.into();
assert_eq!(efi_error, EfiError::InvalidParameter);
let error = GuidError::InvalidHexCharacter { position: 5, character: 'z' };
let efi_error: EfiError = error.into();
assert_eq!(efi_error, EfiError::InvalidParameter);
}
#[test]
fn error_display() {
let error = GuidError::InvalidLength { expected: 32, actual: 30 };
let display = format!("{}", error);
assert_eq!(display, "Invalid GUID length: expected 32 hex characters, found 30");
let error = GuidError::InvalidHexCharacter { position: 5, character: 'z' };
let display = format!("{}", error);
assert_eq!(display, "Invalid hex character 'z' at position 5");
}
#[test]
fn c_interop_from_ref_variant() {
let r_efi_guid = create_test_r_efi_guid();
let patina_guid = Guid::from_ref(&r_efi_guid);
let patina_bytes = patina_guid.as_bytes();
let r_efi_bytes = r_efi_guid.as_bytes();
assert_eq!(patina_bytes, *r_efi_bytes);
assert_eq!(patina_bytes.len(), 16);
let patina_fields = match patina_guid {
Guid::Borrowed(guid) => guid.as_fields(),
_ => panic!("Expected Borrowed variant"),
};
let r_efi_fields = r_efi_guid.as_fields();
assert_eq!(patina_fields, r_efi_fields);
assert_eq!(patina_fields, TEST_GUID_FIELDS);
let r_efi_ptr = &r_efi_guid as *const r_efi_base::Guid;
let patina_ptr = match patina_guid {
Guid::Borrowed(guid) => guid as *const efi::Guid,
_ => panic!("Expected Borrowed variant"),
};
assert_eq!(r_efi_ptr as *const u8, patina_ptr as *const u8);
unsafe {
let r_efi_slice = core::slice::from_raw_parts(r_efi_ptr as *const u8, 16);
let patina_slice = core::slice::from_raw_parts(patina_ptr as *const u8, 16);
assert_eq!(r_efi_slice, patina_slice);
}
}
#[test]
fn c_interop_from_bytes_variant() {
let patina_guid = OwnedGuid::from_string(TEST_GUID_STRING);
let patina_bytes = patina_guid.as_bytes();
assert_eq!(patina_bytes.len(), 16);
let r_efi_guid = create_test_r_efi_guid();
let r_efi_bytes = r_efi_guid.as_bytes();
assert_eq!(patina_bytes, *r_efi_bytes);
let patina_fields = match patina_guid {
Guid::Owned(ref guid) => guid.as_fields(),
_ => panic!("Expected Owned variant"),
};
let r_efi_fields = r_efi_guid.as_fields();
assert_eq!(patina_fields, r_efi_fields);
assert_eq!(patina_fields, TEST_GUID_FIELDS);
let patina_as_efi = match &patina_guid {
Guid::Owned(guid) => *guid,
_ => panic!("Expected Owned variant"),
};
assert_eq!(core::mem::size_of_val(&patina_as_efi), 16);
assert_eq!(patina_as_efi.as_bytes(), r_efi_guid.as_bytes());
let patina_ptr = &patina_as_efi as *const efi::Guid;
unsafe {
let patina_slice = core::slice::from_raw_parts(patina_ptr as *const u8, 16);
let r_efi_slice = core::slice::from_raw_parts(&r_efi_guid as *const _ as *const u8, 16);
assert_eq!(patina_slice, r_efi_slice);
}
}
#[test]
fn c_interop_cross_variant_compatibility() {
let r_efi_guid = create_test_r_efi_guid();
let from_ref_guid = Guid::from_ref(&r_efi_guid);
let from_bytes_guid = OwnedGuid::from_string(TEST_GUID_STRING);
let ref_bytes = from_ref_guid.as_bytes();
let bytes_bytes = from_bytes_guid.as_bytes();
assert_eq!(ref_bytes, bytes_bytes);
assert_eq!(ref_bytes.len(), 16);
assert_eq!(bytes_bytes.len(), 16);
let ref_fields = match from_ref_guid {
Guid::Borrowed(guid) => guid.as_fields(),
_ => panic!("Expected Borrowed variant"),
};
let bytes_fields = match from_bytes_guid {
Guid::Owned(ref guid) => guid.as_fields(),
_ => panic!("Expected Owned variant"),
};
assert_eq!(ref_fields, bytes_fields);
assert_eq!(ref_fields, TEST_GUID_FIELDS);
let ref_c_guid = match from_ref_guid {
Guid::Borrowed(guid) => guid,
_ => panic!("Expected Borrowed variant"),
};
let bytes_c_guid = match &from_bytes_guid {
Guid::Owned(guid) => *guid,
_ => panic!("Expected Owned variant"),
};
assert_eq!(ref_c_guid.as_bytes(), bytes_c_guid.as_bytes());
assert_eq!(core::mem::size_of_val(ref_c_guid), core::mem::size_of_val(&bytes_c_guid));
}
#[test]
fn c_interop_memory_alignment() {
let r_efi_guid = create_test_r_efi_guid();
let from_ref_guid = Guid::from_ref(&r_efi_guid);
let from_bytes_guid = OwnedGuid::from_string(TEST_GUID_STRING);
assert_eq!(align_of::<r_efi_base::Guid>(), align_of::<efi::Guid>());
assert_eq!(size_of::<r_efi_base::Guid>(), size_of::<efi::Guid>());
assert_eq!(size_of::<r_efi_base::Guid>(), 16);
let ref_c_guid = match from_ref_guid {
Guid::Borrowed(guid) => guid,
_ => panic!("Expected Borrowed variant"),
};
let bytes_c_guid = match &from_bytes_guid {
Guid::Owned(guid) => *guid,
_ => panic!("Expected Owned variant"),
};
let ref_ptr = ref_c_guid as *const efi::Guid;
let bytes_ptr = &bytes_c_guid as *const efi::Guid;
assert_eq!(ref_ptr as usize % align_of::<efi::Guid>(), 0);
assert_eq!(bytes_ptr as usize % align_of::<efi::Guid>(), 0);
assert_eq!((ref_ptr as usize) % align_of::<r_efi_base::Guid>(), 0);
assert_eq!((bytes_ptr as usize) % align_of::<r_efi_base::Guid>(), 0);
}
#[test]
fn c_interop_uefi_byte_order() {
let r_efi_guid = create_test_r_efi_guid();
let from_ref_guid = Guid::from_ref(&r_efi_guid);
let from_bytes_guid = OwnedGuid::from_string(TEST_GUID_STRING);
let expected_bytes = [
0x00, 0x84, 0x0e, 0x55, 0x9b, 0xe2, 0xd4, 0x41, 0xa7, 0x16, 0x44, 0x66, 0x55, 0x44, 0x00, 0x00, ];
assert_eq!(from_ref_guid.as_bytes(), expected_bytes);
assert_eq!(from_bytes_guid.as_bytes(), expected_bytes);
assert_eq!(r_efi_guid.as_bytes(), &expected_bytes);
unsafe {
let r_efi_ptr = &r_efi_guid as *const r_efi_base::Guid;
let r_efi_slice = core::slice::from_raw_parts(r_efi_ptr as *const u8, 16);
assert_eq!(r_efi_slice, expected_bytes);
}
}
#[test]
fn from_bytes_method() {
let test_bytes = [
0x00, 0x84, 0x0e, 0x55, 0x9b, 0xe2, 0xd4, 0x41, 0xa7, 0x16, 0x44, 0x66, 0x55, 0x44, 0x00, 0x00, ];
let guid_from_bytes = Guid::from_bytes(&test_bytes);
let guid_from_string = OwnedGuid::from_string(TEST_GUID_STRING);
assert_eq!(guid_from_bytes, guid_from_string);
assert_eq!(guid_from_bytes.as_bytes(), test_bytes);
assert_eq!(guid_from_bytes.as_bytes(), guid_from_string.as_bytes());
match guid_from_bytes {
Guid::Owned(_) => {}
_ => panic!("Expected Owned variant from from_bytes"),
}
let fields = guid_from_bytes.as_fields();
assert_eq!(fields, TEST_GUID_FIELDS);
assert_eq!(format!("{}", guid_from_bytes), TEST_GUID_STRING_UPPER);
}
#[test]
fn binary_guid_size_and_alignment() {
assert_eq!(size_of::<BinaryGuid>(), size_of::<efi::Guid>());
assert_eq!(align_of::<BinaryGuid>(), align_of::<efi::Guid>());
assert_eq!(size_of::<BinaryGuid>(), 16);
}
#[test]
fn binary_guid_repr_transparent() {
let efi_guid = create_test_r_efi_guid();
let binary_guid = BinaryGuid(efi_guid);
let efi_ptr = &efi_guid as *const efi::Guid as *const u8;
let binary_ptr = &binary_guid as *const BinaryGuid as *const u8;
unsafe {
let efi_bytes = core::slice::from_raw_parts(efi_ptr, 16);
let binary_bytes = core::slice::from_raw_parts(binary_ptr, 16);
assert_eq!(efi_bytes, binary_bytes);
}
}
#[test]
fn binary_guid_from_fields() {
let (time_low, time_mid, time_hi_and_version, clk_seq_hi_res, clk_seq_low, node) = TEST_GUID_FIELDS;
let binary_guid =
BinaryGuid::from_fields(time_low, time_mid, time_hi_and_version, clk_seq_hi_res, clk_seq_low, node);
let expected_fields = binary_guid.as_fields();
assert_eq!(expected_fields, TEST_GUID_FIELDS);
const CONST_BINARY_GUID: BinaryGuid =
BinaryGuid::from_fields(0x550e8400, 0xe29b, 0x41d4, 0xa7, 0x16, &[0x44, 0x66, 0x55, 0x44, 0x00, 0x00]);
assert_eq!(CONST_BINARY_GUID.as_fields(), TEST_GUID_FIELDS);
}
#[test]
fn binary_guid_from_bytes() {
let test_bytes = [
0x00, 0x84, 0x0e, 0x55, 0x9b, 0xe2, 0xd4, 0x41, 0xa7, 0x16, 0x44, 0x66, 0x55, 0x44, 0x00, 0x00, ];
let binary_guid = BinaryGuid::from_bytes(&test_bytes);
assert_eq!(binary_guid.as_bytes(), &test_bytes);
assert_eq!(binary_guid.as_fields(), TEST_GUID_FIELDS);
}
#[test]
fn binary_guid_try_from_string() {
let test_cases = [TEST_GUID_STRING, TEST_GUID_STRING_UPPER, TEST_GUID_STRING_NO_DASHES, TEST_GUID_STRING_MIXED];
for input in test_cases {
let result = BinaryGuid::try_from_string(input);
assert!(result.is_ok(), "Failed to parse valid GUID string: {}", input);
let binary_guid = result.unwrap();
assert_eq!(binary_guid.as_fields(), TEST_GUID_FIELDS);
}
let invalid_input = "invalid-guid-string";
assert!(BinaryGuid::try_from_string(invalid_input).is_err(), "Should have failed for invalid input");
}
#[test]
fn binary_guid_as_guid_conversion() {
let binary_guid =
BinaryGuid::from_fields(0x550e8400, 0xe29b, 0x41d4, 0xa7, 0x16, &[0x44, 0x66, 0x55, 0x44, 0x00, 0x00]);
let guid_ref = binary_guid.as_guid();
match guid_ref {
Guid::Borrowed(_) => {}
_ => panic!("Expected Borrowed variant from as_guid()"),
}
assert_eq!(guid_ref.as_fields(), binary_guid.as_fields());
assert_eq!(format!("{}", guid_ref), format!("{}", binary_guid));
}
#[test]
fn binary_guid_to_owned_guid_conversion() {
let binary_guid =
BinaryGuid::from_fields(0x550e8400, 0xe29b, 0x41d4, 0xa7, 0x16, &[0x44, 0x66, 0x55, 0x44, 0x00, 0x00]);
let owned_guid = binary_guid.to_owned_guid();
match owned_guid {
Guid::Owned(_) => {}
_ => panic!("Expected Owned variant from to_owned_guid()"),
}
assert_eq!(owned_guid.as_fields(), binary_guid.as_fields());
assert_eq!(format!("{}", owned_guid), format!("{}", binary_guid));
}
#[test]
fn binary_guid_as_bytes() {
let binary_guid =
BinaryGuid::from_fields(0x550e8400, 0xe29b, 0x41d4, 0xa7, 0x16, &[0x44, 0x66, 0x55, 0x44, 0x00, 0x00]);
let bytes = binary_guid.as_bytes();
let expected_bytes = [
0x00, 0x84, 0x0e, 0x55, 0x9b, 0xe2, 0xd4, 0x41, 0xa7, 0x16, 0x44, 0x66, 0x55, 0x44, 0x00, 0x00, ];
assert_eq!(bytes, &expected_bytes);
}
#[test]
fn binary_guid_as_fields() {
let binary_guid =
BinaryGuid::from_fields(0x550e8400, 0xe29b, 0x41d4, 0xa7, 0x16, &[0x44, 0x66, 0x55, 0x44, 0x00, 0x00]);
let fields = binary_guid.as_fields();
assert_eq!(fields, TEST_GUID_FIELDS);
}
#[test]
fn binary_guid_from_efi_guid_conversions() {
let efi_guid = create_test_r_efi_guid();
let binary_guid_from_value = BinaryGuid::from(efi_guid);
assert_eq!(binary_guid_from_value.as_fields(), TEST_GUID_FIELDS);
let binary_guid_from_ref = BinaryGuid::from(&efi_guid);
assert_eq!(binary_guid_from_ref.as_fields(), TEST_GUID_FIELDS);
assert_eq!(binary_guid_from_value, binary_guid_from_ref);
}
#[test]
fn binary_guid_to_efi_guid_conversions() {
let binary_guid =
BinaryGuid::from_fields(0x550e8400, 0xe29b, 0x41d4, 0xa7, 0x16, &[0x44, 0x66, 0x55, 0x44, 0x00, 0x00]);
let efi_guid_from_value: efi::Guid = binary_guid.into();
assert_eq!(efi_guid_from_value.as_fields(), TEST_GUID_FIELDS);
let efi_guid_from_ref: efi::Guid = (&binary_guid).into();
assert_eq!(efi_guid_from_ref.as_fields(), TEST_GUID_FIELDS);
assert_eq!(efi_guid_from_value, efi_guid_from_ref);
}
#[test]
fn binary_guid_from_guid_conversions() {
let owned_guid = OwnedGuid::from_string(TEST_GUID_STRING);
let binary_guid_from_owned: BinaryGuid = owned_guid.into();
assert_eq!(binary_guid_from_owned.as_fields(), TEST_GUID_FIELDS);
let back_to_owned: OwnedGuid = binary_guid_from_owned.into();
assert_eq!(back_to_owned.as_fields(), TEST_GUID_FIELDS);
assert_eq!(format!("{}", back_to_owned), TEST_GUID_STRING_UPPER);
}
#[test]
fn binary_guid_guid_reference_conversion() {
let binary_guid =
BinaryGuid::from_fields(0x550e8400, 0xe29b, 0x41d4, 0xa7, 0x16, &[0x44, 0x66, 0x55, 0x44, 0x00, 0x00]);
let guid_from_ref: Guid = (&binary_guid).into();
match guid_from_ref {
Guid::Borrowed(_) => {}
_ => panic!("Expected Borrowed variant from &BinaryGuid conversion"),
}
assert_eq!(guid_from_ref.as_fields(), binary_guid.as_fields());
assert_eq!(format!("{}", guid_from_ref), format!("{}", binary_guid));
}
#[test]
fn binary_guid_deref() {
let binary_guid =
BinaryGuid::from_fields(0x550e8400, 0xe29b, 0x41d4, 0xa7, 0x16, &[0x44, 0x66, 0x55, 0x44, 0x00, 0x00]);
let fields_via_deref = binary_guid.as_fields();
let bytes_via_deref = binary_guid.as_bytes();
assert_eq!(fields_via_deref, TEST_GUID_FIELDS);
assert_eq!(bytes_via_deref, binary_guid.as_bytes());
}
#[test]
fn binary_guid_partial_eq_with_efi_guid() {
let efi_guid = create_test_r_efi_guid();
let binary_guid = BinaryGuid::from(efi_guid);
assert_eq!(binary_guid, efi_guid);
assert_eq!(efi_guid, binary_guid);
let different_efi_guid =
efi::Guid::from_fields(0x12345678, 0x1234, 0x5678, 0x90, 0xab, &[0xcd, 0xef, 0x12, 0x34, 0x56, 0x78]);
assert_ne!(binary_guid, different_efi_guid);
assert_ne!(different_efi_guid, binary_guid);
}
#[test]
fn binary_guid_partial_eq_with_guid() {
let binary_guid =
BinaryGuid::from_fields(0x550e8400, 0xe29b, 0x41d4, 0xa7, 0x16, &[0x44, 0x66, 0x55, 0x44, 0x00, 0x00]);
let owned_guid = OwnedGuid::from_string(TEST_GUID_STRING);
assert_eq!(binary_guid, owned_guid);
assert_eq!(owned_guid, binary_guid);
let efi_guid = create_test_r_efi_guid();
let borrowed_guid = Guid::from_ref(&efi_guid);
assert_eq!(binary_guid, borrowed_guid);
assert_eq!(borrowed_guid, binary_guid);
let different_guid = OwnedGuid::from_string("12345678-1234-5678-90AB-CDEF12345678");
assert_ne!(binary_guid, different_guid);
assert_ne!(different_guid, binary_guid);
}
#[test]
fn binary_guid_display() {
let binary_guid =
BinaryGuid::from_fields(0x550e8400, 0xe29b, 0x41d4, 0xa7, 0x16, &[0x44, 0x66, 0x55, 0x44, 0x00, 0x00]);
let display_string = format!("{}", binary_guid);
assert_eq!(display_string, TEST_GUID_STRING_UPPER);
let owned_guid = OwnedGuid::from_string(TEST_GUID_STRING);
assert_eq!(format!("{}", binary_guid), format!("{}", owned_guid));
}
#[test]
fn binary_guid_debug() {
let binary_guid =
BinaryGuid::from_fields(0x550e8400, 0xe29b, 0x41d4, 0xa7, 0x16, &[0x44, 0x66, 0x55, 0x44, 0x00, 0x00]);
let debug_string = format!("{:?}", binary_guid);
assert!(debug_string.contains("BinaryGuid"));
}
#[test]
fn binary_guid_copy_clone() {
let binary_guid =
BinaryGuid::from_fields(0x550e8400, 0xe29b, 0x41d4, 0xa7, 0x16, &[0x44, 0x66, 0x55, 0x44, 0x00, 0x00]);
let copied_guid = binary_guid;
assert_eq!(copied_guid, binary_guid);
let copied_guid2 = binary_guid;
assert_eq!(copied_guid2, binary_guid);
assert_eq!(binary_guid.as_fields(), copied_guid.as_fields());
assert_eq!(binary_guid.as_fields(), copied_guid2.as_fields());
}
#[test]
fn binary_guid_hash() {
use core::hash::{Hash, Hasher};
struct TestHasher {
state: u64,
}
impl TestHasher {
fn new() -> Self {
Self { state: 0 }
}
}
impl Hasher for TestHasher {
fn finish(&self) -> u64 {
self.state
}
fn write(&mut self, bytes: &[u8]) {
for &byte in bytes {
self.state = self.state.wrapping_mul(31).wrapping_add(byte as u64);
}
}
}
let binary_guid1 =
BinaryGuid::from_fields(0x550e8400, 0xe29b, 0x41d4, 0xa7, 0x16, &[0x44, 0x66, 0x55, 0x44, 0x00, 0x00]);
let binary_guid2 =
BinaryGuid::from_fields(0x550e8400, 0xe29b, 0x41d4, 0xa7, 0x16, &[0x44, 0x66, 0x55, 0x44, 0x00, 0x00]);
let binary_guid3 =
BinaryGuid::from_fields(0x12345678, 0x1234, 0x5678, 0x90, 0xab, &[0xcd, 0xef, 0x12, 0x34, 0x56, 0x78]);
let mut hasher1 = TestHasher::new();
let mut hasher2 = TestHasher::new();
let mut hasher3 = TestHasher::new();
binary_guid1.hash(&mut hasher1);
binary_guid2.hash(&mut hasher2);
binary_guid3.hash(&mut hasher3);
assert_eq!(hasher1.finish(), hasher2.finish());
assert_ne!(hasher1.finish(), hasher3.finish());
}
#[test]
fn binary_guid_ord_matches_guid_byte_ordering() {
let guids = [
BinaryGuid::from_string("00000000-0000-0000-0000-000000000000"),
BinaryGuid::from_string("00000000-0000-0000-0000-000000000001"),
BinaryGuid::from_string("00000000-0000-0000-0001-000000000000"),
BinaryGuid::from_string("00000000-0000-0001-0000-000000000000"),
BinaryGuid::from_string("00000000-0001-0000-0000-000000000000"),
BinaryGuid::from_string("00000001-0000-0000-0000-000000000000"),
BinaryGuid::from_string("01000000-0000-0000-0000-000000000000"),
BinaryGuid::from_string("FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF"),
BinaryGuid::from_string("550E8400-E29B-41D4-A716-446655440000"),
BinaryGuid::from_string("550E8400-E29B-41D4-A716-446655440001"),
BinaryGuid::from_string("23C9322F-2AF2-476A-BC4C-26BC88266C71"),
];
for (i, a) in guids.iter().enumerate() {
for (j, b) in guids.iter().enumerate() {
let binary_ord = a.cmp(b);
let guid_ord = a.to_owned_guid().cmp(&b.to_owned_guid());
assert_eq!(
binary_ord, guid_ord,
"Ordering mismatch at guids[{i}] vs guids[{j}]: BinaryGuid is {:?}, Guid is {:?}",
binary_ord, guid_ord
);
}
}
}
#[test]
fn binary_guid_in_c_struct() {
#[repr(C)]
struct TestHeader {
signature: u32,
guid: BinaryGuid,
version: u16,
}
let header = TestHeader {
signature: 0x12345678,
guid: BinaryGuid::from_fields(
0x550e8400,
0xe29b,
0x41d4,
0xa7,
0x16,
&[0x44, 0x66, 0x55, 0x44, 0x00, 0x00],
),
version: 1,
};
assert_eq!(header.guid.as_fields(), TEST_GUID_FIELDS);
assert_eq!(format!("{}", header.guid), TEST_GUID_STRING_UPPER);
assert_eq!(size_of::<TestHeader>(), 24);
}
#[test]
fn binary_guid_zero_constant() {
const ZERO_BINARY_GUID: BinaryGuid = BinaryGuid::from_fields(0, 0, 0, 0, 0, &[0; 6]);
let zero_fields = ZERO_BINARY_GUID.as_fields();
assert_eq!(zero_fields, (0, 0, 0, 0, 0, &[0; 6]));
let zero_bytes = ZERO_BINARY_GUID.as_bytes();
assert_eq!(zero_bytes, &[0; 16]);
assert_eq!(format!("{}", ZERO_BINARY_GUID), "00000000-0000-0000-0000-000000000000");
}
#[test]
fn binary_guid_const_evaluation() {
const TEST_BINARY_GUID: BinaryGuid =
BinaryGuid::from_fields(0x550e8400, 0xe29b, 0x41d4, 0xa7, 0x16, &[0x44, 0x66, 0x55, 0x44, 0x00, 0x00]);
assert_eq!(TEST_BINARY_GUID.as_fields(), TEST_GUID_FIELDS);
assert_eq!(format!("{}", TEST_BINARY_GUID), TEST_GUID_STRING_UPPER);
let runtime_guid =
BinaryGuid::from_fields(0x550e8400, 0xe29b, 0x41d4, 0xa7, 0x16, &[0x44, 0x66, 0x55, 0x44, 0x00, 0x00]);
assert_eq!(TEST_BINARY_GUID, runtime_guid);
}
#[test]
fn binary_guid_zerocopy_operations() {
let guid_bytes: [u8; 16] =
[0x00, 0x84, 0x0e, 0x55, 0x9b, 0xe2, 0xd4, 0x41, 0xa7, 0x16, 0x44, 0x66, 0x55, 0x44, 0x00, 0x00];
let binary_guid_from_bytes = BinaryGuid::from_bytes(&guid_bytes);
let bytes_from_guid = binary_guid_from_bytes.as_bytes();
assert_eq!(bytes_from_guid, &guid_bytes);
assert_eq!(size_of::<BinaryGuid>(), size_of::<efi::Guid>());
assert_eq!(size_of::<BinaryGuid>(), 16);
let multiple_guids_bytes: [u8; 32] = [
0x00, 0x84, 0x0e, 0x55, 0x9b, 0xe2, 0xd4, 0x41, 0xa7, 0x16, 0x44, 0x66, 0x55, 0x44, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
let first_guid_bytes: &[u8; 16] = multiple_guids_bytes[0..16].try_into().unwrap();
let first_guid = BinaryGuid::from_bytes(first_guid_bytes);
let second_guid_bytes: &[u8; 16] = multiple_guids_bytes[16..32].try_into().unwrap();
let second_guid = BinaryGuid::from_bytes(second_guid_bytes);
assert_eq!(first_guid.as_fields(), TEST_GUID_FIELDS);
assert_eq!(second_guid.as_fields(), (0, 0, 0, 0, 0, &[0; 6]));
let binary_guid =
BinaryGuid::from_fields(0x550e8400, 0xe29b, 0x41d4, 0xa7, 0x16, &[0x44, 0x66, 0x55, 0x44, 0x00, 0x00]);
let guid_ptr = &binary_guid as *const BinaryGuid;
let efi_guid_ptr = &binary_guid.0 as *const efi::Guid;
assert_eq!(guid_ptr as *const u8, efi_guid_ptr as *const u8);
let efi_guid = create_test_r_efi_guid();
let binary_guid_from_efi = BinaryGuid::from(efi_guid);
unsafe {
let efi_bytes = core::slice::from_raw_parts(&efi_guid as *const _ as *const u8, 16);
let binary_bytes = core::slice::from_raw_parts(&binary_guid_from_efi as *const _ as *const u8, 16);
assert_eq!(efi_bytes, binary_bytes);
}
let guid_array = [
BinaryGuid::from_fields(0x550e8400, 0xe29b, 0x41d4, 0xa7, 0x16, &[0x44, 0x66, 0x55, 0x44, 0x00, 0x00]),
BinaryGuid::from_fields(0x12345678, 0x1234, 0x5678, 0x90, 0xab, &[0xcd, 0xef, 0x12, 0x34, 0x56, 0x78]),
];
let first_element_bytes = guid_array[0].as_bytes();
let second_element_bytes = guid_array[1].as_bytes();
assert_eq!(first_element_bytes, &guid_bytes);
assert_ne!(first_element_bytes, second_element_bytes);
#[repr(C)]
struct FirmwareTable {
signature: u32,
guids: [BinaryGuid; 2],
checksum: u32,
}
let table = FirmwareTable {
signature: 0x46495246, guids: guid_array,
checksum: 0xDEADBEEF,
};
let table_guid_bytes = table.guids[0].as_bytes();
assert_eq!(table_guid_bytes, &guid_bytes);
assert_eq!(size_of::<FirmwareTable>(), 4 + 32 + 4);
}
#[test]
fn test_binary_guid_from_string_construction_failure_panic() {
let invalid_guid_str = "invalid-guid-string";
let result = std::panic::catch_unwind(|| {
BinaryGuid::from_string(invalid_guid_str);
});
assert!(result.is_err_and(|e| e.downcast_ref::<&'static str>() == Some(&"Invalid GUID string")));
}
#[test]
fn binary_guid_into_inner() {
let binary_guid =
BinaryGuid::from_fields(0x550e8400, 0xe29b, 0x41d4, 0xa7, 0x16, &[0x44, 0x66, 0x55, 0x44, 0x00, 0x00]);
let efi_guid = binary_guid.into_inner();
assert_eq!(efi_guid.as_fields(), TEST_GUID_FIELDS);
assert_eq!(efi_guid.as_bytes(), binary_guid.as_bytes());
}
#[test]
fn binary_guid_as_efi_guid() {
let binary_guid =
BinaryGuid::from_fields(0x550e8400, 0xe29b, 0x41d4, 0xa7, 0x16, &[0x44, 0x66, 0x55, 0x44, 0x00, 0x00]);
let efi_guid_ref = binary_guid.as_efi_guid();
assert_eq!(efi_guid_ref.as_fields(), TEST_GUID_FIELDS);
assert_eq!(efi_guid_ref.as_bytes(), binary_guid.as_bytes());
let ptr1 = &binary_guid.0 as *const efi::Guid;
let ptr2 = efi_guid_ref as *const efi::Guid;
assert_eq!(ptr1, ptr2);
}
#[test]
fn binary_guid_as_mut_efi_guid() {
let mut binary_guid =
BinaryGuid::from_fields(0x550e8400, 0xe29b, 0x41d4, 0xa7, 0x16, &[0x44, 0x66, 0x55, 0x44, 0x00, 0x00]);
let efi_guid_mut = binary_guid.as_mut_efi_guid();
*efi_guid_mut =
efi::Guid::from_fields(0x12345678, 0x1234, 0x5678, 0x90, 0xab, &[0xcd, 0xef, 0x12, 0x34, 0x56, 0x78]);
assert_eq!(
binary_guid.as_fields(),
(0x12345678, 0x1234, 0x5678, 0x90, 0xab, &[0xcd, 0xef, 0x12, 0x34, 0x56, 0x78])
);
assert_ne!(binary_guid.as_fields(), TEST_GUID_FIELDS);
}
#[test]
fn binary_guid_deref_mut() {
let mut binary_guid =
BinaryGuid::from_fields(0x550e8400, 0xe29b, 0x41d4, 0xa7, 0x16, &[0x44, 0x66, 0x55, 0x44, 0x00, 0x00]);
*binary_guid =
efi::Guid::from_fields(0xAABBCCDD, 0x1122, 0x3344, 0x55, 0x66, &[0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC]);
assert_eq!(
binary_guid.as_fields(),
(0xAABBCCDD, 0x1122, 0x3344, 0x55, 0x66, &[0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC])
);
let fields = binary_guid.as_fields();
assert_eq!(fields.0, 0xAABBCCDD);
assert_eq!(fields.1, 0x1122);
assert_eq!(fields.2, 0x3344);
}
#[test]
fn test_to_and_from_guid() {
let guid = BinaryGuid::from_string(TEST_GUID_STRING);
let guid_string = guid.to_string();
let guid_from_other_string = BinaryGuid::from_string(&guid_string);
assert_eq!(guid, guid_from_other_string);
let guid_string2 = guid.to_canonical_string().iter().collect::<String>();
let guid_from_other_string2 = BinaryGuid::from_string(&guid_string2);
assert_eq!(*guid, *guid_from_other_string2);
}
}