@@ -359,6 +359,9 @@ use core::{
359359 slice,
360360} ;
361361
362+ #[ cfg( feature = "std" ) ]
363+ use std:: io;
364+
362365use crate :: pointer:: invariant:: { self , BecauseExclusive } ;
363366
364367#[ cfg( any( feature = "alloc" , test) ) ]
@@ -3068,10 +3071,7 @@ pub unsafe trait FromZeros: TryFromBytes {
30683071 // "exposed" provenance, and thus Rust may have to assume that this
30693072 // may consume provenance from any pointer whose provenance has been
30703073 // exposed.
3071- #[ allow( fuzzy_provenance_casts) ]
3072- unsafe {
3073- NonNull :: new_unchecked ( dangling)
3074- }
3074+ unsafe { NonNull :: new_unchecked ( dangling) }
30753075 } ;
30763076
30773077 let ptr = Self :: raw_from_ptr_len ( ptr, count) ;
@@ -4495,6 +4495,48 @@ pub unsafe trait FromBytes: FromZeros {
44954495 Err ( CastError :: Validity ( i) ) => match i { } ,
44964496 }
44974497 }
4498+
4499+ /// Reads a copy of `self` from an `io::Read`.
4500+ ///
4501+ /// This is useful for interfacing with operating system byte sinks (files,
4502+ /// sockets, etc.).
4503+ ///
4504+ /// # Examples
4505+ ///
4506+ /// ```no_run
4507+ /// use zerocopy::{byteorder::big_endian::*, FromBytes};
4508+ /// use std::fs::File;
4509+ /// # use zerocopy_derive::*;
4510+ ///
4511+ /// #[derive(FromBytes)]
4512+ /// #[repr(C)]
4513+ /// struct BitmapFileHeader {
4514+ /// signature: [u8; 2],
4515+ /// size: U32,
4516+ /// reserved: U64,
4517+ /// offset: U64,
4518+ /// }
4519+ ///
4520+ /// let mut file = File::open("image.bin").unwrap();
4521+ /// let header = BitmapFileHeader::read_from_io(&mut file).unwrap();
4522+ /// ```
4523+ #[ cfg( feature = "std" ) ]
4524+ #[ inline( always) ]
4525+ fn read_from_io < R > ( mut src : R ) -> io:: Result < Self >
4526+ where
4527+ Self : Sized ,
4528+ R : io:: Read ,
4529+ {
4530+ let mut buf = MaybeUninit :: < Self > :: zeroed ( ) ;
4531+ let ptr = Ptr :: from_mut ( & mut buf) ;
4532+ // SAFETY: `buf` consists entirely of initialized, zeroed bytes.
4533+ let ptr = unsafe { ptr. assume_validity :: < invariant:: Initialized > ( ) } ;
4534+ let ptr = ptr. as_bytes :: < BecauseExclusive > ( ) ;
4535+ src. read_exact ( ptr. as_mut ( ) ) ?;
4536+ // SAFETY: `buf` entirely consists of initialized bytes, and `Self` is
4537+ // `FromBytes`.
4538+ Ok ( unsafe { buf. assume_init ( ) } )
4539+ }
44984540}
44994541
45004542/// Interprets the given affix of the given bytes as a `&Self`.
@@ -5081,6 +5123,55 @@ pub unsafe trait IntoBytes {
50815123 }
50825124 Ok ( ( ) )
50835125 }
5126+
5127+ /// Writes a copy of `self` to an `io::Write`.
5128+ ///
5129+ /// This is a shorthand for `dst.write_all(self.as_bytes())`, and is useful
5130+ /// for interfacing with operating system byte sinks (files, sockets, etc.).
5131+ ///
5132+ /// # Examples
5133+ ///
5134+ /// ```no_run
5135+ /// use zerocopy::{byteorder::big_endian::U16, FromBytes, IntoBytes};
5136+ /// use std::fs::File;
5137+ /// # use zerocopy_derive::*;
5138+ ///
5139+ /// #[derive(FromBytes, IntoBytes, Immutable, KnownLayout)]
5140+ /// #[repr(C, packed)]
5141+ /// struct GrayscaleImage {
5142+ /// height: U16,
5143+ /// width: U16,
5144+ /// pixels: [U16],
5145+ /// }
5146+ ///
5147+ /// let image = GrayscaleImage::ref_from_bytes(&[0, 0, 0, 0][..]).unwrap();
5148+ /// let mut file = File::create("image.bin").unwrap();
5149+ /// image.write_to_io(&mut file).unwrap();
5150+ /// ```
5151+ ///
5152+ /// If the write fails, `write_to_io` returns `Err` and a partial write may
5153+ /// have occured; e.g.:
5154+ ///
5155+ /// ```
5156+ /// # use zerocopy::IntoBytes;
5157+ ///
5158+ /// let src = u128::MAX;
5159+ /// let mut dst = [0u8; 2];
5160+ ///
5161+ /// let write_result = src.write_to_io(&mut dst[..]);
5162+ ///
5163+ /// assert!(write_result.is_err());
5164+ /// assert_eq!(dst, [255, 255]);
5165+ /// ```
5166+ #[ cfg( feature = "std" ) ]
5167+ #[ inline( always) ]
5168+ fn write_to_io < W > ( & self , mut dst : W ) -> io:: Result < ( ) >
5169+ where
5170+ Self : Immutable ,
5171+ W : io:: Write ,
5172+ {
5173+ dst. write_all ( self . as_bytes ( ) )
5174+ }
50845175}
50855176
50865177/// Analyzes whether a type is [`Unaligned`].
@@ -5795,6 +5886,20 @@ mod tests {
57955886 assert_eq ! ( bytes, want) ;
57965887 }
57975888
5889+ #[ test]
5890+ #[ cfg( feature = "std" ) ]
5891+ fn test_read_write_io ( ) {
5892+ let mut long_buffer = [ 0 , 0 , 0 , 0 ] ;
5893+ assert ! ( matches!( u16 :: MAX . write_to_io( & mut long_buffer[ ..] ) , Ok ( ( ) ) ) ) ;
5894+ assert_eq ! ( long_buffer, [ 255 , 255 , 0 , 0 ] ) ;
5895+ assert ! ( matches!( u16 :: read_from_io( & long_buffer[ ..] ) , Ok ( u16 :: MAX ) ) ) ;
5896+
5897+ let mut short_buffer = [ 0 , 0 ] ;
5898+ assert ! ( u32 :: MAX . write_to_io( & mut short_buffer[ ..] ) . is_err( ) ) ;
5899+ assert_eq ! ( short_buffer, [ 255 , 255 ] ) ;
5900+ assert ! ( u32 :: read_from_io( & short_buffer[ ..] ) . is_err( ) ) ;
5901+ }
5902+
57985903 #[ test]
57995904 fn test_try_from_bytes_try_read_from ( ) {
58005905 assert_eq ! ( <bool as TryFromBytes >:: try_read_from_bytes( & [ 0 ] ) , Ok ( false ) ) ;
0 commit comments