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,41 +51,52 @@ 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
+ pub ( crate ) 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
70
73
/// Fill dest from src
71
74
///
72
- /// Returns `(n, byte_len)`. `src[..n]` is consumed (and possibly mutated) ,
75
+ /// Returns `(n, byte_len)`. `src[..n]` is consumed,
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
+ pub ( crate ) 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
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 Some ( src) = src. next ( ) {
92
+ // We have consumed all full chunks of dest, but not src.
93
+ let dest = dest. into_remainder ( ) ;
94
+ let n = dest. len ( ) ;
95
+ if n > 0 {
96
+ dest. copy_from_slice ( & src. to_le_bytes ( ) . as_ref ( ) [ ..n] ) ;
97
+ return ( num_chunks + 1 , byte_len + n) ;
98
+ }
99
+ }
91
100
( num_chunks, byte_len)
92
101
}
93
102
@@ -96,8 +105,8 @@ fn fill_via_chunks<T: Observable>(src: &mut [T], dest: &mut [u8]) -> (usize, usi
96
105
///
97
106
/// The return values are `(consumed_u32, filled_u8)`.
98
107
///
99
- /// On big-endian systems, endianness of `src[..consumed_u32]` values is
100
- /// swapped. No other adjustments to `src` are made .
108
+ /// `src` is not modified; it is taken as a `&mut` reference for backward
109
+ /// compatibility with previous versions that did change it .
101
110
///
102
111
/// `filled_u8` is the number of filled bytes in `dest`, which may be less than
103
112
/// the length of `dest`.
@@ -124,6 +133,7 @@ fn fill_via_chunks<T: Observable>(src: &mut [T], dest: &mut [u8]) -> (usize, usi
124
133
/// }
125
134
/// }
126
135
/// ```
136
+ #[ deprecated( since = "0.9.3" , note = "use BlockRng instead" ) ]
127
137
pub fn fill_via_u32_chunks ( src : & mut [ u32 ] , dest : & mut [ u8 ] ) -> ( usize , usize ) {
128
138
fill_via_chunks ( src, dest)
129
139
}
@@ -133,15 +143,16 @@ pub fn fill_via_u32_chunks(src: &mut [u32], dest: &mut [u8]) -> (usize, usize) {
133
143
///
134
144
/// The return values are `(consumed_u64, filled_u8)`.
135
145
///
136
- /// On big-endian systems, endianness of `src[..consumed_u64]` values is
137
- /// swapped. No other adjustments to `src` are made .
146
+ /// `src` is not modified; it is taken as a `&mut` reference for backward
147
+ /// compatibility with previous versions that did change it .
138
148
///
139
149
/// `filled_u8` is the number of filled bytes in `dest`, which may be less than
140
150
/// the length of `dest`.
141
151
/// `consumed_u64` is the number of words consumed from `src`, which is the same
142
152
/// as `filled_u8 / 8` rounded up.
143
153
///
144
154
/// See `fill_via_u32_chunks` for an example.
155
+ #[ deprecated( since = "0.9.3" , note = "use BlockRng64 instead" ) ]
145
156
pub fn fill_via_u64_chunks ( src : & mut [ u64 ] , dest : & mut [ u8 ] ) -> ( usize , usize ) {
146
157
fill_via_chunks ( src, dest)
147
158
}
@@ -166,41 +177,41 @@ mod test {
166
177
167
178
#[ test]
168
179
fn test_fill_via_u32_chunks ( ) {
169
- let src_orig = [ 1 , 2 , 3 ] ;
180
+ let src_orig = [ 1u32 , 2 , 3 ] ;
170
181
171
182
let mut src = src_orig;
172
183
let mut dst = [ 0u8 ; 11 ] ;
173
- assert_eq ! ( fill_via_u32_chunks ( & mut src, & mut dst) , ( 3 , 11 ) ) ;
184
+ assert_eq ! ( fill_via_chunks ( & mut src, & mut dst) , ( 3 , 11 ) ) ;
174
185
assert_eq ! ( dst, [ 1 , 0 , 0 , 0 , 2 , 0 , 0 , 0 , 3 , 0 , 0 ] ) ;
175
186
176
187
let mut src = src_orig;
177
188
let mut dst = [ 0u8 ; 13 ] ;
178
- assert_eq ! ( fill_via_u32_chunks ( & mut src, & mut dst) , ( 3 , 12 ) ) ;
189
+ assert_eq ! ( fill_via_chunks ( & mut src, & mut dst) , ( 3 , 12 ) ) ;
179
190
assert_eq ! ( dst, [ 1 , 0 , 0 , 0 , 2 , 0 , 0 , 0 , 3 , 0 , 0 , 0 , 0 ] ) ;
180
191
181
192
let mut src = src_orig;
182
193
let mut dst = [ 0u8 ; 5 ] ;
183
- assert_eq ! ( fill_via_u32_chunks ( & mut src, & mut dst) , ( 2 , 5 ) ) ;
194
+ assert_eq ! ( fill_via_chunks ( & mut src, & mut dst) , ( 2 , 5 ) ) ;
184
195
assert_eq ! ( dst, [ 1 , 0 , 0 , 0 , 2 ] ) ;
185
196
}
186
197
187
198
#[ test]
188
199
fn test_fill_via_u64_chunks ( ) {
189
- let src_orig = [ 1 , 2 ] ;
200
+ let src_orig = [ 1u64 , 2 ] ;
190
201
191
202
let mut src = src_orig;
192
203
let mut dst = [ 0u8 ; 11 ] ;
193
- assert_eq ! ( fill_via_u64_chunks ( & mut src, & mut dst) , ( 2 , 11 ) ) ;
204
+ assert_eq ! ( fill_via_chunks ( & mut src, & mut dst) , ( 2 , 11 ) ) ;
194
205
assert_eq ! ( dst, [ 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 2 , 0 , 0 ] ) ;
195
206
196
207
let mut src = src_orig;
197
208
let mut dst = [ 0u8 ; 17 ] ;
198
- assert_eq ! ( fill_via_u64_chunks ( & mut src, & mut dst) , ( 2 , 16 ) ) ;
209
+ assert_eq ! ( fill_via_chunks ( & mut src, & mut dst) , ( 2 , 16 ) ) ;
199
210
assert_eq ! ( dst, [ 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] ) ;
200
211
201
212
let mut src = src_orig;
202
213
let mut dst = [ 0u8 ; 5 ] ;
203
- assert_eq ! ( fill_via_u64_chunks ( & mut src, & mut dst) , ( 1 , 5 ) ) ;
214
+ assert_eq ! ( fill_via_chunks ( & mut src, & mut dst) , ( 1 , 5 ) ) ;
204
215
assert_eq ! ( dst, [ 1 , 0 , 0 , 0 , 0 ] ) ;
205
216
}
206
217
}
0 commit comments