18
18
//! non-reproducible sources (e.g. `OsRng`) need not bother with it.
19
19
20
20
use crate :: RngCore ;
21
- use core:: cmp:: min;
22
- use zerocopy:: { Immutable , IntoBytes } ;
23
21
24
22
/// Implement `next_u64` via `next_u32`, little-endian order.
25
23
pub 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]) {
53
51
}
54
52
}
55
53
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 ;
58
57
}
59
58
impl 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 )
62
63
}
63
64
}
64
65
impl 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 )
67
70
}
68
71
}
69
72
@@ -72,32 +75,35 @@ impl Observable for u64 {
72
75
/// Returns `(n, byte_len)`. `src[..n]` is consumed (and possibly mutated),
73
76
/// `dest[..byte_len]` is filled. `src[n..]` and `dest[byte_len..]` are left
74
77
/// 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 ) {
76
79
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
- }
88
80
89
- dest [ ..byte_len ] . copy_from_slice ( & < [ T ] > :: as_bytes ( & src [ ..num_chunks ] ) [ ..byte_len ] ) ;
81
+ // Always use little endian for portability of results.
90
82
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
+ }
92
98
}
93
99
94
100
/// Implement `fill_bytes` by reading chunks from the output buffer of a block
95
101
/// based RNG.
96
102
///
97
103
/// The return values are `(consumed_u32, filled_u8)`.
98
104
///
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 .
101
107
///
102
108
/// `filled_u8` is the number of filled bytes in `dest`, which may be less than
103
109
/// the length of `dest`.
@@ -125,6 +131,7 @@ fn fill_via_chunks<T: Observable>(src: &mut [T], dest: &mut [u8]) -> (usize, usi
125
131
/// }
126
132
/// ```
127
133
pub fn fill_via_u32_chunks ( src : & mut [ u32 ] , dest : & mut [ u8 ] ) -> ( usize , usize ) {
134
+ // TODO(SemVer): src: `&[u32]` as we don't mutate it.
128
135
fill_via_chunks ( src, dest)
129
136
}
130
137
@@ -133,8 +140,8 @@ pub fn fill_via_u32_chunks(src: &mut [u32], dest: &mut [u8]) -> (usize, usize) {
133
140
///
134
141
/// The return values are `(consumed_u64, filled_u8)`.
135
142
///
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 .
138
145
///
139
146
/// `filled_u8` is the number of filled bytes in `dest`, which may be less than
140
147
/// the length of `dest`.
@@ -143,6 +150,7 @@ pub fn fill_via_u32_chunks(src: &mut [u32], dest: &mut [u8]) -> (usize, usize) {
143
150
///
144
151
/// See `fill_via_u32_chunks` for an example.
145
152
pub fn fill_via_u64_chunks ( src : & mut [ u64 ] , dest : & mut [ u8 ] ) -> ( usize , usize ) {
153
+ // TODO(SemVer): src: `&[u64]` as we don't mutate it.
146
154
fill_via_chunks ( src, dest)
147
155
}
148
156
0 commit comments