Skip to content

Commit 5f59b8a

Browse files
committed
uefi-raw
1 parent 5a30e29 commit 5f59b8a

File tree

1 file changed

+70
-13
lines changed

1 file changed

+70
-13
lines changed

uefi-raw/src/lib.rs

+70-13
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,9 @@ impl From<Boolean> for bool {
113113
/// type is defined in the same way as edk2 for compatibility with C code. Note
114114
/// that this is an **untagged union**, so there's no way to tell which type of
115115
/// address an `IpAddress` value contains without additional context.
116+
///
117+
/// For convenience, this type is tightly integrated with the Rust standard
118+
/// library types [`IpAddr`], [`Ipv4Addr`], and [`IpV6Addr`].
116119
#[derive(Clone, Copy)]
117120
#[repr(C)]
118121
pub union IpAddress {
@@ -162,14 +165,48 @@ impl IpAddress {
162165
pub fn as_ptr_mut(&mut self) -> *mut Self {
163166
core::ptr::addr_of_mut!(*self)
164167
}
168+
169+
/// Transforms this EFI type to the Rust standard libraries type.
170+
///
171+
/// # Arguments
172+
/// - `is_ipv6`: Whether the internal data should be interpreted as IPv6 or
173+
/// IPv4 address.
174+
pub fn to_ip_addr(self, is_ipv6: bool) -> IpAddr {
175+
if is_ipv6 {
176+
IpAddr::V6(Ipv6Addr::from(unsafe { self.v6.octets() }))
177+
} else {
178+
IpAddr::V4(Ipv4Addr::from(unsafe { self.v4.octets() }))
179+
}
180+
}
181+
182+
/// Returns the underlying data as [`Ipv4Addr`], if only the first four
183+
/// octets are used.
184+
///
185+
/// # Safety
186+
/// This function is not unsafe memory-wise but callers need to ensure with
187+
/// additional context that the IP is indeed an IPv4 address.
188+
pub unsafe fn as_ipv4(&self) -> Result<Ipv4Addr, Ipv6Addr> {
189+
let extra = self.octets()[4..].iter().any(|&x| x != 0);
190+
if extra {
191+
Ok(Ipv4Addr::from(unsafe { self.v4.octets() }))
192+
} else {
193+
Err(Ipv6Addr::from(unsafe { self.v6.octets() }))
194+
}
195+
}
196+
197+
/// Returns the underlying data as [`Ipv6Addr`].
198+
///
199+
/// # Safety
200+
/// This function is not unsafe memory-wise but callers need to ensure with
201+
/// additional context that the IP is indeed an IPv6 address.
202+
pub unsafe fn as_ipv6(&self) -> Ipv6Addr {
203+
Ipv6Addr::from(unsafe { self.v6.octets() })
204+
}
165205
}
166206

167207
impl Debug for IpAddress {
168208
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
169-
// The type is an untagged union, so we don't know whether it contains
170-
// an IPv4 or IPv6 address. It's also not safe to just print the whole
171-
// 16 bytes, since they might not all be initialized.
172-
f.debug_struct("IpAddress").finish()
209+
f.debug_tuple("IpAddress").field(&self.octets()).finish()
173210
}
174211
}
175212

@@ -207,6 +244,14 @@ impl From<&IpAddr> for IpAddress {
207244
}
208245
}
209246

247+
impl From<[u8; 4]> for IpAddress {
248+
fn from(value: [u8; 4]) -> Self {
249+
Self {
250+
v4: Ipv4Addr::from(value),
251+
}
252+
}
253+
}
254+
210255
impl From<[u8; 16]> for IpAddress {
211256
fn from(value: [u8; 16]) -> Self {
212257
Self {
@@ -299,17 +344,29 @@ mod tests {
299344
unsafe { assert_eq!(ip.v4.octets(), [192, 168, 42, 73]) }
300345
}
301346

302-
/// Test conversion from `core::net::IpAddr` to `IpvAddress`.
303-
///
304-
/// Note that conversion in the other direction is not possible.
347+
/// Test conversion from [`IpAddr`] to [`IpAddress`].
305348
#[test]
306349
fn test_ip_addr_conversion() {
307-
let core_addr = IpAddr::V4(Ipv4Addr::from(TEST_IPV4));
308-
let uefi_addr = IpAddress::from(core_addr);
309-
assert_eq!(unsafe { uefi_addr.v4.octets() }, TEST_IPV4);
350+
// Reference: std types
351+
let core_ipv4 = IpAddr::from(TEST_IPV4);
352+
let core_ipv6 = IpAddr::from(TEST_IPV6);
353+
354+
// Test From [u8; N] constructors
355+
assert_eq!(IpAddress::from(TEST_IPV4).octets()[0..4], TEST_IPV4);
356+
assert_eq!(IpAddress::from(TEST_IPV6).octets(), TEST_IPV6);
357+
{
358+
let bytes: [u8; 16] = IpAddress::from(TEST_IPV6).into();
359+
assert_eq!(bytes, TEST_IPV6);
360+
}
361+
362+
// Test from std type constructors
363+
let efi_ipv4 = IpAddress::from(core_ipv4);
364+
assert_eq!(efi_ipv4.octets()[0..4], TEST_IPV4);
365+
assert_eq!(unsafe { efi_ipv4.as_ipv4().unwrap() }, core_ipv4);
310366

311-
let core_addr = IpAddr::V6(Ipv6Addr::from(TEST_IPV6));
312-
let uefi_addr = IpAddress::from(core_addr);
313-
assert_eq!(unsafe { uefi_addr.v6.octets() }, TEST_IPV6);
367+
let efi_ipv6 = IpAddress::from(core_ipv6);
368+
assert_eq!(efi_ipv6.octets(), TEST_IPV6);
369+
assert_eq!(unsafe { efi_ipv4.as_ipv4().unwrap_err() }, core_ipv6);
370+
assert_eq!(unsafe { efi_ipv4.as_ipv6() }, core_ipv6);
314371
}
315372
}

0 commit comments

Comments
 (0)