#[cfg(feature = "unstable")]
use crate::ProcedureContext;
use crate::{rand, ReducerContext};
use core::cell::UnsafeCell;
use core::marker::PhantomData;
use rand::distributions::{Distribution, Standard};
use rand::rngs::StdRng;
use rand::{RngCore, SeedableRng};
use spacetimedb_lib::Timestamp;
impl ReducerContext {
pub fn random<T>(&self) -> T
where
Standard: Distribution<T>,
{
Standard.sample(&mut self.rng())
}
pub fn rng(&self) -> &StdbRng {
self.rng.get_or_init(|| StdbRng::seed_from_ts(self.timestamp))
}
}
#[cfg(feature = "unstable")]
impl ProcedureContext {
#[cfg(feature = "unstable")]
pub fn random<T>(&self) -> T
where
Standard: Distribution<T>,
{
Standard.sample(&mut self.rng())
}
#[cfg(feature = "unstable")]
pub fn rng(&self) -> &StdbRng {
self.rng.get_or_init(|| StdbRng::seed_from_ts(self.timestamp))
}
}
pub struct StdbRng {
rng: UnsafeCell<StdRng>,
_marker: PhantomData<*mut ()>,
}
impl StdbRng {
fn seed_from_ts(timestamp: Timestamp) -> Self {
Self {
rng: StdRng::seed_from_u64(timestamp.to_micros_since_unix_epoch() as u64).into(),
_marker: PhantomData,
}
}
}
impl RngCore for StdbRng {
fn next_u32(&mut self) -> u32 {
(&*self).next_u32()
}
fn next_u64(&mut self) -> u64 {
(&*self).next_u64()
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
(&*self).fill_bytes(dest)
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand08::Error> {
(&*self).try_fill_bytes(dest)
}
}
impl RngCore for &StdbRng {
#[inline(always)]
fn next_u32(&mut self) -> u32 {
let rng = unsafe { &mut *self.rng.get() };
rng.next_u32()
}
#[inline(always)]
fn next_u64(&mut self) -> u64 {
let rng = unsafe { &mut *self.rng.get() };
rng.next_u64()
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
let rng = unsafe { &mut *self.rng.get() };
rng.fill_bytes(dest)
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand08::Error> {
let rng = unsafe { &mut *self.rng.get() };
rng.try_fill_bytes(dest)
}
}