random_branch/lib.rs
1#![no_std]
2
3// Enable annotating features requirements in docs
4#![cfg_attr(feature = "doc_cfg", feature(doc_cfg))]
5
6// This crate is entirely safe, actually it's just macros
7#![forbid(unsafe_code)]
8
9// Ensures that `pub` means published in the public API.
10// This property is useful for reasoning about breaking API changes.
11#![deny(unreachable_pub)]
12
13// Denies invalid links in docs
14#![deny(rustdoc::broken_intra_doc_links)]
15
16//! Provides a macro to select a random branch.
17//!
18//! This crate provides the [`branch`](crate::branch) and
19//! [`branch_using`](crate::branch_using) macro, which will
20//! execute randomly one of the given expressions.
21//!
22//! It is maybe best visualized by the following example:
23//!
24//! ```rust
25//! # #[cfg(features = "std")] { // only with std
26//! # use random_branch::branch;
27//! branch!(
28//! println!("First line."),
29//! println!("Second line?"),
30//! println!("Third line!"),
31//! );
32//! # } // only with std
33//! ```
34//!
35//! This will be turned into something similar to this:
36//!
37//! ```rust
38//! # #[cfg(features = "std")] { // only with std
39//! # use rand::Rng;
40//! match rand::rng().random_range(0..3) {
41//! 0 => println!("First line."),
42//! 1 => println!("Second line?"),
43//! 2 => println!("Third line!"),
44//! _ => unreachable!(),
45//! }
46//! # } // only with std
47//! ```
48//!
49//! For more details see [`branch`](crate::branch) and
50//! [`branch_using`](crate::branch_using). The basic difference between them is,
51//! that `branch` uses [`rand::rng()`](rand::rng()) whereas
52//! `branch_using` uses the the given [`rand::Rng`](rand::Rng).
53//!
54
55
56// Reexport our version of rand so we can use it from our macros.
57#[doc(hidden)]
58pub use rand;
59
60
61/// Branches into one of the given expressions using the given RNG.
62///
63/// This macro dose essentially the same as [`branch`] but uses the given
64/// [`Rng`](rand::Rng).
65///
66/// This macro turns something like this:
67///
68/// ```rust
69/// # use rand_pcg::Lcg64Xsh32;
70/// # use random_branch::branch_using;
71/// let mut my_rng = /* snip */
72/// # Lcg64Xsh32::new(0,0);
73///
74/// branch_using!( my_rng, {
75/// println!("First line."),
76/// println!("Second line?"),
77/// println!("Third line!"),
78/// });
79/// ```
80///
81/// into something similar to this:
82///
83/// ```rust
84/// # use rand_pcg::Lcg64Xsh32;
85/// let mut my_rng = /* snip */
86/// # Lcg64Xsh32::new(0,0);
87/// # use rand::Rng;
88///
89/// match my_rng.random_range(0..3) {
90/// 0 => println!("First line."),
91/// 1 => println!("Second line?"),
92/// 2 => println!("Third line!"),
93/// _ => unreachable!(),
94/// }
95/// ```
96///
97/// # Examples
98///
99/// You can use functions, macros and other arbitrary expressions:
100///
101/// ```rust
102/// # use rand_pcg::Lcg64Xsh32;
103/// use random_branch::branch_using;
104/// fn do_something() {
105/// println!("There is no such thing")
106/// }
107/// let thing = "fuliluf";
108/// let mut my_rng = /* snip */
109/// # Lcg64Xsh32::new(0,0);
110///
111/// branch_using!( my_rng, {
112/// println!("A {} is an animal!", thing),
113/// {
114/// let thing = "lufiful";
115/// println!("Two {}s will never meet.", thing)
116/// },
117/// println!("Only a {} can see other {0}s.", thing),
118/// do_something(),
119/// });
120/// ```
121///
122/// You can also use it as an expression to yield some randomly chosen value:
123///
124/// ```rust
125/// # use rand_pcg::Lcg64Xsh32;
126/// use random_branch::branch_using;
127/// let mut my_rng = /* snip */
128/// # Lcg64Xsh32::new(0,0);
129///
130/// let num = branch_using!( my_rng, {
131/// 10,
132/// 10 + 11,
133/// 2 * (10 + 11),
134/// 85,
135/// });
136/// assert!(num == 10 || num == 21 || num == 42 || num == 85);
137/// ```
138#[macro_export]
139macro_rules! branch_using {
140 ( $rng:expr, { $( $branch:expr ),* $(,)? }) => {
141 {
142 $crate::branch_internal!(
143 $rng,
144 { $( { $branch } )* },
145 )
146 }
147 };
148}
149
150
151/// Branches into one of the given expressions.
152///
153/// This macro dose essentially the same as [`branch_using`] instead of giving
154/// it some RNG, this macro will simply use the [`rand::rng()`].
155/// However, this then requires `std`, unlike `branch_using`.
156///
157/// This macro turns something like this:
158///
159/// ```rust
160/// # use random_branch::branch;
161/// branch!(
162/// println!("First line."),
163/// println!("Second line?"),
164/// println!("Third line!"),
165/// );
166/// ```
167///
168/// into something similar to this using the `rand::rng()`:
169///
170/// ```rust
171/// # use rand::Rng;
172/// match rand::rng().random_range(0..3) {
173/// 0 => println!("First line."),
174/// 1 => println!("Second line?"),
175/// 2 => println!("Third line!"),
176/// _ => unreachable!(),
177/// }
178/// ```
179///
180///
181/// # Examples
182///
183/// You can use functions, macros and other arbitrary expressions:
184///
185/// ```rust
186/// use random_branch::branch;
187///
188/// fn do_something() {
189/// println!("There is no such thing")
190/// }
191/// let thing = "fuliluf";
192///
193/// branch!(
194/// println!("A {} is an animal!", thing),
195/// {
196/// let thing = "lufiful";
197/// println!("Two {}s will never meet.", thing)
198/// },
199/// println!("Only a {} can see other {0}s.", thing),
200/// do_something(),
201/// );
202/// ```
203///
204/// You can also use it as an expression to yield some randomly chosen value:
205///
206/// ```rust
207/// use random_branch::branch;
208///
209/// let num = branch!(
210/// 10,
211/// 10 + 11,
212/// 2 * (10 + 11),
213/// 85,
214/// );
215/// println!("The best number is {}", num);
216/// # assert!(num == 10 || num == 21 || num == 42 || num == 85);
217/// ```
218#[macro_export]
219#[cfg(feature = "std")]
220#[cfg_attr(feature = "doc_cfg", doc(cfg(feature = "std")))]
221macro_rules! branch {
222 ( $( $branch:expr ),* $(,)? ) => {
223 {
224 $crate::branch_internal!(
225 $crate::rand::rng(),
226 { $( { $branch } )* },
227 )
228 }
229 };
230}
231
232
233/// Internal branching macro
234///
235/// Each branch must be enclosed in braces e.g. `{ }` so it is a single `tt`.
236///
237/// Syntax:
238/// ```text
239/// branch_internal!([RNG], [BRANCHES]+)
240/// ```
241#[doc(hidden)]
242#[macro_export]
243macro_rules! branch_internal {
244 // Entry pattern
245 ( $rng:expr, { $( $branches:tt )* }, ) => {
246 $crate::branch_internal!(@parseRule $rng, 0, {}, { $( $branches )* },)
247 };
248
249 // Invalid, base case
250 (@parseRule $rng:expr, $cnt:expr,
251 { },
252 { },
253 ) => {
254 compile_error!("You must provide at least one choice.")
255 };
256 // Prepares one branch at a time
257 (@parseRule $rng:expr, $cnt:expr,
258 { $( $stuff:tt )* },
259 { $branch:tt $( $rest:tt )* },
260 ) => {
261 {
262 $crate::branch_internal!(@parseRule $rng, $cnt + 1,
263 { $( $stuff )* { $cnt => $branch } },
264 { $( $rest )* },
265 )
266 }
267 };
268 // Assembles all branches into a big match
269 (@parseRule $rng:expr, $cnt:expr,
270 { $( { $cc:expr => $branch:tt } )* },
271 { },
272 ) => {{
273 match $crate::rand::Rng::random_range(&mut $rng, 0 .. ($cnt)) {
274 $( n if n == $cc => $branch )*
275 _ => unreachable!()
276 }
277 }};
278}
279
280#[cfg(test)]
281mod tests {
282 // We actually use mostly doc-tests, which are better suited for macro tests
283}