@@ -53,16 +53,14 @@ pub fn fill_bytes_via_next<R: RngCore + ?Sized>(rng: &mut R, dest: &mut [u8]) {
53
53
}
54
54
55
55
trait Observable : Copy {
56
- type Bytes : AsRef < [ u8 ] > ;
57
- fn to_le_bytes ( self ) -> Self :: Bytes ;
56
+ fn to_le ( self ) -> Self ;
58
57
59
58
// Contract: observing self is memory-safe (implies no uninitialised padding)
60
59
fn as_byte_slice ( x : & [ Self ] ) -> & [ u8 ] ;
61
60
}
62
61
impl Observable for u32 {
63
- type Bytes = [ u8 ; 4 ] ;
64
- fn to_le_bytes ( self ) -> Self :: Bytes {
65
- self . to_le_bytes ( )
62
+ fn to_le ( self ) -> Self {
63
+ self . to_le ( )
66
64
}
67
65
fn as_byte_slice ( x : & [ Self ] ) -> & [ u8 ] {
68
66
let ptr = x. as_ptr ( ) as * const u8 ;
@@ -71,9 +69,8 @@ impl Observable for u32 {
71
69
}
72
70
}
73
71
impl Observable for u64 {
74
- type Bytes = [ u8 ; 8 ] ;
75
- fn to_le_bytes ( self ) -> Self :: Bytes {
76
- self . to_le_bytes ( )
72
+ fn to_le ( self ) -> Self {
73
+ self . to_le ( )
77
74
}
78
75
fn as_byte_slice ( x : & [ Self ] ) -> & [ u8 ] {
79
76
let ptr = x. as_ptr ( ) as * const u8 ;
@@ -82,28 +79,27 @@ impl Observable for u64 {
82
79
}
83
80
}
84
81
85
- fn fill_via_chunks < T : Observable > ( src : & [ T ] , dest : & mut [ u8 ] ) -> ( usize , usize ) {
82
+ /// Fill dest from src
83
+ ///
84
+ /// Returns `(n, byte_len)`. `src[..n]` is consumed (and possibly mutated),
85
+ /// `dest[..byte_len]` is filled. `src[n..]` and `dest[byte_len..]` are left
86
+ /// unaltered.
87
+ fn fill_via_chunks < T : Observable > ( src : & mut [ T ] , dest : & mut [ u8 ] ) -> ( usize , usize ) {
86
88
let size = core:: mem:: size_of :: < T > ( ) ;
87
89
let byte_len = min ( src. len ( ) * size, dest. len ( ) ) ;
88
90
let num_chunks = ( byte_len + size - 1 ) / size;
89
91
90
- if cfg ! ( target_endian = "little" ) {
91
- // On LE we can do a simple copy, which is 25-50% faster:
92
- dest[ ..byte_len] . copy_from_slice ( & T :: as_byte_slice ( & src[ ..num_chunks] ) [ ..byte_len] ) ;
93
- } else {
94
- // This code is valid on all arches, but slower than the above:
95
- let mut i = 0 ;
96
- let mut iter = dest[ ..byte_len] . chunks_exact_mut ( size) ;
97
- for chunk in & mut iter {
98
- chunk. copy_from_slice ( src[ i] . to_le_bytes ( ) . as_ref ( ) ) ;
99
- i += 1 ;
100
- }
101
- let chunk = iter. into_remainder ( ) ;
102
- if !chunk. is_empty ( ) {
103
- chunk. copy_from_slice ( & src[ i] . to_le_bytes ( ) . as_ref ( ) [ ..chunk. len ( ) ] ) ;
92
+ // Byte-swap for portability of results. This must happen before copying
93
+ // since the size of dest is not guaranteed to be a multiple of T or to be
94
+ // sufficiently aligned.
95
+ if cfg ! ( target_endian = "big" ) {
96
+ for x in & mut src[ ..num_chunks] {
97
+ * x = x. to_le ( ) ;
104
98
}
105
99
}
106
100
101
+ dest[ ..byte_len] . copy_from_slice ( & T :: as_byte_slice ( & src[ ..num_chunks] ) [ ..byte_len] ) ;
102
+
107
103
( num_chunks, byte_len)
108
104
}
109
105
@@ -112,6 +108,9 @@ fn fill_via_chunks<T: Observable>(src: &[T], dest: &mut [u8]) -> (usize, usize)
112
108
///
113
109
/// The return values are `(consumed_u32, filled_u8)`.
114
110
///
111
+ /// On big-endian systems, endianness of `src[..consumed_u32]` values is
112
+ /// swapped. No other adjustments to `src` are made.
113
+ ///
115
114
/// `filled_u8` is the number of filled bytes in `dest`, which may be less than
116
115
/// the length of `dest`.
117
116
/// `consumed_u32` is the number of words consumed from `src`, which is the same
@@ -137,21 +136,25 @@ fn fill_via_chunks<T: Observable>(src: &[T], dest: &mut [u8]) -> (usize, usize)
137
136
/// }
138
137
/// }
139
138
/// ```
140
- pub fn fill_via_u32_chunks ( src : & [ u32 ] , dest : & mut [ u8 ] ) -> ( usize , usize ) {
139
+ pub fn fill_via_u32_chunks ( src : & mut [ u32 ] , dest : & mut [ u8 ] ) -> ( usize , usize ) {
141
140
fill_via_chunks ( src, dest)
142
141
}
143
142
144
143
/// Implement `fill_bytes` by reading chunks from the output buffer of a block
145
144
/// based RNG.
146
145
///
147
146
/// The return values are `(consumed_u64, filled_u8)`.
147
+ ///
148
+ /// On big-endian systems, endianness of `src[..consumed_u64]` values is
149
+ /// swapped. No other adjustments to `src` are made.
150
+ ///
148
151
/// `filled_u8` is the number of filled bytes in `dest`, which may be less than
149
152
/// the length of `dest`.
150
153
/// `consumed_u64` is the number of words consumed from `src`, which is the same
151
154
/// as `filled_u8 / 8` rounded up.
152
155
///
153
156
/// See `fill_via_u32_chunks` for an example.
154
- pub fn fill_via_u64_chunks ( src : & [ u64 ] , dest : & mut [ u8 ] ) -> ( usize , usize ) {
157
+ pub fn fill_via_u64_chunks ( src : & mut [ u64 ] , dest : & mut [ u8 ] ) -> ( usize , usize ) {
155
158
fill_via_chunks ( src, dest)
156
159
}
157
160
@@ -175,33 +178,41 @@ mod test {
175
178
176
179
#[ test]
177
180
fn test_fill_via_u32_chunks ( ) {
178
- let src = [ 1 , 2 , 3 ] ;
181
+ let src_orig = [ 1 , 2 , 3 ] ;
182
+
183
+ let mut src = src_orig;
179
184
let mut dst = [ 0u8 ; 11 ] ;
180
- assert_eq ! ( fill_via_u32_chunks( & src, & mut dst) , ( 3 , 11 ) ) ;
185
+ assert_eq ! ( fill_via_u32_chunks( & mut src, & mut dst) , ( 3 , 11 ) ) ;
181
186
assert_eq ! ( dst, [ 1 , 0 , 0 , 0 , 2 , 0 , 0 , 0 , 3 , 0 , 0 ] ) ;
182
187
188
+ let mut src = src_orig;
183
189
let mut dst = [ 0u8 ; 13 ] ;
184
- assert_eq ! ( fill_via_u32_chunks( & src, & mut dst) , ( 3 , 12 ) ) ;
190
+ assert_eq ! ( fill_via_u32_chunks( & mut src, & mut dst) , ( 3 , 12 ) ) ;
185
191
assert_eq ! ( dst, [ 1 , 0 , 0 , 0 , 2 , 0 , 0 , 0 , 3 , 0 , 0 , 0 , 0 ] ) ;
186
192
193
+ let mut src = src_orig;
187
194
let mut dst = [ 0u8 ; 5 ] ;
188
- assert_eq ! ( fill_via_u32_chunks( & src, & mut dst) , ( 2 , 5 ) ) ;
195
+ assert_eq ! ( fill_via_u32_chunks( & mut src, & mut dst) , ( 2 , 5 ) ) ;
189
196
assert_eq ! ( dst, [ 1 , 0 , 0 , 0 , 2 ] ) ;
190
197
}
191
198
192
199
#[ test]
193
200
fn test_fill_via_u64_chunks ( ) {
194
- let src = [ 1 , 2 ] ;
201
+ let src_orig = [ 1 , 2 ] ;
202
+
203
+ let mut src = src_orig;
195
204
let mut dst = [ 0u8 ; 11 ] ;
196
- assert_eq ! ( fill_via_u64_chunks( & src, & mut dst) , ( 2 , 11 ) ) ;
205
+ assert_eq ! ( fill_via_u64_chunks( & mut src, & mut dst) , ( 2 , 11 ) ) ;
197
206
assert_eq ! ( dst, [ 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 2 , 0 , 0 ] ) ;
198
207
208
+ let mut src = src_orig;
199
209
let mut dst = [ 0u8 ; 17 ] ;
200
- assert_eq ! ( fill_via_u64_chunks( & src, & mut dst) , ( 2 , 16 ) ) ;
210
+ assert_eq ! ( fill_via_u64_chunks( & mut src, & mut dst) , ( 2 , 16 ) ) ;
201
211
assert_eq ! ( dst, [ 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] ) ;
202
212
213
+ let mut src = src_orig;
203
214
let mut dst = [ 0u8 ; 5 ] ;
204
- assert_eq ! ( fill_via_u64_chunks( & src, & mut dst) , ( 1 , 5 ) ) ;
215
+ assert_eq ! ( fill_via_u64_chunks( & mut src, & mut dst) , ( 1 , 5 ) ) ;
205
216
assert_eq ! ( dst, [ 1 , 0 , 0 , 0 , 0 ] ) ;
206
217
}
207
218
}
0 commit comments