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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#[cfg(feature = "rand")]
pub use rand::{Rng, RngCore};

#[cfg(feature = "uuid")]
pub use uuid::Uuid;

pub struct HostRng;

impl HostRng {
    /// Generate a 32-bit random number
    #[inline]
    #[must_use]
    pub fn random32() -> u32 {
        ::wasi::random::random::get_random_u64() as _
    }

    /// Generate a v4-format guid in the form "nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn"
    /// where n is a lowercase hex digit and all bits are random.
    #[cfg(feature = "uuid")]
    #[must_use]
    pub fn generate_guid() -> Uuid {
        let buf = uuid::Bytes::try_from(::wasi::random::random::get_random_bytes(16))
            .expect("invalid amount of bytes generated");
        uuid::Builder::from_random_bytes(buf).into_uuid()
    }

    /// Generate a random integer within an inclusive range. ( min <= n <= max )
    #[cfg(feature = "rand")]
    #[must_use]
    pub fn random_in_range(min: u32, max: u32) -> u32 {
        HostRng.gen_range(min..=max)
    }
}

#[cfg(feature = "rand")]
impl crate::RngCore for HostRng {
    #[inline]
    fn next_u32(&mut self) -> u32 {
        HostRng::random32()
    }

    #[inline]
    fn next_u64(&mut self) -> u64 {
        ::wasi::random::random::get_random_u64()
    }

    fn fill_bytes(&mut self, dest: &mut [u8]) {
        let n = dest.len();
        if usize::BITS <= u64::BITS || n <= u64::MAX as _ {
            dest.copy_from_slice(&::wasi::random::random::get_random_bytes(n as _));
        } else {
            let (head, tail) = dest.split_at_mut(u64::MAX as _);
            head.copy_from_slice(&::wasi::random::random::get_random_bytes(u64::MAX));
            // TODO: Optimize
            self.fill_bytes(tail);
        }
    }

    #[inline]
    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand::Error> {
        self.fill_bytes(dest);
        Ok(())
    }
}