1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
use awint_internals::*;
use crate::Bits;
/// `rand_support` functions
impl Bits {
// this is tested by `awint_test/tests/rand.rs`
/// Randomly-assigns `self` using a [rand_core::RngCore] random number
/// generator. This works by calling
/// [RngCore::fill_bytes](rand_core::RngCore::fill_bytes) and uses
/// platform independent methods such that if a pseudorandom generator is
/// used, it should always produce the same results when tried on the same
/// sequence of different bitwidth `Bits`.
///
/// ```
/// // Example using the `rand_xoshiro` crate.
/// use awint::{inlawi, Bits, InlAwi};
/// use rand_xoshiro::{rand_core::SeedableRng, Xoshiro128StarStar};
///
/// let mut rng = Xoshiro128StarStar::seed_from_u64(0);
/// let mut val = inlawi!(0u100);
/// val.rand_(&mut rng);
/// assert_eq!(val, inlawi!(0x5ab77d3629a089d75dec9045du100));
/// val.rand_(&mut rng);
/// assert_eq!(val, inlawi!(0x4c25a514060dea0565c95a8dau100));
/// ```
pub fn rand_<R: rand_core::RngCore>(&mut self, rng: &mut R) {
// We really want to use `fill_bytes` without an intermediate buffer.
// Here we make it portable with respect to length by emulating a byte sized
// unused bits scheme. On big endian systems this will set some unused bytes,
// but this will be fixed below.
let size_in_u8 = if (self.bw() % 8) == 0 {
self.bw() / 8
} else {
(self.bw() / 8) + 1
};
let bytes = &mut self.as_mut_bytes_full_width_nonportable()[..size_in_u8];
rng.fill_bytes(bytes);
// this is a no-op on little endian, but on big endian this fixes byte order in
// regular digits and rotates out unused bytes
const_for!(i in {0..self.total_digits()} {
self.as_mut_slice()[i] = Digit::from_le(self.as_mut_slice()[i]);
});
// clean up unused bits in last byte
self.clear_unused_bits();
}
}