diff --git a/CHANGELOG.md b/CHANGELOG.md index 474e2c159f..e2c979cde7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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) diff --git a/src/lib.rs b/src/lib.rs index 9187c9cc16..d39c6d0e63 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -293,8 +293,8 @@ pub fn random_ratio(numerator: u32, denominator: u32) -> bool { #[cfg(feature = "thread_rng")] #[inline] #[track_caller] -pub fn fill(dest: &mut T) { - dest.fill(&mut rng()) +pub fn fill(dest: &mut [T]) { + Fill::fill_slice(dest, &mut rng()) } #[cfg(test)] diff --git a/src/rng.rs b/src/rng.rs index c502e1ba47..66af038627 100644 --- a/src/rng.rs +++ b/src/rng.rs @@ -311,8 +311,8 @@ pub trait Rng: RngCore { /// /// [`fill_bytes`]: RngCore::fill_bytes #[track_caller] - fn fill(&mut self, dest: &mut T) { - dest.fill(self) + fn fill(&mut self, dest: &mut [T]) { + Fill::fill_slice(dest, self) } /// Alias for [`Rng::random`]. @@ -356,40 +356,24 @@ pub trait Rng: RngCore { impl 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(&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(this: &mut [Self], rng: &mut R); } -macro_rules! impl_fill_each { - () => {}; - ($t:ty) => { - impl Fill for [$t] { - fn fill(&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(&mut self, rng: &mut R) { - rng.fill_bytes(self) +impl Fill for u8 { + fn fill_slice(this: &mut [Self], rng: &mut R) { + rng.fill_bytes(this) } } @@ -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(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(&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(&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,)*) => {{ @@ -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 Fill for [T; N] -where - [T]: Fill, -{ - fn fill(&mut self, rng: &mut R) { - <[T] as Fill>::fill(self, rng) - } -} - #[cfg(test)] mod test { use super::*; @@ -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] diff --git a/tests/fill.rs b/tests/fill.rs new file mode 100644 index 0000000000..3178723b81 --- /dev/null +++ b/tests/fill.rs @@ -0,0 +1,19 @@ +// Copyright 2025 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , 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(this: &mut [Self], rng: &mut R) { + todo!() + } +}