get_random_const/
lib.rs

1//! Simple compile time random generator
2//!
3//! ## Example
4//!
5//! ```rust
6//! use get_random_const::random;
7//!
8//! const RANDOM_U8: u8 = random!(u8);
9//! assert_ne!(RANDOM_U8, 0);
10//!
11//! static RANDOM_I32: i32 = random!(i32);
12//! assert_ne!(RANDOM_I32, 0);
13//!
14//! assert_ne!(random!(u8), 0u8);
15//! assert_ne!(random!(i8), 0i8);
16//! assert_ne!(random!(u16), 0u16);
17//! assert_ne!(random!(i16), 0i16);
18//! assert_ne!(random!(u32), 0u32);
19//! assert_ne!(random!(i32), 0i32);
20//! assert_ne!(random!(u64), 0u64);
21//! assert_ne!(random!(i64), 0i64);
22//! assert_ne!(random!(u128), 0u128);
23//! assert_ne!(random!(i128), 0i128);
24//! assert_ne!(random!(usize), 0usize);
25//! assert_ne!(random!(isize), 0isize);
26//!
27//! let random_array = random!([u32;5]);
28//! assert_eq!(random_array.len(), 5);
29//!
30//! for elem in random_array.iter() {
31//!     assert_ne!(*elem, 0);
32//! }
33//!
34//! let random_array: [u32; 0] = random!([u32;0]); //Well, I guess you can if you want?
35//! assert_eq!(random_array.len(), 0);
36//! ```
37
38
39extern crate proc_macro;
40
41use proc_macro::TokenStream;
42use getrandom::getrandom_uninit;
43
44use core::mem;
45
46fn randomize<T: Copy>() -> T {
47    let mut val = mem::MaybeUninit::<T>::uninit();
48    let slice = unsafe {
49        core::slice::from_raw_parts_mut(val.as_mut_ptr() as *mut mem::MaybeUninit<u8>, core::mem::size_of::<T>())
50    };
51
52    getrandom_uninit(slice).expect("Failed to generate random number");
53    unsafe {
54        val.assume_init()
55    }
56}
57
58fn randomize_type(path: &str) -> Option<String> {
59    let res = if path.eq_ignore_ascii_case("u8"){
60        let res = randomize::<u8>();
61        format!("{}u8", res)
62    } else if path.eq_ignore_ascii_case("i8") {
63        let res = randomize::<i8>();
64        format!("{}i8", res)
65    } else if path.eq_ignore_ascii_case("u16") {
66        let res = randomize::<u16>();
67        format!("{}u16", res)
68    } else if path.eq_ignore_ascii_case("i16") {
69        let res = randomize::<i16>();
70        format!("{}i16", res)
71    } else if path.eq_ignore_ascii_case("u32") {
72        let res = randomize::<u32>();
73        format!("{}u32", res)
74    } else if path.eq_ignore_ascii_case("i32") {
75        let res = randomize::<i32>();
76        format!("{}i32", res)
77    } else if path.eq_ignore_ascii_case("u64") {
78        let res = randomize::<u64>();
79        format!("{}u64", res)
80    } else if path.eq_ignore_ascii_case("i64") {
81        let res = randomize::<i64>();
82        format!("{}i64", res)
83    } else if path.eq_ignore_ascii_case("u128") {
84        let res = randomize::<u128>();
85        format!("{}u128", res)
86    } else if path.eq_ignore_ascii_case("i128") {
87        let res = randomize::<i128>();
88        format!("{}i128", res)
89    } else if path.eq_ignore_ascii_case("usize") {
90        let res = randomize::<usize>();
91        format!("{}usize", res)
92    } else if path.eq_ignore_ascii_case("isize") {
93        let res = randomize::<isize>();
94        format!("{}isize", res)
95    } else {
96        return None
97    };
98
99    Some(res)
100}
101
102#[proc_macro]
103pub fn random(input: TokenStream) -> TokenStream {
104    let input = input.to_string();
105    let input = input.trim();
106
107    if input.is_empty() {
108        panic!("Empty input :(");
109    } else if input.starts_with('[') {
110        if !input.ends_with(']') {
111            panic!("'{}' is missing right bracket", input);
112        }
113
114        let array_content = input[1..input.len()-1].trim();
115        if array_content.is_empty() {
116            panic!("just empty brackets? Did you mean array?");
117        }
118
119        let mut split = array_content.splitn(2, ';');
120        let typ = split.next().unwrap().trim();
121
122        if randomize_type(typ).is_none() {
123            panic!("'{}' is unsupported", typ);
124        }
125
126        let num = split.next().expect("Missing ';' in array type").trim();
127        let num: usize = num.parse().expect("Array type size is invalid as usize");
128
129        let mut result = "[".to_owned();
130        if num > 0 {
131            for _ in 0..num {
132                result.push_str(randomize_type(typ).unwrap().as_str());
133                result.push(',');
134            }
135            result.pop();
136        }
137        result.push(']');
138
139        result.parse().unwrap()
140    } else if let Some(result) = randomize_type(input) {
141        return result.parse().unwrap()
142    } else {
143        panic!("Unsupported type");
144    }
145}