@@ -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 ) ]
118121pub 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
167207impl 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+
210255impl 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