Skip to content

Commit ead83fd

Browse files
authored
Let trait Fill be implemented for element types (#1652)
2 parents 1291ef1 + a1faaeb commit ead83fd

File tree

4 files changed

+74
-94
lines changed

4 files changed

+74
-94
lines changed

CHANGELOG.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,12 @@ A [separate changelog is kept for rand_core](rand_core/CHANGELOG.md).
99
You may also find the [Upgrade Guide](https://rust-random.github.io/book/update.html) useful.
1010

1111
## [Unreleased]
12-
## Additions
12+
### Additions
1313
- Pub export `Xoshiro128PlusPlus`, `Xoshiro256PlusPlus` prngs (#1649)
1414

15+
### Changes
16+
- Let `Fill` be implemented for element types, not sliceable types (#1652)
17+
1518
## [0.9.2 — 2025-07-20]
1619
### Deprecated
1720
- Deprecate `rand::rngs::mock` module and `StepRng` generator (#1634)

src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -293,8 +293,8 @@ pub fn random_ratio(numerator: u32, denominator: u32) -> bool {
293293
#[cfg(feature = "thread_rng")]
294294
#[inline]
295295
#[track_caller]
296-
pub fn fill<T: Fill + ?Sized>(dest: &mut T) {
297-
dest.fill(&mut rng())
296+
pub fn fill<T: Fill>(dest: &mut [T]) {
297+
Fill::fill_slice(dest, &mut rng())
298298
}
299299

300300
#[cfg(test)]

src/rng.rs

Lines changed: 49 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -311,8 +311,8 @@ pub trait Rng: RngCore {
311311
///
312312
/// [`fill_bytes`]: RngCore::fill_bytes
313313
#[track_caller]
314-
fn fill<T: Fill + ?Sized>(&mut self, dest: &mut T) {
315-
dest.fill(self)
314+
fn fill<T: Fill>(&mut self, dest: &mut [T]) {
315+
Fill::fill_slice(dest, self)
316316
}
317317

318318
/// Alias for [`Rng::random`].
@@ -356,40 +356,24 @@ pub trait Rng: RngCore {
356356

357357
impl<R: RngCore + ?Sized> Rng for R {}
358358

359-
/// Types which may be filled with random data
359+
/// Support filling a slice with random data
360360
///
361-
/// This trait allows arrays to be efficiently filled with random data.
361+
/// This trait allows slices of "plain data" types to be efficiently filled
362+
/// with random data.
362363
///
363364
/// Implementations are expected to be portable across machines unless
364365
/// clearly documented otherwise (see the
365366
/// [Chapter on Portability](https://rust-random.github.io/book/portability.html)).
366-
pub trait Fill {
367-
/// Fill self with random data
368-
fn fill<R: Rng + ?Sized>(&mut self, rng: &mut R);
367+
/// The implementations provided achieve this by byte-swapping on big-endian
368+
/// machines.
369+
pub trait Fill: Sized {
370+
/// Fill this with random data
371+
fn fill_slice<R: Rng + ?Sized>(this: &mut [Self], rng: &mut R);
369372
}
370373

371-
macro_rules! impl_fill_each {
372-
() => {};
373-
($t:ty) => {
374-
impl Fill for [$t] {
375-
fn fill<R: Rng + ?Sized>(&mut self, rng: &mut R) {
376-
for elt in self.iter_mut() {
377-
*elt = rng.random();
378-
}
379-
}
380-
}
381-
};
382-
($t:ty, $($tt:ty,)*) => {
383-
impl_fill_each!($t);
384-
impl_fill_each!($($tt,)*);
385-
};
386-
}
387-
388-
impl_fill_each!(bool, char, f32, f64,);
389-
390-
impl Fill for [u8] {
391-
fn fill<R: Rng + ?Sized>(&mut self, rng: &mut R) {
392-
rng.fill_bytes(self)
374+
impl Fill for u8 {
375+
fn fill_slice<R: Rng + ?Sized>(this: &mut [Self], rng: &mut R) {
376+
rng.fill_bytes(this)
393377
}
394378
}
395379

@@ -402,56 +386,45 @@ const unsafe fn __unsafe() {}
402386
/// All bit patterns of `[u8; size_of::<$t>()]` must represent values of `$t`.
403387
macro_rules! impl_fill {
404388
() => {};
389+
(to_le! plain $x:ident) => {
390+
$x.to_le()
391+
};
392+
(to_le! wrapping $x:ident) => {
393+
Wrapping($x.0.to_le())
394+
};
395+
(fill_slice! $t:ty, $to_le:tt) => {
396+
fn fill_slice<R: Rng + ?Sized>(this: &mut [Self], rng: &mut R) {
397+
if this.len() > 0 {
398+
let size = mem::size_of_val(this);
399+
rng.fill_bytes(
400+
// SAFETY: `this` non-null and valid for reads and writes within its `size`
401+
// bytes. `this` meets the alignment requirements of `&mut [u8]`.
402+
// The contents of `this` are initialized. Both `[u8]` and `[$t]` are valid
403+
// for all bit-patterns of their contents (note that the SAFETY requirement
404+
// on callers of this macro). `this` is not borrowed.
405+
unsafe {
406+
slice::from_raw_parts_mut(this.as_mut_ptr()
407+
as *mut u8,
408+
size
409+
)
410+
}
411+
);
412+
for x in this {
413+
*x = impl_fill!(to_le! $to_le x);
414+
}
415+
}
416+
}
417+
};
405418
($t:ty) => {{
406419
// Force caller to wrap with an `unsafe` block
407420
__unsafe();
408421

409-
impl Fill for [$t] {
410-
fn fill<R: Rng + ?Sized>(&mut self, rng: &mut R) {
411-
if self.len() > 0 {
412-
let size = mem::size_of_val(self);
413-
rng.fill_bytes(
414-
// SAFETY: `self` non-null and valid for reads and writes within its `size`
415-
// bytes. `self` meets the alignment requirements of `&mut [u8]`.
416-
// The contents of `self` are initialized. Both `[u8]` and `[$t]` are valid
417-
// for all bit-patterns of their contents (note that the SAFETY requirement
418-
// on callers of this macro). `self` is not borrowed.
419-
unsafe {
420-
slice::from_raw_parts_mut(self.as_mut_ptr()
421-
as *mut u8,
422-
size
423-
)
424-
}
425-
);
426-
for x in self {
427-
*x = x.to_le();
428-
}
429-
}
430-
}
422+
impl Fill for $t {
423+
impl_fill!(fill_slice! $t, plain);
431424
}
432425

433-
impl Fill for [Wrapping<$t>] {
434-
fn fill<R: Rng + ?Sized>(&mut self, rng: &mut R) {
435-
if self.len() > 0 {
436-
let size = self.len() * mem::size_of::<$t>();
437-
rng.fill_bytes(
438-
// SAFETY: `self` non-null and valid for reads and writes within its `size`
439-
// bytes. `self` meets the alignment requirements of `&mut [u8]`.
440-
// The contents of `self` are initialized. Both `[u8]` and `[$t]` are valid
441-
// for all bit-patterns of their contents (note that the SAFETY requirement
442-
// on callers of this macro). `self` is not borrowed.
443-
unsafe {
444-
slice::from_raw_parts_mut(self.as_mut_ptr()
445-
as *mut u8,
446-
size
447-
)
448-
}
449-
);
450-
for x in self {
451-
*x = Wrapping(x.0.to_le());
452-
}
453-
}
454-
}
426+
impl Fill for Wrapping<$t> {
427+
impl_fill!(fill_slice! $t, wrapping);
455428
}}
456429
};
457430
($t:ty, $($tt:ty,)*) => {{
@@ -467,15 +440,6 @@ const _: () = unsafe { impl_fill!(u16, u32, u64, u128,) };
467440
// SAFETY: All bit patterns of `[u8; size_of::<$t>()]` represent values of `i*`.
468441
const _: () = unsafe { impl_fill!(i8, i16, i32, i64, i128,) };
469442

470-
impl<T, const N: usize> Fill for [T; N]
471-
where
472-
[T]: Fill,
473-
{
474-
fn fill<R: Rng + ?Sized>(&mut self, rng: &mut R) {
475-
<[T] as Fill>::fill(self, rng)
476-
}
477-
}
478-
479443
#[cfg(test)]
480444
mod test {
481445
use super::*;
@@ -510,27 +474,21 @@ mod test {
510474

511475
// Convert to byte sequence and back to u64; byte-swap twice if BE.
512476
let mut array = [0u64; 2];
513-
rng.fill(&mut array[..]);
477+
rng.fill(&mut array);
514478
assert_eq!(array, [x, x]);
515479
assert_eq!(rng.next_u64(), x);
516480

517481
// Convert to bytes then u32 in LE order
518482
let mut array = [0u32; 2];
519-
rng.fill(&mut array[..]);
483+
rng.fill(&mut array);
520484
assert_eq!(array, [x as u32, (x >> 32) as u32]);
521485
assert_eq!(rng.next_u32(), x as u32);
522486

523487
// Check equivalence using wrapped arrays
524488
let mut warray = [Wrapping(0u32); 2];
525-
rng.fill(&mut warray[..]);
489+
rng.fill(&mut warray);
526490
assert_eq!(array[0], warray[0].0);
527491
assert_eq!(array[1], warray[1].0);
528-
529-
// Check equivalence for generated floats
530-
let mut array = [0f32; 2];
531-
rng.fill(&mut array);
532-
let arr2: [f32; 2] = rng.random();
533-
assert_eq!(array, arr2);
534492
}
535493

536494
#[test]

tests/fill.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright 2025 Developers of the Rand project.
2+
//
3+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4+
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5+
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6+
// option. This file may not be copied, modified, or distributed
7+
// except according to those terms.
8+
9+
#![allow(unused)]
10+
11+
use rand::{Fill, Rng};
12+
13+
// Test that Fill may be implemented for externally-defined types
14+
struct MyInt(i32);
15+
impl Fill for MyInt {
16+
fn fill_slice<R: Rng + ?Sized>(this: &mut [Self], rng: &mut R) {
17+
todo!()
18+
}
19+
}

0 commit comments

Comments
 (0)