Skip to main content

cfg_rs/source/
random.rs

1//! Random source.
2
3use rand::Rng;
4
5use super::{ConfigSource, memory::ConfigSourceBuilder};
6use crate::{ConfigError, ConfigValue, value::RandValue};
7
8/// Random source.
9#[allow(missing_debug_implementations, missing_copy_implementations)]
10pub(crate) struct Random;
11
12impl ConfigSource for Random {
13    fn name(&self) -> &str {
14        "random_generator"
15    }
16
17    fn load(&self, source: &mut ConfigSourceBuilder<'_>) -> Result<(), ConfigError> {
18        source.set("random.u8", RandValue::U8);
19        source.set("random.u16", RandValue::U16);
20        source.set("random.u32", RandValue::U32);
21        source.set("random.u64", RandValue::U64);
22        source.set("random.u128", RandValue::U128);
23        source.set("random.usize", RandValue::Usize);
24        source.set("random.i8", RandValue::I8);
25        source.set("random.i16", RandValue::I16);
26        source.set("random.i32", RandValue::I32);
27        source.set("random.i64", RandValue::I64);
28        source.set("random.i128", RandValue::I128);
29        source.set("random.isize", RandValue::Isize);
30        Ok(())
31    }
32}
33
34macro_rules! get_val {
35    ($($f:ident.$n:literal),+) => {$(
36        #[inline]
37        fn $f<R, F: Fn(&[u8; $n]) -> R>(f: F) -> R {
38            let mut rng = rand::rng();
39            let mut x = [0; $n];
40            rng.fill_bytes(&mut x);
41            (f)(&x)
42        }
43        )+};
44}
45
46get_val!(get_1.1, get_2.2, get_4.4, get_8.8, get_16.16);
47
48impl RandValue {
49    pub(crate) fn normalize(self) -> ConfigValue<'static> {
50        match self {
51            RandValue::U8 => get_1(|f| u8::from_le_bytes(*f)).into(),
52            RandValue::U16 => get_2(|f| u16::from_le_bytes(*f)).into(),
53            RandValue::U32 => get_4(|f| u32::from_le_bytes(*f)).into(),
54            RandValue::U64 => get_8(|f| u64::from_le_bytes(*f)).into(),
55            RandValue::U128 => get_16(|f| u128::from_le_bytes(*f)).into(),
56            #[cfg(target_pointer_width = "64")]
57            RandValue::Usize => get_8(|f| usize::from_le_bytes(*f)).into(),
58            #[cfg(target_pointer_width = "32")]
59            RandValue::Usize => get_4(|f| usize::from_le_bytes(*f)).into(),
60            RandValue::I8 => get_1(|f| i8::from_le_bytes(*f)).into(),
61            RandValue::I16 => get_2(|f| i16::from_le_bytes(*f)).into(),
62            RandValue::I32 => get_4(|f| i32::from_le_bytes(*f)).into(),
63            RandValue::I64 => get_8(|f| i64::from_le_bytes(*f)).into(),
64            RandValue::I128 => get_16(|f| i128::from_le_bytes(*f)).into(),
65            #[cfg(target_pointer_width = "64")]
66            RandValue::Isize => get_8(|f| isize::from_le_bytes(*f)).into(),
67            #[cfg(target_pointer_width = "32")]
68            RandValue::Isize => get_4(|f| isize::from_le_bytes(*f)).into(),
69        }
70    }
71}
72
73#[cfg_attr(coverage_nightly, coverage(off))]
74#[cfg(test)]
75mod test {
76
77    use crate::test::TestConfigExt;
78
79    use super::Random;
80
81    #[test]
82    fn env_test() {
83        let config = Random.new_config();
84        let a = config.get::<u128>("random.u128").unwrap();
85        let b = config.get::<u128>("random.u128").unwrap();
86        assert_ne!(a, b);
87    }
88
89    #[test]
90    fn value_test() {
91        let config = Random.new_config();
92        assert!(config.get::<u8>("random.u8").is_ok());
93        assert!(config.get::<u16>("random.u16").is_ok());
94        assert!(config.get::<u32>("random.u32").is_ok());
95        assert!(config.get::<u64>("random.u64").is_ok());
96        assert!(config.get::<u128>("random.u128").is_ok());
97        assert!(config.get::<usize>("random.usize").is_ok());
98        assert!(config.get::<i8>("random.i8").is_ok());
99        assert!(config.get::<i16>("random.i16").is_ok());
100        assert!(config.get::<i32>("random.i32").is_ok());
101        assert!(config.get::<i64>("random.i64").is_ok());
102        assert!(config.get::<i128>("random.i128").is_ok());
103        assert!(config.get::<isize>("random.isize").is_ok());
104    }
105}