@@ -113,6 +113,9 @@ impl From<Boolean> for bool {
113
113
/// type is defined in the same way as edk2 for compatibility with C code. Note
114
114
/// that this is an **untagged union**, so there's no way to tell which type of
115
115
/// 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`].
116
119
#[ derive( Clone , Copy ) ]
117
120
#[ repr( C ) ]
118
121
pub union IpAddress {
@@ -162,14 +165,48 @@ impl IpAddress {
162
165
pub fn as_ptr_mut ( & mut self ) -> * mut Self {
163
166
core:: ptr:: addr_of_mut!( * self )
164
167
}
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
+ }
165
205
}
166
206
167
207
impl Debug for IpAddress {
168
208
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 ( )
173
210
}
174
211
}
175
212
@@ -207,6 +244,14 @@ impl From<&IpAddr> for IpAddress {
207
244
}
208
245
}
209
246
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
+
210
255
impl From < [ u8 ; 16 ] > for IpAddress {
211
256
fn from ( value : [ u8 ; 16 ] ) -> Self {
212
257
Self {
@@ -299,17 +344,29 @@ mod tests {
299
344
unsafe { assert_eq ! ( ip. v4. octets( ) , [ 192 , 168 , 42 , 73 ] ) }
300
345
}
301
346
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`].
305
348
#[ test]
306
349
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) ;
310
366
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) ;
314
371
}
315
372
}
0 commit comments