vrd/macros.rs
1// Copyright © 2023-2026 vrd. All rights reserved.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3
4//! Convenience macros over the [`crate::Random`] facade.
5//!
6//! These wrap the inherent methods on `Random` so callers can write
7//! short-form expressions without importing the type explicitly.
8
9/// Generates an unbiased `u32` in the half-open range `[min, max)`.
10///
11/// # Examples
12///
13/// ```
14/// use vrd::{Random, random_range};
15///
16/// let mut rng = Random::from_u64_seed(42);
17/// let n = random_range!(rng, 10, 20);
18/// assert!(n >= 10 && n < 20);
19/// ```
20#[macro_export]
21macro_rules! random_range {
22 ($rng:expr, $min:expr, $max:expr) => {
23 $rng.random_range($min, $max)
24 };
25}
26
27/// Generates a random `bool` whose probability of `true` is the second
28/// argument. Panics if the probability is outside `[0.0, 1.0]`.
29///
30/// # Examples
31///
32/// ```
33/// use vrd::{Random, rand_bool};
34///
35/// let mut rng = Random::from_u64_seed(42);
36/// let b = rand_bool!(rng, 0.5);
37/// ```
38#[macro_export]
39macro_rules! rand_bool {
40 ($rng:expr, $probability:expr) => {{
41 $rng.bool($probability)
42 }};
43}
44
45/// Returns a `Vec<u8>` of `len` random bytes. Requires the `alloc`
46/// feature.
47///
48/// # Examples
49///
50/// ```
51/// use vrd::{Random, rand_bytes};
52///
53/// # #[cfg(feature = "alloc")]
54/// # {
55/// let mut rng = Random::from_u64_seed(42);
56/// let bytes = rand_bytes!(rng, 16);
57/// assert_eq!(bytes.len(), 16);
58/// # }
59/// ```
60#[cfg(feature = "alloc")]
61#[macro_export]
62macro_rules! rand_bytes {
63 ($rng:expr, $len:expr) => {
64 $rng.bytes($len)
65 };
66}
67
68/// Returns a random lowercase ASCII char (`'a'..='z'`).
69///
70/// # Examples
71///
72/// ```
73/// use vrd::{Random, rand_char};
74///
75/// let mut rng = Random::from_u64_seed(42);
76/// let c = rand_char!(rng);
77/// assert!(c.is_ascii_lowercase());
78/// ```
79#[macro_export]
80macro_rules! rand_char {
81 ($rng:expr) => {
82 $rng.char()
83 };
84}
85
86/// Picks a random reference into the given slice (`Option<&T>`).
87///
88/// # Examples
89///
90/// ```
91/// use vrd::{Random, rand_choose};
92///
93/// let mut rng = Random::from_u64_seed(42);
94/// let choices = [1, 2, 3];
95/// let pick = rand_choose!(rng, &choices);
96/// ```
97#[macro_export]
98macro_rules! rand_choose {
99 ($rng:expr, $values:expr) => {
100 $rng.choose($values)
101 };
102}
103
104/// Generates an `f32` in `[0.0, 1.0)`.
105///
106/// # Examples
107///
108/// ```
109/// use vrd::{Random, rand_float};
110///
111/// let mut rng = Random::from_u64_seed(42);
112/// let f = rand_float!(rng);
113/// ```
114#[macro_export]
115macro_rules! rand_float {
116 ($rng:expr) => {
117 $rng.float()
118 };
119}
120
121/// Generates an unbiased `i32` in the inclusive range `[min, max]`.
122///
123/// # Examples
124///
125/// ```
126/// use vrd::{Random, rand_int};
127///
128/// let mut rng = Random::from_u64_seed(42);
129/// let n = rand_int!(rng, -10, 10);
130/// ```
131#[macro_export]
132macro_rules! rand_int {
133 ($rng:expr, $min:expr, $max:expr) => {
134 $rng.int($min, $max)
135 };
136}
137
138/// Generates an unbiased `u32` in the inclusive range `[min, max]`.
139///
140/// # Examples
141///
142/// ```
143/// use vrd::{Random, rand_uint};
144///
145/// let mut rng = Random::from_u64_seed(42);
146/// let n = rand_uint!(rng, 0, 100);
147/// ```
148#[macro_export]
149macro_rules! rand_uint {
150 ($rng:expr, $min:expr, $max:expr) => {
151 $rng.uint($min, $max)
152 };
153}
154
155/// Generates an `f64` in `[0.0, 1.0)`.
156///
157/// # Examples
158///
159/// ```
160/// use vrd::{Random, rand_double};
161///
162/// let mut rng = Random::from_u64_seed(42);
163/// let d = rand_double!(rng);
164/// ```
165#[macro_export]
166macro_rules! rand_double {
167 ($rng:expr) => {
168 $rng.double()
169 };
170}
171
172/// Inclusive `[min, max]` range for `i32`.
173///
174/// # Examples
175///
176/// ```
177/// use vrd::{Random, rand_range};
178///
179/// let mut rng = Random::from_u64_seed(42);
180/// let n = rand_range!(rng, 1, 10);
181/// ```
182#[macro_export]
183macro_rules! rand_range {
184 ($rng:expr, $min:expr, $max:expr) => {
185 $rng.range($min, $max)
186 };
187}
188
189/// Re-seeds the active backend.
190///
191/// # Examples
192///
193/// ```
194/// use vrd::{Random, rand_seed};
195///
196/// let mut rng = Random::from_u64_seed(42);
197/// rand_seed!(rng, 123);
198/// ```
199#[macro_export]
200macro_rules! rand_seed {
201 ($rng:expr, $seed:expr) => {
202 $rng.seed($seed)
203 };
204}
205
206/// Forces a Mersenne-Twister twist; no-op on Xoshiro.
207///
208/// # Examples
209///
210/// ```
211/// use vrd::{Random, rand_twist};
212///
213/// # #[cfg(all(feature = "alloc", feature = "std"))]
214/// # {
215/// let mut rng = Random::new_mersenne_twister();
216/// rand_twist!(rng);
217/// # }
218/// ```
219#[macro_export]
220macro_rules! rand_twist {
221 ($rng:expr) => {
222 $rng.twist()
223 };
224}
225
226/// Returns a random alphanumeric ASCII char.
227///
228/// # Examples
229///
230/// ```
231/// use vrd::{Random, rand_alphanumeric};
232///
233/// let mut rng = Random::from_u64_seed(42);
234/// let c = rand_alphanumeric!(rng);
235/// ```
236#[macro_export]
237macro_rules! rand_alphanumeric {
238 ($rng:expr) => {{
239 const CHARS: &[u8; 62] =
240 b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
241 let idx = $rng.bounded(CHARS.len() as u32) as usize;
242 CHARS[idx] as char
243 }};
244}
245
246/// Returns a fresh lowercase ASCII `String` of `length` chars. Requires
247/// `alloc`.
248///
249/// # Examples
250///
251/// ```
252/// use vrd::{Random, rand_string};
253///
254/// # #[cfg(feature = "alloc")]
255/// # {
256/// let mut rng = Random::from_u64_seed(42);
257/// let s = rand_string!(rng, 10);
258/// # }
259/// ```
260#[cfg(feature = "alloc")]
261#[macro_export]
262macro_rules! rand_string {
263 ($rng:expr, $length:expr) => {
264 $rng.string($length)
265 };
266}
267
268/// Fisher-Yates shuffle in place.
269///
270/// # Examples
271///
272/// ```
273/// use vrd::{Random, rand_shuffle};
274///
275/// let mut rng = Random::from_u64_seed(42);
276/// let mut nums = [1, 2, 3];
277/// rand_shuffle!(rng, &mut nums);
278/// ```
279#[macro_export]
280macro_rules! rand_shuffle {
281 ($rng:expr, $slice:expr) => {{
282 $rng.shuffle($slice)
283 }};
284}
285
286/// Selects a reference into `$choices` weighted by `$weights`.
287///
288/// # Examples
289///
290/// ```
291/// use vrd::{Random, rand_weighted_choice};
292///
293/// let mut rng = Random::from_u64_seed(42);
294/// let choices = ["a", "b"];
295/// let weights = [10, 90];
296/// let pick = rand_weighted_choice!(rng, &choices, &weights);
297/// ```
298#[macro_export]
299macro_rules! rand_weighted_choice {
300 ($rng:expr, $choices:expr, $weights:expr) => {{
301 assert_eq!(
302 $choices.len(),
303 $weights.len(),
304 "choices and weights must have the same length"
305 );
306 let total: u32 = $weights.iter().sum();
307 assert!(total > 0, "total weight must be positive");
308 let mut rnd = $rng.bounded(total);
309 let mut selected = None;
310 for (i, &w) in $weights.iter().enumerate() {
311 if rnd < w {
312 selected = Some(&$choices[i]);
313 break;
314 }
315 rnd -= w;
316 }
317 selected.expect("weighted choice failed to select")
318 }};
319}
320
321/// Standard Box-Muller normal sample.
322///
323/// # Examples
324///
325/// ```
326/// use vrd::{Random, rand_normal};
327///
328/// let mut rng = Random::from_u64_seed(42);
329/// let n = rand_normal!(rng, 0.0, 1.0);
330/// ```
331#[macro_export]
332macro_rules! rand_normal {
333 ($rng:expr, $mu:expr, $sigma:expr) => {{
334 $rng.normal($mu, $sigma)
335 }};
336}
337
338/// Exponential sample with the given rate.
339///
340/// # Examples
341///
342/// ```
343/// use vrd::{Random, rand_exponential};
344///
345/// let mut rng = Random::from_u64_seed(42);
346/// let e = rand_exponential!(rng, 1.5);
347/// ```
348#[macro_export]
349macro_rules! rand_exponential {
350 ($rng:expr, $rate:expr) => {{
351 $rng.exponential($rate)
352 }};
353}
354
355/// Poisson sample with the given mean.
356///
357/// # Examples
358///
359/// ```
360/// use vrd::{Random, rand_poisson};
361///
362/// let mut rng = Random::from_u64_seed(42);
363/// let p = rand_poisson!(rng, 3.0);
364/// ```
365#[macro_export]
366macro_rules! rand_poisson {
367 ($rng:expr, $mean:expr) => {{
368 $rng.poisson($mean)
369 }};
370}