Skip to main content

reifydb_runtime/context/rng/
mod.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2025 ReifyDB
3
4//! Random number generation abstraction.
5//!
6//! Provides an `Rng` enum that can use either OS entropy or a deterministic seed.
7
8use std::sync::{Arc, Mutex};
9
10use getrandom::fill as getrandom_fill;
11use rand::{Rng as RandRng, SeedableRng, rngs::StdRng};
12
13/// A random number generator that can be either OS-backed or seeded/deterministic.
14#[derive(Clone)]
15pub enum Rng {
16	/// Uses OS entropy via `getrandom` (non-deterministic).
17	Os,
18	/// Uses a seeded PRNG for deterministic output (e.g. testing).
19	Seeded(SeededRng),
20}
21
22impl Default for Rng {
23	fn default() -> Self {
24		Rng::Os
25	}
26}
27
28impl Rng {
29	/// Create a deterministic RNG from the given seed.
30	pub fn seeded(seed: u64) -> Self {
31		Rng::Seeded(SeededRng::new(seed))
32	}
33
34	/// Generate 16 random bytes (suitable for UUID v4).
35	pub fn bytes_16(&self) -> [u8; 16] {
36		match self {
37			Rng::Os => {
38				let mut buf = [0u8; 16];
39				getrandom_fill(&mut buf).expect("getrandom failed");
40				buf
41			}
42			Rng::Seeded(seeded) => {
43				let mut buf = [0u8; 16];
44				let mut rng = seeded.inner.lock().unwrap();
45				rng.fill_bytes(&mut buf);
46				buf
47			}
48		}
49	}
50
51	/// Generate 32 random bytes (suitable for token generation).
52	pub fn bytes_32(&self) -> [u8; 32] {
53		match self {
54			Rng::Os => {
55				let mut buf = [0u8; 32];
56				getrandom_fill(&mut buf).expect("getrandom failed");
57				buf
58			}
59			Rng::Seeded(seeded) => {
60				let mut buf = [0u8; 32];
61				let mut rng = seeded.inner.lock().unwrap();
62				rng.fill_bytes(&mut buf);
63				buf
64			}
65		}
66	}
67
68	/// Generate 10 random bytes (suitable for UUID v7 random portion).
69	pub fn bytes_10(&self) -> [u8; 10] {
70		match self {
71			Rng::Os => {
72				let mut buf = [0u8; 10];
73				getrandom_fill(&mut buf).expect("getrandom failed");
74				buf
75			}
76			Rng::Seeded(seeded) => {
77				let mut buf = [0u8; 10];
78				let mut rng = seeded.inner.lock().unwrap();
79				rng.fill_bytes(&mut buf);
80				buf
81			}
82		}
83	}
84}
85
86/// A seeded, deterministic RNG backed by `StdRng` wrapped in `Arc<Mutex<..>>`.
87#[derive(Clone)]
88pub struct SeededRng {
89	inner: Arc<Mutex<StdRng>>,
90}
91
92impl SeededRng {
93	/// Create a new seeded RNG from the given seed.
94	pub fn new(seed: u64) -> Self {
95		Self {
96			inner: Arc::new(Mutex::new(StdRng::seed_from_u64(seed))),
97		}
98	}
99}