Skip to main content

faker_rust/
config.rs

1//! Faker configuration - locale and random number generator settings
2
3use rand::SeedableRng;
4use rand::rngs::StdRng;
5use std::cell::RefCell;
6use std::rc::Rc;
7
8thread_local! {
9    static _FAKER_CONFIG: Rc<RefCell<FakerConfig>> = Rc::new(RefCell::new(FakerConfig::default()));
10}
11
12/// Faker configuration
13#[derive(Clone, Debug)]
14pub struct FakerConfig {
15    /// Current locale (default: "en")
16    pub locale: String,
17    /// Random number generator
18    pub rng: Rc<RefCell<StdRng>>,
19}
20
21impl Default for FakerConfig {
22    fn default() -> Self {
23        Self {
24            locale: "en".to_string(),
25            rng: Rc::new(RefCell::new(StdRng::from_entropy())),
26        }
27    }
28}
29
30impl FakerConfig {
31    /// Get the current Faker configuration
32    pub fn current() -> Self {
33        _FAKER_CONFIG.with(|config| config.borrow().clone())
34    }
35
36    /// Set the locale
37    pub fn set_locale(locale: &str) {
38        _FAKER_CONFIG.with(|config| {
39            config.borrow_mut().locale = locale.to_string();
40        });
41    }
42
43    /// Get the current locale
44    pub fn locale() -> String {
45        _FAKER_CONFIG.with(|config| config.borrow().locale.clone())
46    }
47
48    /// Set the random seed for deterministic output
49    pub fn set_seed(seed: u64) {
50        _FAKER_CONFIG.with(|config| {
51            config.borrow_mut().rng = Rc::new(RefCell::new(StdRng::seed_from_u64(seed)));
52        });
53    }
54
55    /// Generate a random number using the configured RNG
56    pub fn rand_u32(&self, max: u32) -> u32 {
57        use rand::Rng;
58        self.rng.borrow_mut().gen_range(0..max)
59    }
60
61    /// Generate a random usize
62    pub fn rand_usize(&self, max: usize) -> usize {
63        use rand::Rng;
64        self.rng.borrow_mut().gen_range(0..max)
65    }
66
67    /// Generate a random number between min and max (inclusive)
68    pub fn rand_range(&self, min: u32, max: u32) -> u32 {
69        if max <= min {
70            return min;
71        }
72        // Use exclusive range to avoid off-by-one error
73        let range = min..max;
74        use rand::Rng;
75        let mut rng = self.rng.borrow_mut();
76        rng.gen_range(range)
77    }
78
79    /// Generate a random i64 between min and max
80    pub fn rand_range_i64(&self, min: i64, max: i64) -> i64 {
81        if max <= min {
82            return min;
83        }
84        let range = min..max;
85        use rand::Rng;
86        let mut rng = self.rng.borrow_mut();
87        rng.gen_range(range)
88    }
89
90    /// Generate a random f64 between 0.0 and 1.0
91    pub fn rand_f64(&self) -> f64 {
92        use rand::Rng;
93        let mut rng = self.rng.borrow_mut();
94        let a: u32 = rng.gen_range(0..1000000);
95        (a as f64) / 1000000.0
96    }
97
98    /// Generate a random bool
99    pub fn rand_bool(&self) -> bool {
100        use rand::Rng;
101        let mut rng = self.rng.borrow_mut();
102        rng.gen_range(0..2) == 1
103    }
104
105    /// Generate a random char
106    pub fn rand_char(&self, chars: &[char]) -> char {
107        if chars.is_empty() {
108            return 'a'; // fallback
109        }
110        let idx = self.rand_range(0, chars.len() as u32) as usize;
111        chars[idx]
112    }
113
114    /// Sample a random element from a slice
115    pub fn sample<T: Clone>(&self, items: &[T]) -> T {
116        if items.is_empty() {
117            return items
118                .first()
119                .cloned()
120                .unwrap_or_else(|| panic!("Cannot sample from empty slice"));
121        }
122        let idx = self.rand_range(0, items.len() as u32) as usize;
123        items[idx].clone()
124    }
125
126    /// Shuffle a vector in place
127    #[allow(clippy::ptr_arg)]
128    pub fn shuffle<T>(&self, vec: &mut Vec<T>) {
129        use rand::seq::SliceRandom;
130        vec.shuffle(&mut *self.rng.borrow_mut());
131    }
132}