@@ -359,6 +359,9 @@ use core::{
359
359
slice,
360
360
} ;
361
361
362
+ #[ cfg( feature = "std" ) ]
363
+ use std:: io;
364
+
362
365
use crate :: pointer:: { invariant, BecauseExclusive } ;
363
366
364
367
#[ cfg( any( feature = "alloc" , test) ) ]
@@ -3083,10 +3086,7 @@ pub unsafe trait FromZeros: TryFromBytes {
3083
3086
// "exposed" provenance, and thus Rust may have to assume that this
3084
3087
// may consume provenance from any pointer whose provenance has been
3085
3088
// exposed.
3086
- #[ allow( fuzzy_provenance_casts) ]
3087
- unsafe {
3088
- NonNull :: new_unchecked ( dangling)
3089
- }
3089
+ unsafe { NonNull :: new_unchecked ( dangling) }
3090
3090
} ;
3091
3091
3092
3092
let ptr = Self :: raw_from_ptr_len ( ptr, count) ;
@@ -4526,6 +4526,48 @@ pub unsafe trait FromBytes: FromZeros {
4526
4526
}
4527
4527
}
4528
4528
4529
+ /// Reads a copy of `self` from an `io::Read`.
4530
+ ///
4531
+ /// This is useful for interfacing with operating system byte sinks (files,
4532
+ /// sockets, etc.).
4533
+ ///
4534
+ /// # Examples
4535
+ ///
4536
+ /// ```no_run
4537
+ /// use zerocopy::{byteorder::big_endian::*, FromBytes};
4538
+ /// use std::fs::File;
4539
+ /// # use zerocopy_derive::*;
4540
+ ///
4541
+ /// #[derive(FromBytes)]
4542
+ /// #[repr(C)]
4543
+ /// struct BitmapFileHeader {
4544
+ /// signature: [u8; 2],
4545
+ /// size: U32,
4546
+ /// reserved: U64,
4547
+ /// offset: U64,
4548
+ /// }
4549
+ ///
4550
+ /// let mut file = File::open("image.bin").unwrap();
4551
+ /// let header = BitmapFileHeader::read_from_io(&mut file).unwrap();
4552
+ /// ```
4553
+ #[ cfg( feature = "std" ) ]
4554
+ #[ inline( always) ]
4555
+ fn read_from_io < R > ( mut src : R ) -> io:: Result < Self >
4556
+ where
4557
+ Self : Sized ,
4558
+ R : io:: Read ,
4559
+ {
4560
+ let mut buf = MaybeUninit :: < Self > :: zeroed ( ) ;
4561
+ let ptr = Ptr :: from_mut ( & mut buf) ;
4562
+ // SAFETY: `buf` consists entirely of initialized, zeroed bytes.
4563
+ let ptr = unsafe { ptr. assume_validity :: < invariant:: Initialized > ( ) } ;
4564
+ let ptr = ptr. as_bytes :: < BecauseExclusive > ( ) ;
4565
+ src. read_exact ( ptr. as_mut ( ) ) ?;
4566
+ // SAFETY: `buf` entirely consists of initialized bytes, and `Self` is
4567
+ // `FromBytes`.
4568
+ Ok ( unsafe { buf. assume_init ( ) } )
4569
+ }
4570
+
4529
4571
#[ deprecated( since = "0.8.0" , note = "renamed to `FromBytes::ref_from_bytes`" ) ]
4530
4572
#[ doc( hidden) ]
4531
4573
#[ must_use = "has no side effects" ]
@@ -5189,6 +5231,55 @@ pub unsafe trait IntoBytes {
5189
5231
Ok ( ( ) )
5190
5232
}
5191
5233
5234
+ /// Writes a copy of `self` to an `io::Write`.
5235
+ ///
5236
+ /// This is a shorthand for `dst.write_all(self.as_bytes())`, and is useful
5237
+ /// for interfacing with operating system byte sinks (files, sockets, etc.).
5238
+ ///
5239
+ /// # Examples
5240
+ ///
5241
+ /// ```no_run
5242
+ /// use zerocopy::{byteorder::big_endian::U16, FromBytes, IntoBytes};
5243
+ /// use std::fs::File;
5244
+ /// # use zerocopy_derive::*;
5245
+ ///
5246
+ /// #[derive(FromBytes, IntoBytes, Immutable, KnownLayout)]
5247
+ /// #[repr(C, packed)]
5248
+ /// struct GrayscaleImage {
5249
+ /// height: U16,
5250
+ /// width: U16,
5251
+ /// pixels: [U16],
5252
+ /// }
5253
+ ///
5254
+ /// let image = GrayscaleImage::ref_from_bytes(&[0, 0, 0, 0][..]).unwrap();
5255
+ /// let mut file = File::create("image.bin").unwrap();
5256
+ /// image.write_to_io(&mut file).unwrap();
5257
+ /// ```
5258
+ ///
5259
+ /// If the write fails, `write_to_io` returns `Err` and a partial write may
5260
+ /// have occured; e.g.:
5261
+ ///
5262
+ /// ```
5263
+ /// # use zerocopy::IntoBytes;
5264
+ ///
5265
+ /// let src = u128::MAX;
5266
+ /// let mut dst = [0u8; 2];
5267
+ ///
5268
+ /// let write_result = src.write_to_io(&mut dst[..]);
5269
+ ///
5270
+ /// assert!(write_result.is_err());
5271
+ /// assert_eq!(dst, [255, 255]);
5272
+ /// ```
5273
+ #[ cfg( feature = "std" ) ]
5274
+ #[ inline( always) ]
5275
+ fn write_to_io < W > ( & self , mut dst : W ) -> io:: Result < ( ) >
5276
+ where
5277
+ Self : Immutable ,
5278
+ W : io:: Write ,
5279
+ {
5280
+ dst. write_all ( self . as_bytes ( ) )
5281
+ }
5282
+
5192
5283
#[ deprecated( since = "0.8.0" , note = "`IntoBytes::as_bytes_mut` was renamed to `as_mut_bytes`" ) ]
5193
5284
#[ doc( hidden) ]
5194
5285
#[ inline]
@@ -5951,6 +6042,20 @@ mod tests {
5951
6042
assert_eq ! ( bytes, want) ;
5952
6043
}
5953
6044
6045
+ #[ test]
6046
+ #[ cfg( feature = "std" ) ]
6047
+ fn test_read_write_io ( ) {
6048
+ let mut long_buffer = [ 0 , 0 , 0 , 0 ] ;
6049
+ assert ! ( matches!( u16 :: MAX . write_to_io( & mut long_buffer[ ..] ) , Ok ( ( ) ) ) ) ;
6050
+ assert_eq ! ( long_buffer, [ 255 , 255 , 0 , 0 ] ) ;
6051
+ assert ! ( matches!( u16 :: read_from_io( & long_buffer[ ..] ) , Ok ( u16 :: MAX ) ) ) ;
6052
+
6053
+ let mut short_buffer = [ 0 , 0 ] ;
6054
+ assert ! ( u32 :: MAX . write_to_io( & mut short_buffer[ ..] ) . is_err( ) ) ;
6055
+ assert_eq ! ( short_buffer, [ 255 , 255 ] ) ;
6056
+ assert ! ( u32 :: read_from_io( & short_buffer[ ..] ) . is_err( ) ) ;
6057
+ }
6058
+
5954
6059
#[ test]
5955
6060
fn test_try_from_bytes_try_read_from ( ) {
5956
6061
assert_eq ! ( <bool as TryFromBytes >:: try_read_from_bytes( & [ 0 ] ) , Ok ( false ) ) ;
0 commit comments