@@ -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:: { self , BecauseExclusive } ;
363
366
364
367
#[ cfg( any( feature = "alloc" , test) ) ]
@@ -3068,10 +3071,7 @@ pub unsafe trait FromZeros: TryFromBytes {
3068
3071
// "exposed" provenance, and thus Rust may have to assume that this
3069
3072
// may consume provenance from any pointer whose provenance has been
3070
3073
// exposed.
3071
- #[ allow( fuzzy_provenance_casts) ]
3072
- unsafe {
3073
- NonNull :: new_unchecked ( dangling)
3074
- }
3074
+ unsafe { NonNull :: new_unchecked ( dangling) }
3075
3075
} ;
3076
3076
3077
3077
let ptr = Self :: raw_from_ptr_len ( ptr, count) ;
@@ -4495,6 +4495,48 @@ pub unsafe trait FromBytes: FromZeros {
4495
4495
Err ( CastError :: Validity ( i) ) => match i { } ,
4496
4496
}
4497
4497
}
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
+ }
4498
4540
}
4499
4541
4500
4542
/// Interprets the given affix of the given bytes as a `&Self`.
@@ -5081,6 +5123,55 @@ pub unsafe trait IntoBytes {
5081
5123
}
5082
5124
Ok ( ( ) )
5083
5125
}
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
+ }
5084
5175
}
5085
5176
5086
5177
/// Analyzes whether a type is [`Unaligned`].
@@ -5795,6 +5886,20 @@ mod tests {
5795
5886
assert_eq ! ( bytes, want) ;
5796
5887
}
5797
5888
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
+
5798
5903
#[ test]
5799
5904
fn test_try_from_bytes_try_read_from ( ) {
5800
5905
assert_eq ! ( <bool as TryFromBytes >:: try_read_from_bytes( & [ 0 ] ) , Ok ( false ) ) ;
0 commit comments