mos_hardware/mega65/
random.rs

1// copyright 2023 mikael lund aka wombat
2//
3// licensed under the apache license, version 2.0 (the "license");
4// you may not use this file except in compliance with the license.
5// you may obtain a copy of the license at
6//
7//     http://www.apache.org/licenses/license-2.0
8//
9// unless required by applicable law or agreed to in writing, software
10// distributed under the license is distributed on an "as is" basis,
11// without warranties or conditions of any kind, either express or implied.
12// see the license for the specific language governing permissions and
13// limitations under the license.
14
15//! Support for pseudo random numbers
16
17use super::libc;
18use core::ops::Shl;
19use rand_core::{Error, RngCore, SeedableRng};
20
21/// Generate random byte using MEGA65 libc
22pub fn rand8(max_value: u8) -> u8 {
23    unsafe { libc::rand8(max_value) }
24}
25
26/// Non-deterministic random number generator using MEGA65 Libc
27///
28/// Implements the [`rand::RngCore`](https://docs.rs/rand/latest/rand/trait.RngCore.html)
29/// trait and can thus be used with Rusts `rand` crate.
30///
31/// ## Examples
32/// ~~~
33/// use mos_hardware::mega65::random;
34/// use rand::seq::SliceRandom;
35/// let mut rng = LibcRng::default();
36/// let value = [11, 23].choose(&mut rng).unwrap(); // 11 or 23
37/// ~~~
38#[derive(Default)]
39pub struct LibcRng {}
40
41impl LibcRng {
42    /// New seeded generator
43    pub fn new(seed: LibcSeed) -> Self {
44        unsafe { libc::srand(u32::from_ne_bytes(seed.0)) };
45        LibcRng::default()
46    }
47}
48
49impl RngCore for LibcRng {
50    fn next_u32(&mut self) -> u32 {
51        unsafe { libc::rand32(u32::MAX) }
52    }
53    fn next_u64(&mut self) -> u64 {
54        // https://stackoverflow.com/a/2769598
55        u64::from(self.next_u32()).shl(32) | u64::from(self.next_u32())
56    }
57    fn fill_bytes(&mut self, dest: &mut [u8]) {
58        dest.iter_mut()
59            .for_each(|byte| *byte = unsafe { libc::rand8(u8::MAX) });
60    }
61    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
62        self.fill_bytes(dest);
63        Ok(())
64    }
65}
66
67/// 32-bit random number seed
68#[derive(Default)]
69pub struct LibcSeed(pub [u8; 4]);
70
71impl AsMut<[u8]> for LibcSeed {
72    fn as_mut(&mut self) -> &mut [u8] {
73        &mut self.0
74    }
75}
76
77impl SeedableRng for LibcRng {
78    type Seed = LibcSeed;
79    fn from_seed(seed: Self::Seed) -> Self {
80        LibcRng::new(seed)
81    }
82}