Skip to main content

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}