Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@ A [separate changelog is kept for rand_core](rand_core/CHANGELOG.md).
You may also find the [Upgrade Guide](https://rust-random.github.io/book/update.html) useful.

## [Unreleased]
## Additions
### Additions
- Pub export `Xoshiro128PlusPlus`, `Xoshiro256PlusPlus` prngs (#1649)

### Changes
- Let `Fill` be implemented for element types, not sliceable types (#1652)

## [0.9.2 — 2025-07-20]
### Deprecated
- Deprecate `rand::rngs::mock` module and `StepRng` generator (#1634)
Expand Down
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,8 +293,8 @@ pub fn random_ratio(numerator: u32, denominator: u32) -> bool {
#[cfg(feature = "thread_rng")]
#[inline]
#[track_caller]
pub fn fill<T: Fill + ?Sized>(dest: &mut T) {
dest.fill(&mut rng())
pub fn fill<T: Fill>(dest: &mut [T]) {
Fill::fill_slice(dest, &mut rng())
}

#[cfg(test)]
Expand Down
140 changes: 49 additions & 91 deletions src/rng.rs
Original file line number Diff line number Diff line change
Expand Up @@ -311,8 +311,8 @@ pub trait Rng: RngCore {
///
/// [`fill_bytes`]: RngCore::fill_bytes
#[track_caller]
fn fill<T: Fill + ?Sized>(&mut self, dest: &mut T) {
dest.fill(self)
fn fill<T: Fill>(&mut self, dest: &mut [T]) {
Fill::fill_slice(dest, self)
}

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

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

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

macro_rules! impl_fill_each {
() => {};
($t:ty) => {
impl Fill for [$t] {
fn fill<R: Rng + ?Sized>(&mut self, rng: &mut R) {
for elt in self.iter_mut() {
*elt = rng.random();
}
}
}
};
($t:ty, $($tt:ty,)*) => {
impl_fill_each!($t);
impl_fill_each!($($tt,)*);
};
}

impl_fill_each!(bool, char, f32, f64,);

impl Fill for [u8] {
fn fill<R: Rng + ?Sized>(&mut self, rng: &mut R) {
rng.fill_bytes(self)
impl Fill for u8 {
fn fill_slice<R: Rng + ?Sized>(this: &mut [Self], rng: &mut R) {
rng.fill_bytes(this)
}
}

Expand All @@ -402,56 +386,45 @@ const unsafe fn __unsafe() {}
/// All bit patterns of `[u8; size_of::<$t>()]` must represent values of `$t`.
macro_rules! impl_fill {
() => {};
(to_le! plain $x:ident) => {
$x.to_le()
};
(to_le! wrapping $x:ident) => {
Wrapping($x.0.to_le())
};
(fill_slice! $t:ty, $to_le:tt) => {
fn fill_slice<R: Rng + ?Sized>(this: &mut [Self], rng: &mut R) {
if this.len() > 0 {
let size = mem::size_of_val(this);
rng.fill_bytes(
// SAFETY: `this` non-null and valid for reads and writes within its `size`
// bytes. `this` meets the alignment requirements of `&mut [u8]`.
// The contents of `this` are initialized. Both `[u8]` and `[$t]` are valid
// for all bit-patterns of their contents (note that the SAFETY requirement
// on callers of this macro). `this` is not borrowed.
unsafe {
slice::from_raw_parts_mut(this.as_mut_ptr()
as *mut u8,
size
)
}
);
for x in this {
*x = impl_fill!(to_le! $to_le x);
}
}
}
};
($t:ty) => {{
// Force caller to wrap with an `unsafe` block
__unsafe();

impl Fill for [$t] {
fn fill<R: Rng + ?Sized>(&mut self, rng: &mut R) {
if self.len() > 0 {
let size = mem::size_of_val(self);
rng.fill_bytes(
// SAFETY: `self` non-null and valid for reads and writes within its `size`
// bytes. `self` meets the alignment requirements of `&mut [u8]`.
// The contents of `self` are initialized. Both `[u8]` and `[$t]` are valid
// for all bit-patterns of their contents (note that the SAFETY requirement
// on callers of this macro). `self` is not borrowed.
unsafe {
slice::from_raw_parts_mut(self.as_mut_ptr()
as *mut u8,
size
)
}
);
for x in self {
*x = x.to_le();
}
}
}
impl Fill for $t {
impl_fill!(fill_slice! $t, plain);
}

impl Fill for [Wrapping<$t>] {
fn fill<R: Rng + ?Sized>(&mut self, rng: &mut R) {
if self.len() > 0 {
let size = self.len() * mem::size_of::<$t>();
rng.fill_bytes(
// SAFETY: `self` non-null and valid for reads and writes within its `size`
// bytes. `self` meets the alignment requirements of `&mut [u8]`.
// The contents of `self` are initialized. Both `[u8]` and `[$t]` are valid
// for all bit-patterns of their contents (note that the SAFETY requirement
// on callers of this macro). `self` is not borrowed.
unsafe {
slice::from_raw_parts_mut(self.as_mut_ptr()
as *mut u8,
size
)
}
);
for x in self {
*x = Wrapping(x.0.to_le());
}
}
}
impl Fill for Wrapping<$t> {
impl_fill!(fill_slice! $t, wrapping);
}}
};
($t:ty, $($tt:ty,)*) => {{
Expand All @@ -467,15 +440,6 @@ const _: () = unsafe { impl_fill!(u16, u32, u64, u128,) };
// SAFETY: All bit patterns of `[u8; size_of::<$t>()]` represent values of `i*`.
const _: () = unsafe { impl_fill!(i8, i16, i32, i64, i128,) };

impl<T, const N: usize> Fill for [T; N]
where
[T]: Fill,
{
fn fill<R: Rng + ?Sized>(&mut self, rng: &mut R) {
<[T] as Fill>::fill(self, rng)
}
}

#[cfg(test)]
mod test {
use super::*;
Expand Down Expand Up @@ -510,27 +474,21 @@ mod test {

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

// Convert to bytes then u32 in LE order
let mut array = [0u32; 2];
rng.fill(&mut array[..]);
rng.fill(&mut array);
assert_eq!(array, [x as u32, (x >> 32) as u32]);
assert_eq!(rng.next_u32(), x as u32);

// Check equivalence using wrapped arrays
let mut warray = [Wrapping(0u32); 2];
rng.fill(&mut warray[..]);
rng.fill(&mut warray);
assert_eq!(array[0], warray[0].0);
assert_eq!(array[1], warray[1].0);

// Check equivalence for generated floats
let mut array = [0f32; 2];
rng.fill(&mut array);
let arr2: [f32; 2] = rng.random();
assert_eq!(array, arr2);
}

#[test]
Expand Down
19 changes: 19 additions & 0 deletions tests/fill.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright 2025 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(unused)]

use rand::{Fill, Rng};

// Test that Fill may be implemented for externally-defined types
struct MyInt(i32);
impl Fill for MyInt {
fn fill_slice<R: Rng + ?Sized>(this: &mut [Self], rng: &mut R) {
todo!()
}
}
Loading