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}