1818//! non-reproducible sources (e.g. `OsRng`) need not bother with it.
1919
2020use crate :: RngCore ;
21- use core:: cmp:: min;
22- use zerocopy:: { Immutable , IntoBytes } ;
2321
2422/// Implement `next_u64` via `next_u32`, little-endian order.
2523pub fn next_u64_via_u32 < R : RngCore + ?Sized > ( rng : & mut R ) -> u64 {
@@ -53,17 +51,22 @@ pub fn fill_bytes_via_next<R: RngCore + ?Sized>(rng: &mut R, dest: &mut [u8]) {
5351 }
5452}
5553
56- trait Observable : IntoBytes + Immutable + Copy {
57- fn to_le ( self ) -> Self ;
54+ trait Observable : Copy {
55+ type Bytes : Sized + AsRef < [ u8 ] > ;
56+ fn to_le_bytes ( self ) -> Self :: Bytes ;
5857}
5958impl Observable for u32 {
60- fn to_le ( self ) -> Self {
61- self . to_le ( )
59+ type Bytes = [ u8 ; 4 ] ;
60+
61+ fn to_le_bytes ( self ) -> Self :: Bytes {
62+ Self :: to_le_bytes ( self )
6263 }
6364}
6465impl Observable for u64 {
65- fn to_le ( self ) -> Self {
66- self . to_le ( )
66+ type Bytes = [ u8 ; 8 ] ;
67+
68+ fn to_le_bytes ( self ) -> Self :: Bytes {
69+ Self :: to_le_bytes ( self )
6770 }
6871}
6972
@@ -72,32 +75,35 @@ impl Observable for u64 {
7275/// Returns `(n, byte_len)`. `src[..n]` is consumed (and possibly mutated),
7376/// `dest[..byte_len]` is filled. `src[n..]` and `dest[byte_len..]` are left
7477/// unaltered.
75- fn fill_via_chunks < T : Observable > ( src : & mut [ T ] , dest : & mut [ u8 ] ) -> ( usize , usize ) {
78+ fn fill_via_chunks < T : Observable > ( src : & [ T ] , dest : & mut [ u8 ] ) -> ( usize , usize ) {
7679 let size = core:: mem:: size_of :: < T > ( ) ;
77- let byte_len = min ( core:: mem:: size_of_val ( src) , dest. len ( ) ) ;
78- let num_chunks = ( byte_len + size - 1 ) / size;
79-
80- // Byte-swap for portability of results. This must happen before copying
81- // since the size of dest is not guaranteed to be a multiple of T or to be
82- // sufficiently aligned.
83- if cfg ! ( target_endian = "big" ) {
84- for x in & mut src[ ..num_chunks] {
85- * x = x. to_le ( ) ;
86- }
87- }
8880
89- dest [ ..byte_len ] . copy_from_slice ( & < [ T ] > :: as_bytes ( & src [ ..num_chunks ] ) [ ..byte_len ] ) ;
81+ // Always use little endian for portability of results.
9082
91- ( num_chunks, byte_len)
83+ let mut dest = dest. chunks_exact_mut ( size) ;
84+ let mut src = src. iter ( ) ;
85+
86+ let zipped = dest. by_ref ( ) . zip ( src. by_ref ( ) ) ;
87+ let num_chunks = zipped. len ( ) ;
88+ zipped. for_each ( |( dest, src) | dest. copy_from_slice ( src. to_le_bytes ( ) . as_ref ( ) ) ) ;
89+
90+ let byte_len = num_chunks * size;
91+ if let ( dest_tail @ [ _, ..] , Some ( src) ) = ( dest. into_remainder ( ) , src. next ( ) ) {
92+ let n = dest_tail. len ( ) ;
93+ dest_tail. copy_from_slice ( & src. to_le_bytes ( ) . as_ref ( ) [ ..n] ) ;
94+ ( num_chunks + 1 , byte_len + n)
95+ } else {
96+ ( num_chunks, byte_len)
97+ }
9298}
9399
94100/// Implement `fill_bytes` by reading chunks from the output buffer of a block
95101/// based RNG.
96102///
97103/// The return values are `(consumed_u32, filled_u8)`.
98104///
99- /// On big-endian systems, endianness of `src[..consumed_u32]` values is
100- /// swapped. No other adjustments to `src` are made .
105+ /// `src` is not modified; it is taken as a `&mut` reference for backward
106+ /// compatibility with previous versions that did change it .
101107///
102108/// `filled_u8` is the number of filled bytes in `dest`, which may be less than
103109/// the length of `dest`.
@@ -125,6 +131,7 @@ fn fill_via_chunks<T: Observable>(src: &mut [T], dest: &mut [u8]) -> (usize, usi
125131/// }
126132/// ```
127133pub fn fill_via_u32_chunks ( src : & mut [ u32 ] , dest : & mut [ u8 ] ) -> ( usize , usize ) {
134+ // TODO(SemVer): src: `&[u32]` as we don't mutate it.
128135 fill_via_chunks ( src, dest)
129136}
130137
@@ -133,8 +140,8 @@ pub fn fill_via_u32_chunks(src: &mut [u32], dest: &mut [u8]) -> (usize, usize) {
133140///
134141/// The return values are `(consumed_u64, filled_u8)`.
135142///
136- /// On big-endian systems, endianness of `src[..consumed_u64]` values is
137- /// swapped. No other adjustments to `src` are made .
143+ /// `src` is not modified; it is taken as a `&mut` reference for backward
144+ /// compatibility with previous versions that did change it .
138145///
139146/// `filled_u8` is the number of filled bytes in `dest`, which may be less than
140147/// the length of `dest`.
@@ -143,6 +150,7 @@ pub fn fill_via_u32_chunks(src: &mut [u32], dest: &mut [u8]) -> (usize, usize) {
143150///
144151/// See `fill_via_u32_chunks` for an example.
145152pub fn fill_via_u64_chunks ( src : & mut [ u64 ] , dest : & mut [ u8 ] ) -> ( usize , usize ) {
153+ // TODO(SemVer): src: `&[u64]` as we don't mutate it.
146154 fill_via_chunks ( src, dest)
147155}
148156
0 commit comments