product_os_random/lib.rs
1//! # Product OS Random
2//!
3//! A random number generation library providing cryptographically secure RNGs,
4//! random text/number generators, and word/name generators. Supports `no_std` environments.
5//!
6//! ## Features
7//!
8//! This crate provides multiple feature flags to control functionality and dependencies:
9//!
10//! ### Core Features
11//! - `default` - Basic random generation with `StdRng` and getrandom support
12//! - `core` - Full standard library support with `StdRng`, `ThreadRng`, and `OsRng`
13//! - `send_only` - Send-safe RNG variants only
14//! - `constrained` - Minimal allocation-only mode (no default RNG, user must provide)
15//! - `custom` - Custom RNG support with spin locks for `no_std` environments
16//! - `custom_send_only` - Custom Send-safe RNG support
17//!
18//! ### Dataset Features
19//! - `words` - Enable random word generation
20//! - `nouns` - Enable random noun generation
21//! - `adjectives` - Enable random adjective generation
22//! - `names` - Enable random full name generation
23//! - `first_names` - Enable random first name generation
24//! - `last_names` - Enable random last name generation
25//!
26//! ## Security Considerations
27//!
28//! ### Cryptographic vs Non-Cryptographic RNGs
29//!
30//! - **`CryptoRNG`**: Use for security-sensitive operations (passwords, keys, tokens).
31//! Implements `CryptoRng` marker trait indicating cryptographic security.
32//! - **`RNG`**: General-purpose random generation. Some variants are cryptographically
33//! secure (like `OsRng`), others are not (like seeded `StdRng`).
34//!
35//! ### Thread Safety
36//!
37//! - `RNG::Thread` uses `ThreadRng` which is thread-local
38//! - Custom RNG wrappers use `Arc<Mutex<>>` for thread-safe access
39//! - All RNG variants implement `Clone` for easy distribution
40//!
41//! ## Usage Examples
42//!
43//! ### Convenience Functions (Recommended)
44//!
45//! The simplest way to generate random data:
46//!
47//! ```rust
48//! # #[cfg(feature = "core")]
49//! # {
50//! let password = product_os_random::random_password(16);
51//! let code = product_os_random::random_alphanumeric(10);
52//! let port = product_os_random::random_usize(1025, 65535);
53//! let bytes = product_os_random::random_bytes(32);
54//! let key = product_os_random::generate_random_key(32);
55//! # }
56//! ```
57//!
58//! ### Stateful Generator with Custom RNG
59//!
60//! ```rust
61//! # #[cfg(feature = "core")]
62//! # {
63//! use product_os_random::{RandomGenerator, RandomGeneratorTemplate, RNG};
64//! use rand::SeedableRng;
65//!
66//! // Create a seeded RNG for reproducible results
67//! let rng = RNG::Std(rand::rngs::StdRng::seed_from_u64(42));
68//! let mut gen = RandomGenerator::new(Some(rng));
69//!
70//! // Generate random data
71//! let bytes = gen.get_random_bytes(32);
72//! let number = gen.get_random_usize(1, 100);
73//! let alphanumeric = gen.get_random_alphanumeric(10);
74//! # }
75//! ```
76//!
77//! ### Cryptographic Key Generation
78//!
79//! ```rust
80//! # #[cfg(feature = "core")]
81//! # {
82//! use product_os_random::RandomGenerator;
83//!
84//! // Generate a cryptographic key
85//! let key = RandomGenerator::generate_simple_key_one_time(32);
86//! assert_eq!(key.len(), 32);
87//! # }
88//! ```
89//!
90//! ### Using Feature-Gated Name Generation
91//!
92//! ```rust
93//! # #[cfg(all(feature = "core", feature = "names"))]
94//! # {
95//! use product_os_random::RandomGenerator;
96//!
97//! let username = RandomGenerator::get_simple_random_username_one_time(
98//! Some(2),
99//! Some(4),
100//! Some("_".to_string())
101//! );
102//!
103//! let email = RandomGenerator::get_simple_random_email_one_time(
104//! Some(2),
105//! Some(3),
106//! None,
107//! vec!["example.com".to_string()]
108//! );
109//! # }
110//! ```
111//!
112//! ### Custom RNG Implementation
113//!
114//! ```rust
115//! # #[cfg(feature = "custom")]
116//! # {
117//! use product_os_random::{CustomRng, RNG};
118//! use rand::SeedableRng;
119//!
120//! let seed_rng = rand::rngs::StdRng::seed_from_u64(42);
121//! let custom = CustomRng::new(seed_rng);
122//! let rng = RNG::Custom(custom);
123//! # }
124//! ```
125//!
126//! ## Performance Characteristics
127//!
128//! - **String Generation**: Pre-allocates with `String::with_capacity` for efficiency
129//! - **Large Datasets**: Names datasets are large (~400K lines total), consider binary size
130//! - **Lock Contention**: Custom RNGs use mutexes, may have contention under high concurrency
131//! - **`no_std` Support**: Minimal overhead when used without standard library features
132
133#![no_std]
134// Clippy configuration
135#![warn(clippy::all, clippy::pedantic, clippy::cargo)]
136#![warn(missing_docs)]
137// Allow certain patterns that are intentional
138#![allow(clippy::module_name_repetitions)] // RandomGenerator naming is intentional
139#![allow(clippy::similar_names)] // rng, gen are standard in RNG code
140#![allow(unreachable_patterns)] // Patterns may be unreachable with certain feature combinations
141#![allow(clippy::too_many_lines)] // Large file is acceptable for now, will refactor later
142#![allow(clippy::must_use_candidate)] // Many functions could use #[must_use], will add gradually
143#![allow(clippy::missing_errors_doc)] // Error docs will be added with try_ variants
144#![allow(clippy::missing_panics_doc)] // Panic docs exist in main documentation
145#![allow(clippy::missing_docs_in_private_items)] // Private items don't need docs
146#![allow(clippy::if_same_then_else)] // Feature-gated code may look identical but isn't
147
148extern crate alloc;
149
150use alloc::string::String;
151#[cfg(any(feature = "custom", feature = "custom_send_only"))]
152use alloc::sync::Arc;
153#[cfg(feature = "rand")]
154use alloc::vec;
155use alloc::vec::Vec;
156
157#[cfg(feature = "adjectives")]
158mod adjectives;
159#[cfg(feature = "first_names")]
160mod first_names;
161#[cfg(feature = "last_names")]
162mod last_names;
163#[cfg(feature = "names")]
164mod names;
165#[cfg(feature = "nouns")]
166mod nouns;
167#[cfg(feature = "words")]
168mod words;
169
170#[cfg(any(feature = "core", feature = "send_only"))]
171pub use rand::rngs::StdRng;
172
173#[cfg(all(feature = "core", not(feature = "send_only")))]
174pub use rand::rngs::ThreadRng;
175
176#[cfg(feature = "core")]
177pub use rand::rngs::OsRng;
178
179#[cfg(feature = "custom")]
180pub use getrandom::register_custom_getrandom;
181
182#[cfg(feature = "rand")]
183pub use rand::{CryptoRng, Error, Rng, RngCore, SeedableRng};
184
185// Helper functions for character filtering and range operations
186// These reduce code duplication and fix clippy warnings
187
188/// Filters a character value to exclude certain special characters.
189/// Used in random string generation to ensure printable, alphanumeric-focused output.
190///
191/// Character ranges that get shifted:
192/// - 33-37 → +20 (shifts to 53-57, which are '5' to '9')
193/// - 38-47 → +10 (shifts to 48-57, which are '0' to '9')
194/// - 58-64 → +10 (shifts to 68-74, which are 'D' to 'J')
195/// - 91-96 → +10 (shifts to 101-106, which are 'e' to 'j')
196#[cfg(feature = "rand")]
197#[inline]
198fn filter_printable_char(mut value: u8) -> u8 {
199 if (33..=37).contains(&value) {
200 value += 20;
201 } else if (38..=47).contains(&value) {
202 value += 10;
203 } else if (58..=64).contains(&value) {
204 value += 10;
205 } else if (91..=96).contains(&value) {
206 value += 10;
207 }
208 value
209}
210
211/// Filters a character value for alphanumeric output (0-9, a-z, A-Z).
212///
213/// Character ranges that get shifted:
214/// - 58-64 → +10 (shifts to A-Z range)
215/// - 91-96 → +10 (shifts to a-z range)
216#[cfg(feature = "rand")]
217#[inline]
218fn filter_alphanumeric_char(mut value: u8) -> u8 {
219 if (58..=64).contains(&value) {
220 value += 10;
221 } else if (91..=96).contains(&value) {
222 value += 10;
223 }
224 value
225}
226
227/// Converts a string to title case (first letter uppercase, rest lowercase).
228///
229/// This is a simple implementation for single-word name data, replacing the
230/// `inflections` crate dependency. Handles Unicode correctly via `char::to_uppercase`
231/// and `char::to_lowercase`.
232#[cfg(any(feature = "first_names", feature = "last_names"))]
233#[allow(dead_code)]
234fn to_title_case(s: &str) -> String {
235 let mut chars = s.chars();
236 match chars.next() {
237 None => String::new(),
238 Some(first) => {
239 let mut result = String::with_capacity(s.len());
240 for c in first.to_uppercase() {
241 result.push(c);
242 }
243 for c in chars {
244 for lc in c.to_lowercase() {
245 result.push(lc);
246 }
247 }
248 result
249 }
250 }
251}
252
253/// A thread-safe wrapper around any `RngCore` implementation for use in `no_std` environments.
254///
255/// This type wraps an RNG in `Arc<Mutex<>>` using a spin lock, making it shareable across
256/// threads in `no_std` contexts. The mutex ensures safe concurrent access to the underlying RNG.
257///
258/// # Thread Safety
259///
260/// Uses spin locks from the `spin` crate, which are suitable for `no_std` environments.
261/// Under high contention, spin locks may consume CPU cycles waiting for the lock.
262///
263/// # Examples
264///
265/// ```rust
266/// # #[cfg(feature = "custom")]
267/// # {
268/// use product_os_random::CustomRng;
269/// use rand::SeedableRng;
270///
271/// let seed_rng = rand::rngs::StdRng::seed_from_u64(42);
272/// let custom = CustomRng::new(seed_rng);
273/// # }
274/// ```
275#[cfg(feature = "custom")]
276#[derive(Clone)]
277pub struct CustomRng {
278 rng: Arc<spin::mutex::Mutex<dyn RngCore>>,
279}
280
281#[cfg(feature = "custom")]
282impl CustomRng {
283 /// Creates a new `CustomRng` wrapping the provided RNG.
284 ///
285 /// The RNG is wrapped in `Arc<Mutex<>>` to enable thread-safe cloning and concurrent access.
286 ///
287 /// # Examples
288 ///
289 /// ```rust
290 /// # #[cfg(feature = "custom")]
291 /// # {
292 /// use product_os_random::CustomRng;
293 /// use rand::SeedableRng;
294 ///
295 /// let rng = rand::rngs::StdRng::seed_from_u64(42);
296 /// let custom = CustomRng::new(rng);
297 /// # }
298 /// ```
299 pub fn new(rng: impl RngCore + 'static) -> Self {
300 Self {
301 rng: Arc::new(spin::mutex::Mutex::new(rng)),
302 }
303 }
304}
305
306#[cfg(feature = "custom")]
307impl RngCore for CustomRng {
308 fn next_u32(&mut self) -> u32 {
309 let mut rl = self.rng.lock();
310 rl.next_u32()
311 }
312
313 fn next_u64(&mut self) -> u64 {
314 let mut rl = self.rng.lock();
315 rl.next_u64()
316 }
317
318 fn fill_bytes(&mut self, dest: &mut [u8]) {
319 let mut rl = self.rng.lock();
320 rl.fill_bytes(dest);
321 }
322
323 fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
324 let mut rl = self.rng.lock();
325 rl.try_fill_bytes(dest)
326 }
327}
328
329/// Marker trait for cryptographically secure RNGs.
330///
331/// This trait combines `RngCore` and `CryptoRng` to indicate that an RNG is suitable
332/// for security-sensitive operations like key generation, password creation, and token generation.
333///
334/// # Security
335///
336/// Implementors of this trait must provide cryptographically secure random number generation.
337/// This typically means:
338/// - Output is indistinguishable from true randomness
339/// - Past outputs don't reveal future outputs
340/// - Sufficient entropy from a secure source
341///
342/// # Examples
343///
344/// ```rust
345/// # #[cfg(feature = "custom")]
346/// # {
347/// use product_os_random::{RngCore, CryptoRng, RngCrypto, Error};
348/// use rand::SeedableRng;
349///
350/// struct MyCryptoRng(rand::rngs::StdRng);
351///
352/// impl RngCore for MyCryptoRng {
353/// fn next_u32(&mut self) -> u32 { self.0.next_u32() }
354/// fn next_u64(&mut self) -> u64 { self.0.next_u64() }
355/// fn fill_bytes(&mut self, dest: &mut [u8]) { self.0.fill_bytes(dest) }
356/// fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
357/// self.0.try_fill_bytes(dest)
358/// }
359/// }
360///
361/// impl CryptoRng for MyCryptoRng {}
362/// impl RngCrypto for MyCryptoRng {}
363/// # }
364/// ```
365#[cfg(any(feature = "custom", feature = "custom_send_only"))]
366pub trait RngCrypto: RngCore + CryptoRng {}
367
368/// A thread-safe wrapper around cryptographically secure RNGs for use in `no_std` environments.
369///
370/// Similar to `CustomRng`, but specifically for RNGs that implement the `RngCrypto` trait,
371/// providing additional type safety for cryptographic operations.
372///
373/// # Security
374///
375/// This type should only wrap RNGs that are cryptographically secure. The wrapper itself
376/// doesn't add or remove security properties, it only provides thread-safe access.
377///
378/// # Examples
379///
380/// ```rust
381/// # #[cfg(feature = "custom")]
382/// # {
383/// use product_os_random::{CustomCryptoRng, RngCore, CryptoRng, RngCrypto, Error};
384/// use rand::SeedableRng;
385///
386/// #[derive(Clone)]
387/// struct MyCryptoRng(rand::rngs::StdRng);
388///
389/// impl RngCore for MyCryptoRng {
390/// fn next_u32(&mut self) -> u32 { self.0.next_u32() }
391/// fn next_u64(&mut self) -> u64 { self.0.next_u64() }
392/// fn fill_bytes(&mut self, dest: &mut [u8]) { self.0.fill_bytes(dest) }
393/// fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
394/// self.0.try_fill_bytes(dest)
395/// }
396/// }
397///
398/// impl CryptoRng for MyCryptoRng {}
399/// impl RngCrypto for MyCryptoRng {}
400///
401/// let rng = MyCryptoRng(rand::rngs::StdRng::seed_from_u64(42));
402/// let custom = CustomCryptoRng::new(rng);
403/// # }
404/// ```
405#[derive(Clone)]
406#[cfg(feature = "custom")]
407pub struct CustomCryptoRng {
408 rng: Arc<spin::mutex::Mutex<dyn RngCrypto>>,
409}
410
411#[cfg(feature = "custom")]
412impl CustomCryptoRng {
413 /// Creates a new `CustomCryptoRng` wrapping the provided cryptographic RNG.
414 ///
415 /// # Security
416 ///
417 /// The provided RNG must implement `RngCrypto`, ensuring it's suitable for
418 /// cryptographic operations.
419 ///
420 /// # Examples
421 ///
422 /// ```rust
423 /// # #[cfg(feature = "custom")]
424 /// # {
425 /// use product_os_random::{CustomCryptoRng, RngCore, CryptoRng, RngCrypto, Error};
426 /// use rand::SeedableRng;
427 ///
428 /// #[derive(Clone)]
429 /// struct MyCryptoRng(rand::rngs::StdRng);
430 ///
431 /// impl RngCore for MyCryptoRng {
432 /// fn next_u32(&mut self) -> u32 { self.0.next_u32() }
433 /// fn next_u64(&mut self) -> u64 { self.0.next_u64() }
434 /// fn fill_bytes(&mut self, dest: &mut [u8]) { self.0.fill_bytes(dest) }
435 /// fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
436 /// self.0.try_fill_bytes(dest)
437 /// }
438 /// }
439 ///
440 /// impl CryptoRng for MyCryptoRng {}
441 /// impl RngCrypto for MyCryptoRng {}
442 ///
443 /// let rng = MyCryptoRng(rand::rngs::StdRng::seed_from_u64(42));
444 /// let custom = CustomCryptoRng::new(rng);
445 /// # }
446 /// ```
447 pub fn new(rng: impl RngCrypto + 'static) -> Self {
448 Self {
449 rng: Arc::new(spin::mutex::Mutex::new(rng)),
450 }
451 }
452}
453
454#[cfg(feature = "custom")]
455impl RngCrypto for CustomCryptoRng {}
456
457#[cfg(feature = "custom")]
458impl CryptoRng for CustomCryptoRng {}
459
460#[cfg(feature = "custom")]
461impl RngCore for CustomCryptoRng {
462 fn next_u32(&mut self) -> u32 {
463 let mut rl = self.rng.lock();
464 rl.next_u32()
465 }
466
467 fn next_u64(&mut self) -> u64 {
468 let mut rl = self.rng.lock();
469 rl.next_u64()
470 }
471
472 fn fill_bytes(&mut self, dest: &mut [u8]) {
473 let mut rl = self.rng.lock();
474 rl.fill_bytes(dest);
475 }
476
477 fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
478 let mut rl = self.rng.lock();
479 rl.try_fill_bytes(dest)
480 }
481}
482
483/// Unified RNG enum supporting multiple random number generator backends.
484///
485/// This enum provides a common interface over different RNG implementations, allowing
486/// users to choose the appropriate RNG for their use case while maintaining a consistent API.
487///
488/// # Variants
489///
490/// - `Std` - Standard RNG (`StdRng`) - Fast, suitable for general use, can be seeded for reproducibility
491/// - `Thread` - Thread-local RNG (`ThreadRng`) - Convenient, automatically seeded, thread-local
492/// - `OS` - Operating system RNG (`OsRng`) - Cryptographically secure, uses OS entropy
493/// - `Custom` - Custom RNG wrapper - For user-provided RNG implementations
494/// - `CustomRaw` - Raw custom RNG with Arc/Mutex - For advanced use cases
495/// - `CustomRawSend` - Send-safe raw custom RNG - For concurrent scenarios
496/// - `CustomCrypto` - Custom cryptographic RNG - For custom crypto implementations
497/// - `CustomCryptoRaw` - Raw custom crypto RNG - Advanced crypto use cases
498/// - `CustomCryptoRawSend` - Send-safe raw custom crypto RNG - Concurrent crypto scenarios
499///
500/// # Feature Flags
501///
502/// Different variants are available under different feature flags:
503/// - `Std` requires `core` or `send_only`
504/// - `Thread` and `OS` require `core`
505/// - Custom variants require `custom` or `custom_send_only`
506///
507/// # Examples
508///
509/// ```rust
510/// # #[cfg(feature = "core")]
511/// # {
512/// use product_os_random::{RNG, RngCore};
513/// use rand::SeedableRng;
514///
515/// // Create a seeded RNG for reproducible results
516/// let rng = RNG::Std(rand::rngs::StdRng::seed_from_u64(42));
517///
518/// // Or use OS randomness for cryptographic security
519/// let crypto_rng = RNG::OS(rand::rngs::OsRng);
520/// # }
521/// ```
522///
523/// # Performance
524///
525/// - `StdRng`: Fast, suitable for simulations and general use
526/// - `ThreadRng`: Fast, convenient, good default choice
527/// - `OsRng`: Slower but cryptographically secure
528/// - Custom variants: Performance depends on the wrapped RNG
529///
530/// # Size Note
531///
532/// This enum has a large size difference between variants (`StdRng` is ~312 bytes while others
533/// are ~16 bytes). This is intentional to avoid boxing and maintain API compatibility.
534#[cfg(feature = "rand")]
535#[allow(clippy::large_enum_variant)]
536#[derive(Clone)]
537pub enum RNG {
538 /// Standard RNG (`StdRng`) - Fast, can be seeded for reproducible results.
539 #[cfg(any(feature = "core", feature = "send_only"))]
540 Std(StdRng),
541 /// Thread-local RNG (`ThreadRng`) - Convenient, automatically seeded, thread-local.
542 /// Excluded when `send_only` is active since `ThreadRng` is not `Send`.
543 #[cfg(all(feature = "core", not(feature = "send_only")))]
544 Thread(ThreadRng),
545 /// Operating system RNG (`OsRng`) - Cryptographically secure, uses OS entropy.
546 #[cfg(feature = "core")]
547 OS(OsRng),
548 /// Custom RNG wrapper - For user-provided RNG implementations.
549 #[cfg(feature = "custom")]
550 Custom(CustomRng),
551 /// Raw custom RNG with Arc/Mutex - For advanced use cases.
552 #[cfg(feature = "custom")]
553 CustomRaw(Arc<spin::mutex::Mutex<dyn RngCore>>),
554 /// Send-safe raw custom RNG - For concurrent scenarios.
555 #[cfg(any(feature = "custom", feature = "custom_send_only"))]
556 CustomRawSend(Arc<spin::mutex::Mutex<dyn RngCore + Send>>),
557 /// Custom cryptographic RNG - For custom crypto implementations.
558 #[cfg(feature = "custom")]
559 CustomCrypto(CustomCryptoRng),
560 /// Raw custom crypto RNG - Advanced crypto use cases.
561 #[cfg(feature = "custom")]
562 CustomCryptoRaw(Arc<spin::mutex::Mutex<dyn RngCrypto>>),
563 /// Send-safe raw custom crypto RNG - Concurrent crypto scenarios.
564 #[cfg(any(feature = "custom", feature = "custom_send_only"))]
565 CustomCryptoRawSend(Arc<spin::mutex::Mutex<dyn RngCrypto + Send>>),
566}
567
568#[cfg(feature = "rand")]
569impl RngCore for RNG {
570 fn next_u32(&mut self) -> u32 {
571 match self {
572 #[cfg(any(feature = "core", feature = "send_only"))]
573 RNG::Std(r) => r.next_u32(),
574 #[cfg(all(feature = "core", not(feature = "send_only")))]
575 RNG::Thread(r) => r.next_u32(),
576 #[cfg(feature = "core")]
577 RNG::OS(r) => r.next_u32(),
578 #[cfg(feature = "custom")]
579 RNG::Custom(r) => r.next_u32(),
580 #[cfg(feature = "custom")]
581 RNG::CustomRaw(r) => {
582 let mut rl = r.lock();
583 rl.next_u32()
584 }
585 #[cfg(any(feature = "custom", feature = "custom_send_only"))]
586 RNG::CustomRawSend(r) => {
587 let mut rl = r.lock();
588 rl.next_u32()
589 }
590 #[cfg(feature = "custom")]
591 RNG::CustomCrypto(r) => r.next_u32(),
592 #[cfg(feature = "custom")]
593 RNG::CustomCryptoRaw(r) => {
594 let mut rl = r.lock();
595 rl.next_u32()
596 }
597 #[cfg(any(feature = "custom", feature = "custom_send_only"))]
598 RNG::CustomCryptoRawSend(r) => {
599 let mut rl = r.lock();
600 rl.next_u32()
601 }
602 _ => panic!("No known random generator"),
603 }
604 }
605
606 fn next_u64(&mut self) -> u64 {
607 match self {
608 #[cfg(any(feature = "core", feature = "send_only"))]
609 RNG::Std(r) => r.next_u64(),
610 #[cfg(all(feature = "core", not(feature = "send_only")))]
611 RNG::Thread(r) => r.next_u64(),
612 #[cfg(feature = "core")]
613 RNG::OS(r) => r.next_u64(),
614 #[cfg(feature = "custom")]
615 RNG::Custom(r) => r.next_u64(),
616 #[cfg(feature = "custom")]
617 RNG::CustomRaw(r) => {
618 let mut rl = r.lock();
619 rl.next_u64()
620 }
621 #[cfg(any(feature = "custom", feature = "custom_send_only"))]
622 RNG::CustomRawSend(r) => {
623 let mut rl = r.lock();
624 rl.next_u64()
625 }
626 #[cfg(feature = "custom")]
627 RNG::CustomCrypto(r) => r.next_u64(),
628 #[cfg(feature = "custom")]
629 RNG::CustomCryptoRaw(r) => {
630 let mut rl = r.lock();
631 rl.next_u64()
632 }
633 #[cfg(any(feature = "custom", feature = "custom_send_only"))]
634 RNG::CustomCryptoRawSend(r) => {
635 let mut rl = r.lock();
636 rl.next_u64()
637 }
638 _ => panic!("No known random generator"),
639 }
640 }
641
642 #[allow(unused_variables)]
643 fn fill_bytes(&mut self, dest: &mut [u8]) {
644 match self {
645 #[cfg(any(feature = "core", feature = "send_only"))]
646 RNG::Std(r) => r.fill_bytes(dest),
647 #[cfg(all(feature = "core", not(feature = "send_only")))]
648 RNG::Thread(r) => r.fill_bytes(dest),
649 #[cfg(feature = "core")]
650 RNG::OS(r) => r.fill_bytes(dest),
651 #[cfg(feature = "custom")]
652 RNG::Custom(r) => r.fill_bytes(dest),
653 #[cfg(feature = "custom")]
654 RNG::CustomRaw(r) => {
655 let mut rl = r.lock();
656 rl.fill_bytes(dest);
657 }
658 #[cfg(any(feature = "custom", feature = "custom_send_only"))]
659 RNG::CustomRawSend(r) => {
660 let mut rl = r.lock();
661 rl.fill_bytes(dest);
662 }
663 #[cfg(feature = "custom")]
664 RNG::CustomCrypto(r) => r.fill_bytes(dest),
665 #[cfg(feature = "custom")]
666 RNG::CustomCryptoRaw(r) => {
667 let mut rl = r.lock();
668 rl.fill_bytes(dest);
669 }
670 #[cfg(any(feature = "custom", feature = "custom_send_only"))]
671 RNG::CustomCryptoRawSend(r) => {
672 let mut rl = r.lock();
673 rl.fill_bytes(dest);
674 }
675 _ => panic!("No known random generator"),
676 }
677 }
678
679 #[allow(unused_variables)]
680 fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
681 match self {
682 #[cfg(any(feature = "core", feature = "send_only"))]
683 RNG::Std(r) => r.try_fill_bytes(dest),
684 #[cfg(all(feature = "core", not(feature = "send_only")))]
685 RNG::Thread(r) => r.try_fill_bytes(dest),
686 #[cfg(feature = "core")]
687 RNG::OS(r) => r.try_fill_bytes(dest),
688 #[cfg(feature = "custom")]
689 RNG::Custom(r) => r.try_fill_bytes(dest),
690 #[cfg(feature = "custom")]
691 RNG::CustomRaw(r) => {
692 let mut rl = r.lock();
693 rl.try_fill_bytes(dest)
694 }
695 #[cfg(any(feature = "custom", feature = "custom_send_only"))]
696 RNG::CustomRawSend(r) => {
697 let mut rl = r.lock();
698 rl.try_fill_bytes(dest)
699 }
700 #[cfg(feature = "custom")]
701 RNG::CustomCrypto(r) => r.try_fill_bytes(dest),
702 #[cfg(feature = "custom")]
703 RNG::CustomCryptoRaw(r) => {
704 let mut rl = r.lock();
705 rl.try_fill_bytes(dest)
706 }
707 #[cfg(any(feature = "custom", feature = "custom_send_only"))]
708 RNG::CustomCryptoRawSend(r) => {
709 let mut rl = r.lock();
710 rl.try_fill_bytes(dest)
711 }
712 _ => panic!("No known random generator"),
713 }
714 }
715}
716
717/// Unified cryptographically secure RNG enum.
718///
719/// Similar to `RNG`, but all variants implement the `CryptoRng` marker trait, indicating
720/// they are suitable for security-sensitive operations.
721///
722/// # Security Guarantee
723///
724/// All variants of this enum provide cryptographically secure random number generation,
725/// suitable for:
726/// - Key generation
727/// - Password creation
728/// - Security tokens
729/// - Cryptographic nonces
730/// - Any security-critical random data
731///
732/// # Variants
733///
734/// - `Std` - `StdRng` (when used with proper entropy source)
735/// - `Thread` - `ThreadRng` (cryptographically secure)
736/// - `OS` - `OsRng` (uses OS-provided cryptographic RNG)
737/// - `CustomCrypto` - Custom crypto RNG wrapper
738/// - `CustomCryptoRaw` - Raw custom crypto RNG
739/// - `CustomCryptoRawSend` - Send-safe raw custom crypto RNG
740///
741/// # Examples
742///
743/// ```rust
744/// # #[cfg(feature = "core")]
745/// # {
746/// use product_os_random::{CryptoRNG, RngCore, CryptoRng};
747///
748/// // Use OS randomness for maximum security
749/// let mut rng = CryptoRNG::OS(rand::rngs::OsRng);
750///
751/// // Generate cryptographically secure random bytes
752/// let mut key = [0u8; 32];
753/// rng.fill_bytes(&mut key);
754/// # }
755/// ```
756///
757/// # Performance
758///
759/// Cryptographic RNGs are generally slower than non-cryptographic ones, as they
760/// must maintain security properties. `OsRng` may block if entropy is not available.
761///
762/// # Size Note
763///
764/// This enum has a large size difference between variants (`StdRng` is ~312 bytes while others
765/// are ~16 bytes). This is intentional to avoid boxing and maintain API compatibility.
766#[cfg(feature = "rand")]
767#[allow(clippy::large_enum_variant)]
768#[derive(Clone)]
769pub enum CryptoRNG {
770 /// Standard RNG (`StdRng`) - When used with proper entropy source.
771 #[cfg(any(feature = "core", feature = "send_only"))]
772 Std(StdRng),
773 /// Thread-local RNG (`ThreadRng`) - Cryptographically secure.
774 /// Excluded when `send_only` is active since `ThreadRng` is not `Send`.
775 #[cfg(all(feature = "core", not(feature = "send_only")))]
776 Thread(ThreadRng),
777 /// Operating system RNG (`OsRng`) - Uses OS-provided cryptographic RNG.
778 #[cfg(feature = "core")]
779 OS(OsRng),
780 /// Custom cryptographic RNG wrapper.
781 #[cfg(feature = "custom")]
782 CustomCrypto(CustomCryptoRng),
783 /// Raw custom crypto RNG with Arc/Mutex.
784 #[cfg(feature = "custom")]
785 CustomCryptoRaw(Arc<spin::mutex::Mutex<dyn RngCrypto>>),
786 /// Send-safe raw custom crypto RNG.
787 #[cfg(any(feature = "custom", feature = "custom_send_only"))]
788 CustomCryptoRawSend(Arc<spin::mutex::Mutex<dyn RngCrypto + Send>>),
789}
790
791#[cfg(feature = "rand")]
792impl CryptoRng for CryptoRNG {}
793
794#[cfg(feature = "rand")]
795impl RngCore for CryptoRNG {
796 fn next_u32(&mut self) -> u32 {
797 match self {
798 #[cfg(any(feature = "core", feature = "send_only"))]
799 CryptoRNG::Std(r) => r.next_u32(),
800 #[cfg(all(feature = "core", not(feature = "send_only")))]
801 CryptoRNG::Thread(r) => r.next_u32(),
802 #[cfg(feature = "core")]
803 CryptoRNG::OS(r) => r.next_u32(),
804 #[cfg(feature = "custom")]
805 CryptoRNG::CustomCrypto(r) => r.next_u32(),
806 #[cfg(feature = "custom")]
807 CryptoRNG::CustomCryptoRaw(r) => {
808 let mut rl = r.lock();
809 rl.next_u32()
810 }
811 #[cfg(any(feature = "custom", feature = "custom_send_only"))]
812 CryptoRNG::CustomCryptoRawSend(r) => {
813 let mut rl = r.lock();
814 rl.next_u32()
815 }
816 _ => panic!("No known random generator"),
817 }
818 }
819
820 fn next_u64(&mut self) -> u64 {
821 match self {
822 #[cfg(any(feature = "core", feature = "send_only"))]
823 CryptoRNG::Std(r) => r.next_u64(),
824 #[cfg(all(feature = "core", not(feature = "send_only")))]
825 CryptoRNG::Thread(r) => r.next_u64(),
826 #[cfg(feature = "core")]
827 CryptoRNG::OS(r) => r.next_u64(),
828 #[cfg(feature = "custom")]
829 CryptoRNG::CustomCrypto(r) => r.next_u64(),
830 #[cfg(feature = "custom")]
831 CryptoRNG::CustomCryptoRaw(r) => {
832 let mut rl = r.lock();
833 rl.next_u64()
834 }
835 #[cfg(any(feature = "custom", feature = "custom_send_only"))]
836 CryptoRNG::CustomCryptoRawSend(r) => {
837 let mut rl = r.lock();
838 rl.next_u64()
839 }
840 _ => panic!("No known random generator"),
841 }
842 }
843
844 #[allow(unused_variables)]
845 fn fill_bytes(&mut self, dest: &mut [u8]) {
846 match self {
847 #[cfg(any(feature = "core", feature = "send_only"))]
848 CryptoRNG::Std(r) => r.fill_bytes(dest),
849 #[cfg(all(feature = "core", not(feature = "send_only")))]
850 CryptoRNG::Thread(r) => r.fill_bytes(dest),
851 #[cfg(feature = "core")]
852 CryptoRNG::OS(r) => r.fill_bytes(dest),
853 #[cfg(feature = "custom")]
854 CryptoRNG::CustomCrypto(r) => r.fill_bytes(dest),
855 #[cfg(feature = "custom")]
856 CryptoRNG::CustomCryptoRaw(r) => {
857 let mut rl = r.lock();
858 rl.fill_bytes(dest);
859 }
860 #[cfg(any(feature = "custom", feature = "custom_send_only"))]
861 CryptoRNG::CustomCryptoRawSend(r) => {
862 let mut rl = r.lock();
863 rl.fill_bytes(dest);
864 }
865 _ => panic!("No known random generator"),
866 }
867 }
868
869 #[allow(unused_variables)]
870 fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
871 match self {
872 #[cfg(any(feature = "core", feature = "send_only"))]
873 CryptoRNG::Std(r) => r.try_fill_bytes(dest),
874 #[cfg(all(feature = "core", not(feature = "send_only")))]
875 CryptoRNG::Thread(r) => r.try_fill_bytes(dest),
876 #[cfg(feature = "core")]
877 CryptoRNG::OS(r) => r.try_fill_bytes(dest),
878 #[cfg(feature = "custom")]
879 CryptoRNG::CustomCrypto(r) => r.try_fill_bytes(dest),
880 #[cfg(feature = "custom")]
881 CryptoRNG::CustomCryptoRaw(r) => {
882 let mut rl = r.lock();
883 rl.try_fill_bytes(dest)
884 }
885 #[cfg(any(feature = "custom", feature = "custom_send_only"))]
886 CryptoRNG::CustomCryptoRawSend(r) => {
887 let mut rl = r.lock();
888 rl.try_fill_bytes(dest)
889 }
890 _ => panic!("No known random generator"),
891 }
892 }
893}
894
895/// High-level random data generator with stateful RNG.
896///
897/// `RandomGenerator` provides convenient methods for generating various types of random data
898/// while maintaining an internal RNG state. It implements the `RandomGeneratorTemplate` trait
899/// for instance methods and provides static methods for one-time generation.
900///
901/// # Usage Patterns
902///
903/// ## Stateful Generation
904///
905/// Create a generator once and reuse it for multiple operations:
906///
907/// ```rust
908/// # #[cfg(feature = "core")]
909/// # {
910/// use product_os_random::{RandomGenerator, RandomGeneratorTemplate};
911///
912/// let mut gen = RandomGenerator::new(None); // Uses default RNG
913/// let bytes1 = gen.get_random_bytes(10);
914/// let bytes2 = gen.get_random_bytes(10);
915/// let number = gen.get_random_usize(1, 100);
916/// # }
917/// ```
918///
919/// ## One-Time Generation
920///
921/// Use static methods for single random values without maintaining state:
922///
923/// ```rust
924/// # #[cfg(feature = "core")]
925/// # {
926/// use product_os_random::RandomGenerator;
927///
928/// let password = RandomGenerator::get_simple_random_password_one_time(16);
929/// let alphanumeric = RandomGenerator::get_simple_random_alphanumeric_one_time(10);
930/// # }
931/// ```
932///
933/// # Feature-Gated Behavior
934///
935/// - With `core` or `send_only`: Can create generator without providing RNG (uses `StdRng::from_entropy()`)
936/// - With `constrained` only: Must provide an RNG, panics if None given
937///
938/// # Panics
939///
940/// Methods will panic in `constrained` mode if no RNG is provided. In `core` or `send_only` modes,
941/// a default RNG is used when None is provided.
942#[cfg(feature = "rand")]
943#[derive(Clone)]
944pub struct RandomGenerator {
945 generator: RNG,
946}
947
948#[cfg(any(feature = "constrained", feature = "core", feature = "send_only"))]
949impl RandomGenerator {
950 /// Creates a new `RandomGenerator` with the provided RNG, or uses a default RNG.
951 ///
952 /// # Arguments
953 ///
954 /// * `gen` - Optional RNG to use. If `None` is provided:
955 /// - In `core` or `send_only` mode: Uses `StdRng::from_entropy()`
956 /// - In `constrained` mode: Panics with "No generator provided"
957 ///
958 /// # Examples
959 ///
960 /// ```rust
961 /// # #[cfg(feature = "core")]
962 /// # {
963 /// use product_os_random::{RandomGenerator, RNG};
964 /// use rand::SeedableRng;
965 ///
966 /// // With custom RNG
967 /// let rng = RNG::Std(rand::rngs::StdRng::seed_from_u64(42));
968 /// let gen = RandomGenerator::new(Some(rng));
969 ///
970 /// // With default RNG (core/send_only only)
971 /// let gen2 = RandomGenerator::new(None);
972 /// # }
973 /// ```
974 ///
975 /// # Panics
976 ///
977 /// Panics in `constrained` mode if `gen` is `None`.
978 pub fn new(gen: Option<RNG>) -> Self {
979 let generator = {
980 #[cfg(all(
981 feature = "constrained",
982 all(not(feature = "core"), not(feature = "send_only"))
983 ))]
984 {
985 match gen {
986 Some(g) => g,
987 None => panic!("No generator provided"),
988 }
989 }
990 #[cfg(any(feature = "core", feature = "send_only"))]
991 {
992 gen.unwrap_or_else(|| RNG::Std(StdRng::from_entropy()))
993 }
994 };
995
996 Self { generator }
997 }
998
999 /// Generates a cryptographic key of the specified length (simple version, no custom RNG).
1000 ///
1001 /// This is a convenience method that generates a key without requiring an RNG parameter.
1002 /// Uses `StdRng::from_entropy()` in `core`/`send_only` mode.
1003 ///
1004 /// # Arguments
1005 ///
1006 /// * `len` - Length of the key in bytes
1007 ///
1008 /// # Returns
1009 ///
1010 /// A `Vec<u8>` containing `len` random bytes suitable for cryptographic use.
1011 ///
1012 /// # Examples
1013 ///
1014 /// ```rust
1015 /// # #[cfg(feature = "core")]
1016 /// # {
1017 /// use product_os_random::RandomGenerator;
1018 ///
1019 /// let key = RandomGenerator::generate_simple_key_one_time(32);
1020 /// assert_eq!(key.len(), 32);
1021 /// # }
1022 /// ```
1023 pub fn generate_simple_key_one_time(len: usize) -> Vec<u8> {
1024 RandomGenerator::generate_key_one_time(len, &mut None::<RNG>)
1025 }
1026
1027 /// Generates a cryptographic key of the specified length with an optional custom RNG.
1028 ///
1029 /// # Arguments
1030 ///
1031 /// * `len` - Length of the key in bytes
1032 /// * `gen` - Optional RNG to use. If `None`, uses default RNG (in `core`/`send_only` mode)
1033 ///
1034 /// # Returns
1035 ///
1036 /// A `Vec<u8>` containing `len` random bytes.
1037 ///
1038 /// # Panics
1039 ///
1040 /// Panics in `constrained` mode if `gen` is `None`.
1041 ///
1042 /// # Examples
1043 ///
1044 /// ```rust
1045 /// # #[cfg(feature = "core")]
1046 /// # {
1047 /// use product_os_random::RandomGenerator;
1048 /// use rand::SeedableRng;
1049 ///
1050 /// let mut rng = Some(rand::rngs::StdRng::seed_from_u64(42));
1051 /// let key = RandomGenerator::generate_key_one_time(32, &mut rng);
1052 /// assert_eq!(key.len(), 32);
1053 /// # }
1054 /// ```
1055 pub fn generate_key_one_time(len: usize, gen: &mut Option<impl RngCore>) -> Vec<u8> {
1056 #[cfg(all(
1057 feature = "constrained",
1058 all(not(feature = "core"), not(feature = "send_only"))
1059 ))]
1060 {
1061 match gen {
1062 Some(rng) => {
1063 let mut key = Vec::with_capacity(len);
1064 for _ in 0..len {
1065 key.push(rng.gen());
1066 }
1067 key
1068 }
1069 None => panic!("No generator provided"),
1070 }
1071 }
1072 #[cfg(any(feature = "core", feature = "send_only"))]
1073 {
1074 if let Some(rng) = gen {
1075 let mut key = Vec::with_capacity(len);
1076 for _ in 0..len {
1077 key.push(rng.gen());
1078 }
1079 key
1080 } else {
1081 let mut rng = StdRng::from_entropy();
1082 let mut key = Vec::with_capacity(len);
1083 for _ in 0..len {
1084 key.push(rng.gen());
1085 }
1086 key
1087 }
1088 }
1089 }
1090
1091 /// Generates random bytes (simple version, no custom RNG needed).
1092 ///
1093 /// This is a convenience wrapper around `get_random_bytes_one_time` that uses the default RNG.
1094 ///
1095 /// # Arguments
1096 ///
1097 /// * `len` - Number of bytes to generate
1098 ///
1099 /// # Returns
1100 ///
1101 /// A `Vec<u8>` containing `len` random bytes (0-255).
1102 pub fn get_simple_random_bytes_one_time(len: usize) -> Vec<u8> {
1103 RandomGenerator::get_random_bytes_one_time(len, &mut None::<RNG>)
1104 }
1105
1106 /// Generates random bytes with an optional custom RNG.
1107 ///
1108 /// # Arguments
1109 ///
1110 /// * `len` - Number of bytes to generate
1111 /// * `gen` - Optional RNG to use. If `None`, uses default RNG (in `core`/`send_only` mode)
1112 ///
1113 /// # Returns
1114 ///
1115 /// A `Vec<u8>` containing `len` random bytes (0-255).
1116 ///
1117 /// # Panics
1118 ///
1119 /// Panics in `constrained` mode if `gen` is `None`.
1120 pub fn get_random_bytes_one_time(len: usize, gen: &mut Option<impl RngCore>) -> Vec<u8> {
1121 let mut bytes = vec![0u8; len];
1122 #[cfg(all(
1123 feature = "constrained",
1124 all(not(feature = "core"), not(feature = "send_only"))
1125 ))]
1126 {
1127 match gen {
1128 Some(rng) => {
1129 rng.fill_bytes(&mut bytes);
1130 }
1131 None => panic!("No generator provided"),
1132 }
1133 }
1134 #[cfg(any(feature = "core", feature = "send_only"))]
1135 {
1136 if let Some(rng) = gen {
1137 rng.fill_bytes(&mut bytes);
1138 } else {
1139 let mut rng = StdRng::from_entropy();
1140 rng.fill_bytes(&mut bytes);
1141 }
1142 }
1143 bytes
1144 }
1145
1146 /// Generates a random `usize` within range (simple version, no custom RNG).
1147 ///
1148 /// This is a convenience method that generates a random number without requiring an RNG parameter.
1149 ///
1150 /// # Arguments
1151 ///
1152 /// * `min` - Minimum value (inclusive)
1153 /// * `max` - Maximum value (inclusive)
1154 ///
1155 /// # Returns
1156 ///
1157 /// A random `usize` in the range `[min, max]`.
1158 pub fn get_simple_random_usize_one_time(min: usize, max: usize) -> usize {
1159 RandomGenerator::get_random_usize_one_time(min, max, &mut None::<RNG>)
1160 }
1161
1162 /// Generates a random `usize` within range with an optional custom RNG.
1163 ///
1164 /// # Arguments
1165 ///
1166 /// * `min` - Minimum value (inclusive)
1167 /// * `max` - Maximum value (inclusive)
1168 /// * `gen` - Optional RNG to use. If `None`, uses default RNG (in `core`/`send_only` mode)
1169 ///
1170 /// # Returns
1171 ///
1172 /// A random `usize` in the range `[min, max]`.
1173 ///
1174 /// # Panics
1175 ///
1176 /// Panics in `constrained` mode if `gen` is `None`.
1177 pub fn get_random_usize_one_time(
1178 min: usize,
1179 max: usize,
1180 gen: &mut Option<impl RngCore>,
1181 ) -> usize {
1182 #[cfg(all(
1183 feature = "constrained",
1184 all(not(feature = "core"), not(feature = "send_only"))
1185 ))]
1186 {
1187 match gen {
1188 Some(rng) => rng.gen_range(min..=max),
1189 None => panic!("No generator provided"),
1190 }
1191 }
1192 #[cfg(any(feature = "core", feature = "send_only"))]
1193 {
1194 if let Some(rng) = gen {
1195 rng.gen_range(min..=max)
1196 } else {
1197 let mut rng = StdRng::from_entropy();
1198 rng.gen_range(min..=max)
1199 }
1200 }
1201 }
1202
1203 /// Generates a random string of printable ASCII characters (simple version).
1204 ///
1205 /// Generates a string containing random printable ASCII characters in the ranges:
1206 /// - Letters (a-z, A-Z)
1207 /// - Numbers (0-9)
1208 ///
1209 /// Special characters and symbols are excluded through character range filtering.
1210 ///
1211 /// # Arguments
1212 ///
1213 /// * `len` - Length of the string
1214 ///
1215 /// # Returns
1216 ///
1217 /// A `String` of length `len` containing random printable characters.
1218 ///
1219 /// # Examples
1220 ///
1221 /// ```rust
1222 /// # #[cfg(feature = "core")]
1223 /// # {
1224 /// use product_os_random::RandomGenerator;
1225 ///
1226 /// let s = RandomGenerator::get_simple_random_string_one_time(10);
1227 /// assert_eq!(s.len(), 10);
1228 /// # }
1229 /// ```
1230 pub fn get_simple_random_string_one_time(len: usize) -> String {
1231 RandomGenerator::get_random_string_one_time(len, &mut None::<RNG>)
1232 }
1233
1234 /// Generates a random string of printable ASCII characters with optional custom RNG.
1235 ///
1236 /// Character generation uses ASCII codes 33-122, with filtering to exclude certain
1237 /// special characters and symbols, resulting in alphanumeric and common punctuation.
1238 ///
1239 /// # Arguments
1240 ///
1241 /// * `len` - Length of the string
1242 /// * `gen` - Optional RNG to use. If `None`, uses default RNG (in `core`/`send_only` mode)
1243 ///
1244 /// # Returns
1245 ///
1246 /// A `String` of length `len` containing random characters.
1247 ///
1248 /// # Panics
1249 ///
1250 /// Panics in `constrained` mode if `gen` is `None`.
1251 pub fn get_random_string_one_time(len: usize, gen: &mut Option<impl RngCore>) -> String {
1252 let mut str = String::with_capacity(len);
1253 #[cfg(all(
1254 feature = "constrained",
1255 all(not(feature = "core"), not(feature = "send_only"))
1256 ))]
1257 {
1258 match gen {
1259 Some(rng) => {
1260 for _ in 0..len {
1261 let value: u8 = rng.gen_range(33..=122);
1262 let filtered = filter_printable_char(value);
1263 str.push(char::from(filtered));
1264 }
1265 }
1266 None => panic!("No generator provided"),
1267 }
1268 }
1269 #[cfg(any(feature = "core", feature = "send_only"))]
1270 {
1271 if let Some(rng) = gen {
1272 for _ in 0..len {
1273 let value: u8 = rng.gen_range(33..=122);
1274 let filtered = filter_printable_char(value);
1275 str.push(char::from(filtered));
1276 }
1277 } else {
1278 let mut rng = StdRng::from_entropy();
1279 for _ in 0..len {
1280 let value: u8 = rng.gen_range(33..=122);
1281 let filtered = filter_printable_char(value);
1282 str.push(char::from(filtered));
1283 }
1284 }
1285 }
1286 str
1287 }
1288
1289 /// Generates a random string from a character set (simple version, no custom RNG).
1290 ///
1291 /// # Arguments
1292 ///
1293 /// * `len` - Length of the string
1294 /// * `characters` - String containing the character set to choose from
1295 ///
1296 /// # Returns
1297 ///
1298 /// A `String` of length `len` with characters randomly selected from `characters`.
1299 pub fn get_simple_random_from_characters_one_time(len: usize, characters: &str) -> String {
1300 RandomGenerator::get_random_from_characters_one_time(len, characters, &mut None::<RNG>)
1301 }
1302
1303 /// Generates a random string from a character set with an optional custom RNG.
1304 ///
1305 /// # Arguments
1306 ///
1307 /// * `len` - Length of the string
1308 /// * `characters` - String containing the character set to choose from
1309 /// * `gen` - Optional RNG to use. If `None`, uses default RNG (in `core`/`send_only` mode)
1310 ///
1311 /// # Returns
1312 ///
1313 /// A `String` of length `len` with characters randomly selected from `characters`.
1314 ///
1315 /// # Panics
1316 ///
1317 /// Panics in `constrained` mode if `gen` is `None`.
1318 /// May panic if `characters` is empty.
1319 pub fn get_random_from_characters_one_time(
1320 len: usize,
1321 characters: &str,
1322 gen: &mut Option<impl RngCore>,
1323 ) -> String {
1324 let mut str = String::with_capacity(len);
1325 let char_vec: Vec<char> = characters.chars().collect();
1326 let char_count = char_vec.len();
1327
1328 #[cfg(all(
1329 feature = "constrained",
1330 all(not(feature = "core"), not(feature = "send_only"))
1331 ))]
1332 {
1333 match gen {
1334 Some(rng) => {
1335 for _ in 0..len {
1336 let ch = char_vec[rng.gen_range(0..char_count)];
1337 str.push(ch);
1338 }
1339 }
1340 None => panic!("No generator provided"),
1341 }
1342 }
1343 #[cfg(any(feature = "core", feature = "send_only"))]
1344 {
1345 if let Some(rng) = gen {
1346 for _ in 0..len {
1347 let ch = char_vec[rng.gen_range(0..char_count)];
1348 str.push(ch);
1349 }
1350 } else {
1351 let mut rng = StdRng::from_entropy();
1352 for _ in 0..len {
1353 let ch = char_vec[rng.gen_range(0..char_count)];
1354 str.push(ch);
1355 }
1356 }
1357 }
1358
1359 str
1360 }
1361
1362 /// Generates a random alphanumeric string (simple version).
1363 ///
1364 /// Creates a string containing only letters (a-z, A-Z) and digits (0-9).
1365 /// Suitable for identifiers, codes, and non-security-critical tokens.
1366 ///
1367 /// # Arguments
1368 ///
1369 /// * `len` - Length of the string
1370 ///
1371 /// # Returns
1372 ///
1373 /// A `String` of length `len` containing random alphanumeric characters.
1374 ///
1375 /// # Examples
1376 ///
1377 /// ```rust
1378 /// # #[cfg(feature = "core")]
1379 /// # {
1380 /// use product_os_random::RandomGenerator;
1381 ///
1382 /// let code = RandomGenerator::get_simple_random_alphanumeric_one_time(10);
1383 /// assert_eq!(code.len(), 10);
1384 /// assert!(code.chars().all(|c| c.is_alphanumeric()));
1385 /// # }
1386 /// ```
1387 pub fn get_simple_random_alphanumeric_one_time(len: usize) -> String {
1388 RandomGenerator::get_random_alphanumeric_one_time(len, &mut None::<RNG>)
1389 }
1390
1391 /// Generates a random alphanumeric string with an optional custom RNG.
1392 ///
1393 /// Creates a string containing only letters (a-z, A-Z) and digits (0-9).
1394 ///
1395 /// # Arguments
1396 ///
1397 /// * `len` - Length of the string
1398 /// * `gen` - Optional RNG to use. If `None`, uses default RNG (in `core`/`send_only` mode)
1399 ///
1400 /// # Returns
1401 ///
1402 /// A `String` of length `len` containing only alphanumeric characters.
1403 ///
1404 /// # Panics
1405 ///
1406 /// Panics in `constrained` mode if `gen` is `None`.
1407 pub fn get_random_alphanumeric_one_time(len: usize, gen: &mut Option<impl RngCore>) -> String {
1408 let mut str = String::with_capacity(len);
1409 #[cfg(all(
1410 feature = "constrained",
1411 all(not(feature = "core"), not(feature = "send_only"))
1412 ))]
1413 {
1414 match gen {
1415 Some(rng) => {
1416 for _ in 0..len {
1417 let value: u8 = rng.gen_range(48..=122);
1418 let filtered = filter_alphanumeric_char(value);
1419 str.push(char::from(filtered));
1420 }
1421 }
1422 None => panic!("No generator provided"),
1423 }
1424 }
1425 #[cfg(any(feature = "core", feature = "send_only"))]
1426 {
1427 if let Some(rng) = gen {
1428 for _ in 0..len {
1429 let value: u8 = rng.gen_range(48..=122);
1430 let filtered = filter_alphanumeric_char(value);
1431 str.push(char::from(filtered));
1432 }
1433 } else {
1434 let mut rng = StdRng::from_entropy();
1435 for _ in 0..len {
1436 let value: u8 = rng.gen_range(48..=122);
1437 let filtered = filter_alphanumeric_char(value);
1438 str.push(char::from(filtered));
1439 }
1440 }
1441 }
1442 str
1443 }
1444
1445 /// Generates a random password string (simple version).
1446 ///
1447 /// Creates a password containing a wide range of printable ASCII characters (33-122),
1448 /// including letters, digits, and special characters.
1449 ///
1450 /// # Security Note
1451 ///
1452 /// For production password generation, consider using `CryptoRNG` with `OsRng` to ensure
1453 /// cryptographic security.
1454 ///
1455 /// # Arguments
1456 ///
1457 /// * `len` - Length of the password
1458 ///
1459 /// # Returns
1460 ///
1461 /// A `String` of length `len` containing random password characters.
1462 ///
1463 /// # Examples
1464 ///
1465 /// ```rust
1466 /// # #[cfg(feature = "core")]
1467 /// # {
1468 /// use product_os_random::RandomGenerator;
1469 ///
1470 /// let password = RandomGenerator::get_simple_random_password_one_time(16);
1471 /// assert_eq!(password.len(), 16);
1472 /// # }
1473 /// ```
1474 pub fn get_simple_random_password_one_time(len: usize) -> String {
1475 RandomGenerator::get_random_password_one_time(len, &mut None::<RNG>)
1476 }
1477
1478 /// Generates a random password string with an optional custom RNG.
1479 ///
1480 /// Creates a password containing a wide range of printable ASCII characters (33-122),
1481 /// including letters, digits, and special characters.
1482 ///
1483 /// # Security Note
1484 ///
1485 /// For production password generation, consider using `CryptoRNG` with `OsRng` to ensure
1486 /// cryptographic security.
1487 ///
1488 /// # Arguments
1489 ///
1490 /// * `len` - Length of the password
1491 /// * `gen` - Optional RNG to use. If `None`, uses default RNG (in `core`/`send_only` mode)
1492 ///
1493 /// # Returns
1494 ///
1495 /// A `String` of length `len` containing random password characters.
1496 ///
1497 /// # Panics
1498 ///
1499 /// Panics in `constrained` mode if `gen` is `None`.
1500 pub fn get_random_password_one_time(len: usize, gen: &mut Option<impl RngCore>) -> String {
1501 let mut str = String::with_capacity(len);
1502 #[cfg(all(
1503 feature = "constrained",
1504 all(not(feature = "core"), not(feature = "send_only"))
1505 ))]
1506 {
1507 match gen {
1508 Some(rng) => {
1509 for _ in 0..len {
1510 let value: u8 = rng.gen_range(33..=122);
1511 str.push(char::from(value));
1512 }
1513 }
1514 None => panic!("No generator provided"),
1515 }
1516 }
1517 #[cfg(any(feature = "core", feature = "send_only"))]
1518 {
1519 if let Some(rng) = gen {
1520 for _ in 0..len {
1521 let value: u8 = rng.gen_range(33..=122);
1522 str.push(char::from(value));
1523 }
1524 } else {
1525 let mut rng = StdRng::from_entropy();
1526 for _ in 0..len {
1527 let value: u8 = rng.gen_range(33..=122);
1528 str.push(char::from(value));
1529 }
1530 }
1531 }
1532 str
1533 }
1534
1535 /// Generates a random email address using a default RNG.
1536 ///
1537 /// This is a convenience wrapper around `get_random_email_one_time` that uses
1538 /// a default RNG instance.
1539 ///
1540 /// # Arguments
1541 ///
1542 /// * `num_names` - Optional number of name components (default: 2)
1543 /// * `num_numbers` - Optional number of numeric components (default: 0)
1544 /// * `separator` - Optional separator between components (default: ".")
1545 /// * `domains` - List of possible email domains to choose from
1546 ///
1547 /// # Returns
1548 ///
1549 /// A random email address string
1550 ///
1551 /// # Examples
1552 ///
1553 /// ```rust
1554 /// # #[cfg(all(feature = "core", feature = "names"))]
1555 /// # {
1556 /// use product_os_random::RandomGenerator;
1557 ///
1558 /// let email = RandomGenerator::get_simple_random_email_one_time(
1559 /// Some(2), Some(0), Some(".".to_string()), vec!["example.com".to_string()]
1560 /// );
1561 /// println!("Random email: {}", email);
1562 /// # }
1563 /// ```
1564 #[cfg(feature = "names")]
1565 pub fn get_simple_random_email_one_time(
1566 num_names: Option<usize>,
1567 num_numbers: Option<usize>,
1568 separator: Option<String>,
1569 domains: Vec<String>,
1570 ) -> String {
1571 RandomGenerator::get_random_email_one_time(
1572 num_names,
1573 num_numbers,
1574 separator,
1575 domains,
1576 &mut None::<RNG>,
1577 )
1578 }
1579
1580 /// Generates a random email address using the provided RNG.
1581 ///
1582 /// Creates an email address by combining random names, optional numbers, and
1583 /// a domain from the provided list.
1584 ///
1585 /// # Arguments
1586 ///
1587 /// * `num_names` - Optional number of name components (default: 2)
1588 /// * `num_numbers` - Optional number of numeric components (default: 0)
1589 /// * `separator` - Optional separator between components (default: ".")
1590 /// * `domains` - List of possible email domains to choose from
1591 /// * `gen` - Mutable reference to an optional RNG instance
1592 ///
1593 /// # Returns
1594 ///
1595 /// A random email address string
1596 #[cfg(feature = "names")]
1597 #[allow(clippy::needless_pass_by_value)] // Keep Vec<String> for API compatibility
1598 pub fn get_random_email_one_time(
1599 num_names: Option<usize>,
1600 num_numbers: Option<usize>,
1601 separator: Option<String>,
1602 domains: Vec<String>,
1603 gen: &mut Option<impl RngCore>,
1604 ) -> String {
1605 let num_names = num_names.unwrap_or(2);
1606
1607 let num_numbers = num_numbers.unwrap_or(3);
1608
1609 let separator = separator.unwrap_or_default();
1610
1611 let mut str = String::new();
1612
1613 let username = RandomGenerator::get_random_username_one_time(
1614 Some(num_names),
1615 Some(num_numbers),
1616 Some(separator.clone()),
1617 gen,
1618 );
1619
1620 str.push_str(username.as_str());
1621 str.push('@');
1622
1623 let num_domains = domains.len();
1624
1625 #[cfg(all(
1626 feature = "constrained",
1627 all(not(feature = "core"), not(feature = "send_only"))
1628 ))]
1629 {
1630 match gen {
1631 Some(rng) => {
1632 let pick_domain = rng.gen_range(0..num_domains);
1633 str.push_str(domains.get(pick_domain).unwrap().as_str());
1634 }
1635 None => panic!("No generator provided"),
1636 }
1637 }
1638 #[cfg(any(feature = "core", feature = "send_only"))]
1639 {
1640 if let Some(rng) = gen {
1641 let pick_domain = rng.gen_range(0..num_domains);
1642 str.push_str(domains.get(pick_domain).unwrap().as_str());
1643 } else {
1644 let mut rng = StdRng::from_entropy();
1645 let pick_domain = rng.gen_range(0..num_domains);
1646 str.push_str(domains.get(pick_domain).unwrap().as_str());
1647 }
1648 }
1649
1650 str
1651 }
1652
1653 /// Generates a random username using a default RNG.
1654 ///
1655 /// This is a convenience wrapper around `get_random_username_one_time` that uses
1656 /// a default RNG instance.
1657 ///
1658 /// # Arguments
1659 ///
1660 /// * `num_names` - Optional number of name components (default: 2)
1661 /// * `num_numbers` - Optional number of numeric components (default: 0)
1662 /// * `separator` - Optional separator between components (default: "_")
1663 ///
1664 /// # Returns
1665 ///
1666 /// A random username string
1667 ///
1668 /// # Examples
1669 ///
1670 /// ```rust
1671 /// # #[cfg(all(feature = "core", feature = "names"))]
1672 /// # {
1673 /// use product_os_random::RandomGenerator;
1674 ///
1675 /// let username = RandomGenerator::get_simple_random_username_one_time(
1676 /// Some(2), Some(3), Some("_".to_string())
1677 /// );
1678 /// println!("Random username: {}", username);
1679 /// # }
1680 /// ```
1681 #[cfg(feature = "names")]
1682 pub fn get_simple_random_username_one_time(
1683 num_names: Option<usize>,
1684 num_numbers: Option<usize>,
1685 separator: Option<String>,
1686 ) -> String {
1687 RandomGenerator::get_random_username_one_time(
1688 num_names,
1689 num_numbers,
1690 separator,
1691 &mut None::<RNG>,
1692 )
1693 }
1694
1695 /// Generates a random username using the provided RNG.
1696 ///
1697 /// Creates a username by combining random names and optional numbers with a separator.
1698 ///
1699 /// # Arguments
1700 ///
1701 /// * `num_names` - Optional number of name components (default: 2)
1702 /// * `num_numbers` - Optional number of numeric components (default: 0)
1703 /// * `separator` - Optional separator between components (default: "_")
1704 /// * `gen` - Mutable reference to an optional RNG instance
1705 ///
1706 /// # Returns
1707 ///
1708 /// A random username string
1709 #[cfg(feature = "names")]
1710 pub fn get_random_username_one_time(
1711 num_names: Option<usize>,
1712 num_numbers: Option<usize>,
1713 separator: Option<String>,
1714 gen: &mut Option<impl RngCore>,
1715 ) -> String {
1716 let names_count = names::NAMES.len();
1717
1718 let num_names = num_names.unwrap_or(2);
1719
1720 let num_numbers = num_numbers.unwrap_or(5);
1721
1722 let separator = separator.unwrap_or_default();
1723
1724 let mut str = String::new();
1725
1726 #[cfg(all(
1727 feature = "constrained",
1728 all(not(feature = "core"), not(feature = "send_only"))
1729 ))]
1730 {
1731 match gen {
1732 Some(rng) => {
1733 for counter in 0..num_names {
1734 let value: usize = rng.gen_range(0..names_count);
1735 if counter > 0 {
1736 str.push_str(separator.as_str());
1737 }
1738 str.push_str(names::NAMES[value].to_lowercase().as_str());
1739 }
1740
1741 if num_numbers > 0 {
1742 str.push_str(separator.as_str());
1743 }
1744
1745 for _ in 0..num_numbers {
1746 let value: u8 = rng.gen_range(48..57);
1747 str.push(char::from(value));
1748 }
1749 }
1750 None => panic!("No generator provided"),
1751 }
1752 }
1753 #[cfg(any(feature = "core", feature = "send_only"))]
1754 {
1755 if let Some(rng) = gen {
1756 for counter in 0..num_names {
1757 let value: usize = rng.gen_range(0..names_count);
1758 if counter > 0 {
1759 str.push_str(separator.as_str());
1760 }
1761 str.push_str(names::NAMES[value].to_lowercase().as_str());
1762 }
1763
1764 if num_numbers > 0 {
1765 str.push_str(separator.as_str());
1766 }
1767
1768 for _ in 0..num_numbers {
1769 let value: u8 = rng.gen_range(48..57);
1770 str.push(char::from(value));
1771 }
1772 } else {
1773 let mut rng = StdRng::from_entropy();
1774 for counter in 0..num_names {
1775 let value: usize = rng.gen_range(0..names_count);
1776 if counter > 0 {
1777 str.push_str(separator.as_str());
1778 }
1779 str.push_str(names::NAMES[value].to_lowercase().as_str());
1780 }
1781
1782 if num_numbers > 0 {
1783 str.push_str(separator.as_str());
1784 }
1785
1786 for _ in 0..num_numbers {
1787 let value: u8 = rng.gen_range(48..57);
1788 str.push(char::from(value));
1789 }
1790 }
1791 }
1792
1793 str
1794 }
1795
1796 /// Generates a random full name using a default RNG.
1797 ///
1798 /// This is a convenience wrapper around `get_random_name_one_time` that uses
1799 /// a default RNG instance.
1800 ///
1801 /// # Returns
1802 ///
1803 /// A random full name string (first name + last name)
1804 ///
1805 /// # Examples
1806 ///
1807 /// ```rust
1808 /// # #[cfg(all(feature = "core", feature = "names", feature = "first_names", feature = "last_names"))]
1809 /// # {
1810 /// use product_os_random::RandomGenerator;
1811 ///
1812 /// let name = RandomGenerator::get_simple_random_name_one_time();
1813 /// println!("Random name: {}", name);
1814 /// # }
1815 /// ```
1816 #[cfg(feature = "names")]
1817 pub fn get_simple_random_name_one_time() -> String {
1818 RandomGenerator::get_random_name_one_time(&mut None::<RNG>)
1819 }
1820
1821 /// Generates a random full name using the provided RNG.
1822 ///
1823 /// Creates a full name by combining a random first name and last name.
1824 ///
1825 /// # Arguments
1826 ///
1827 /// * `gen` - Mutable reference to an optional RNG instance
1828 ///
1829 /// # Returns
1830 ///
1831 /// A random full name string (first name + last name)
1832 #[cfg(feature = "names")]
1833 pub fn get_random_name_one_time(gen: &mut Option<impl RngCore>) -> String {
1834 let names_count = names::NAMES.len();
1835
1836 let mut str = String::new();
1837
1838 #[cfg(all(
1839 feature = "constrained",
1840 all(not(feature = "core"), not(feature = "send_only"))
1841 ))]
1842 {
1843 match gen {
1844 Some(rng) => {
1845 let value: usize = rng.gen_range(0..names_count);
1846 str.push_str(names::NAMES[value]);
1847 }
1848 None => panic!("No generator provided"),
1849 }
1850 }
1851 #[cfg(any(feature = "core", feature = "send_only"))]
1852 {
1853 if let Some(rng) = gen {
1854 let value: usize = rng.gen_range(0..names_count);
1855 str.push_str(names::NAMES[value]);
1856 } else {
1857 let mut rng = StdRng::from_entropy();
1858 let value: usize = rng.gen_range(0..names_count);
1859 str.push_str(names::NAMES[value]);
1860 }
1861 }
1862 str
1863 }
1864
1865 /// Generates a random first name using a default RNG.
1866 ///
1867 /// This is a convenience wrapper around `get_random_first_name_one_time` that uses
1868 /// a default RNG instance.
1869 ///
1870 /// # Returns
1871 ///
1872 /// A random first name string (capitalized)
1873 ///
1874 /// # Examples
1875 ///
1876 /// ```rust
1877 /// # #[cfg(all(feature = "core", feature = "names", feature = "first_names"))]
1878 /// # {
1879 /// use product_os_random::RandomGenerator;
1880 ///
1881 /// let first_name = RandomGenerator::get_simple_random_first_name_one_time();
1882 /// println!("Random first name: {}", first_name);
1883 /// # }
1884 /// ```
1885 #[cfg(feature = "names")]
1886 pub fn get_simple_random_first_name_one_time() -> String {
1887 RandomGenerator::get_random_first_name_one_time(&mut None::<RNG>)
1888 }
1889
1890 /// Generates a random first name using the provided RNG.
1891 ///
1892 /// Selects a random first name from the built-in dataset and capitalizes it.
1893 ///
1894 /// # Arguments
1895 ///
1896 /// * `gen` - Mutable reference to an optional RNG instance
1897 ///
1898 /// # Returns
1899 ///
1900 /// A random first name string (capitalized)
1901 #[cfg(feature = "first_names")]
1902 pub fn get_random_first_name_one_time(gen: &mut Option<impl RngCore>) -> String {
1903 let names_count = first_names::FIRSTNAMES.len();
1904
1905 let mut str = String::new();
1906
1907 #[cfg(all(
1908 feature = "constrained",
1909 all(not(feature = "core"), not(feature = "send_only"))
1910 ))]
1911 {
1912 match gen {
1913 Some(rng) => {
1914 let value: usize = rng.gen_range(0..names_count);
1915 str.push_str(to_title_case(first_names::FIRSTNAMES[value]).as_str());
1916 }
1917 None => panic!("No generator provided"),
1918 }
1919 }
1920 #[cfg(any(feature = "core", feature = "send_only"))]
1921 {
1922 if let Some(rng) = gen {
1923 let value: usize = rng.gen_range(0..names_count);
1924 str.push_str(to_title_case(first_names::FIRSTNAMES[value]).as_str());
1925 } else {
1926 let mut rng = StdRng::from_entropy();
1927 let value: usize = rng.gen_range(0..names_count);
1928 str.push_str(to_title_case(first_names::FIRSTNAMES[value]).as_str());
1929 }
1930 }
1931
1932 str
1933 }
1934
1935 /// Generates a random last name using a default RNG.
1936 ///
1937 /// This is a convenience wrapper around `get_random_last_name_one_time` that uses
1938 /// a default RNG instance.
1939 ///
1940 /// # Returns
1941 ///
1942 /// A random last name string (capitalized)
1943 ///
1944 /// # Examples
1945 ///
1946 /// ```rust
1947 /// # #[cfg(all(feature = "core", feature = "names", feature = "last_names"))]
1948 /// # {
1949 /// use product_os_random::RandomGenerator;
1950 ///
1951 /// let last_name = RandomGenerator::get_simple_random_last_name_one_time();
1952 /// println!("Random last name: {}", last_name);
1953 /// # }
1954 /// ```
1955 #[cfg(feature = "names")]
1956 pub fn get_simple_random_last_name_one_time() -> String {
1957 RandomGenerator::get_random_last_name_one_time(&mut None::<RNG>)
1958 }
1959
1960 /// Generates a random last name using the provided RNG.
1961 ///
1962 /// Selects a random last name from the built-in dataset and capitalizes it.
1963 ///
1964 /// # Arguments
1965 ///
1966 /// * `gen` - Mutable reference to an optional RNG instance
1967 ///
1968 /// # Returns
1969 ///
1970 /// A random last name string (capitalized)
1971 #[cfg(feature = "last_names")]
1972 pub fn get_random_last_name_one_time(gen: &mut Option<impl RngCore>) -> String {
1973 let names_count = last_names::LASTNAMES.len();
1974
1975 let mut str = String::new();
1976
1977 #[cfg(all(
1978 feature = "constrained",
1979 all(not(feature = "core"), not(feature = "send_only"))
1980 ))]
1981 {
1982 match gen {
1983 Some(rng) => {
1984 let value: usize = rng.gen_range(0..names_count);
1985 str.push_str(to_title_case(last_names::LASTNAMES[value]).as_str());
1986 }
1987 None => panic!("No generator provided"),
1988 }
1989 }
1990 #[cfg(any(feature = "core", feature = "send_only"))]
1991 {
1992 if let Some(rng) = gen {
1993 let value: usize = rng.gen_range(0..names_count);
1994 str.push_str(to_title_case(last_names::LASTNAMES[value]).as_str());
1995 } else {
1996 let mut rng = StdRng::from_entropy();
1997 let value: usize = rng.gen_range(0..names_count);
1998 str.push_str(to_title_case(last_names::LASTNAMES[value]).as_str());
1999 }
2000 }
2001
2002 str
2003 }
2004}
2005
2006#[cfg(feature = "rand")]
2007impl RandomGeneratorTemplate for RandomGenerator {
2008 fn get_random_bytes(&mut self, len: usize) -> Vec<u8> {
2009 let mut bytes = vec![0u8; len];
2010 self.generator.fill_bytes(&mut bytes);
2011 bytes
2012 }
2013
2014 fn get_random_usize(&mut self, min: usize, max: usize) -> usize {
2015 self.generator.gen_range(min..=max)
2016 }
2017
2018 fn get_random_u32(&mut self) -> u32 {
2019 self.generator.next_u32()
2020 }
2021
2022 fn get_random_u64(&mut self) -> u64 {
2023 self.generator.next_u64()
2024 }
2025
2026 fn get_random_string(&mut self, len: usize) -> String {
2027 let mut str = String::with_capacity(len);
2028 for _ in 0..len {
2029 let value: u8 = self.generator.gen_range(33..=122);
2030 let filtered = filter_printable_char(value);
2031 str.push(char::from(filtered));
2032 }
2033 str
2034 }
2035
2036 fn get_random_from_characters(&mut self, len: usize, characters: &str) -> String {
2037 let mut str = String::with_capacity(len);
2038 let char_vec: Vec<char> = characters.chars().collect();
2039 let char_count = char_vec.len();
2040
2041 for _ in 0..len {
2042 let ch = char_vec[self.generator.gen_range(0..char_count)];
2043 str.push(ch);
2044 }
2045
2046 str
2047 }
2048
2049 fn get_random_alphanumeric(&mut self, len: usize) -> String {
2050 let mut str = String::with_capacity(len);
2051 for _ in 0..len {
2052 let value: u8 = self.generator.gen_range(48..=122);
2053 let filtered = filter_alphanumeric_char(value);
2054 str.push(char::from(filtered));
2055 }
2056 str
2057 }
2058
2059 fn generate_key(&mut self, len: usize) -> Vec<u8> {
2060 let mut key = Vec::with_capacity(len);
2061 for _ in 0..len {
2062 key.push(self.generator.gen());
2063 }
2064 key
2065 }
2066}
2067
2068/// Template trait defining instance methods for random data generation.
2069///
2070/// This trait defines the interface for stateful random generation. Types implementing
2071/// this trait maintain an internal RNG state and provide methods for generating various
2072/// types of random data.
2073///
2074/// # Implementation
2075///
2076/// `RandomGenerator` implements this trait, providing all these methods as instance methods
2077/// that use the generator's internal RNG.
2078///
2079/// # Examples
2080///
2081/// ```rust
2082/// # #[cfg(feature = "core")]
2083/// # {
2084/// use product_os_random::{RandomGenerator, RandomGeneratorTemplate};
2085///
2086/// let mut gen = RandomGenerator::new(None);
2087///
2088/// // Generate various random data
2089/// let bytes = gen.get_random_bytes(16);
2090/// let number = gen.get_random_usize(1, 100);
2091/// let text = gen.get_random_string(20);
2092/// let alphanum = gen.get_random_alphanumeric(10);
2093/// let key = gen.generate_key(32);
2094/// # }
2095/// ```
2096pub trait RandomGeneratorTemplate {
2097 /// Generates a vector of random bytes.
2098 ///
2099 /// # Arguments
2100 ///
2101 /// * `len` - Number of bytes to generate
2102 ///
2103 /// # Returns
2104 ///
2105 /// A `Vec<u8>` containing `len` random bytes (0-255).
2106 fn get_random_bytes(&mut self, len: usize) -> Vec<u8>;
2107
2108 /// Generates a random `usize` within the specified range (inclusive).
2109 ///
2110 /// # Arguments
2111 ///
2112 /// * `min` - Minimum value (inclusive)
2113 /// * `max` - Maximum value (inclusive)
2114 ///
2115 /// # Returns
2116 ///
2117 /// A random `usize` in the range `[min, max]`.
2118 fn get_random_usize(&mut self, min: usize, max: usize) -> usize;
2119
2120 /// Generates a random `u32`.
2121 ///
2122 /// # Returns
2123 ///
2124 /// A random 32-bit unsigned integer.
2125 fn get_random_u32(&mut self) -> u32;
2126
2127 /// Generates a random `u64`.
2128 ///
2129 /// # Returns
2130 ///
2131 /// A random 64-bit unsigned integer.
2132 fn get_random_u64(&mut self) -> u64;
2133
2134 /// Generates a random string of printable characters.
2135 ///
2136 /// # Arguments
2137 ///
2138 /// * `len` - Length of the string
2139 ///
2140 /// # Returns
2141 ///
2142 /// A `String` containing `len` random printable characters.
2143 fn get_random_string(&mut self, len: usize) -> String;
2144
2145 /// Generates a random string from the provided character set.
2146 ///
2147 /// # Arguments
2148 ///
2149 /// * `len` - Length of the string
2150 /// * `characters` - String containing the character set to choose from
2151 ///
2152 /// # Returns
2153 ///
2154 /// A `String` of length `len` with characters randomly selected from `characters`.
2155 ///
2156 /// # Panics
2157 ///
2158 /// May panic if `characters` is empty or contains invalid UTF-8.
2159 fn get_random_from_characters(&mut self, len: usize, characters: &str) -> String;
2160
2161 /// Generates a random alphanumeric string.
2162 ///
2163 /// # Arguments
2164 ///
2165 /// * `len` - Length of the string
2166 ///
2167 /// # Returns
2168 ///
2169 /// A `String` of length `len` containing only letters (a-z, A-Z) and digits (0-9).
2170 fn get_random_alphanumeric(&mut self, len: usize) -> String;
2171
2172 /// Generates a cryptographic key.
2173 ///
2174 /// # Arguments
2175 ///
2176 /// * `len` - Length of the key in bytes
2177 ///
2178 /// # Returns
2179 ///
2180 /// A `Vec<u8>` containing `len` random bytes suitable for use as a cryptographic key.
2181 fn generate_key(&mut self, len: usize) -> Vec<u8>;
2182}
2183
2184// =============================================================================
2185// Top-level convenience functions
2186// =============================================================================
2187//
2188// These free functions provide the simplest possible API for one-time random
2189// generation. They use the default RNG internally and require no parameters
2190// beyond the generation settings.
2191
2192/// Generates a random `usize` within the specified range (inclusive).
2193///
2194/// # Arguments
2195///
2196/// * `min` - Minimum value (inclusive)
2197/// * `max` - Maximum value (inclusive)
2198///
2199/// # Returns
2200///
2201/// A random `usize` in the range `[min, max]`.
2202///
2203/// # Examples
2204///
2205/// ```rust
2206/// # #[cfg(feature = "core")]
2207/// # {
2208/// let value = product_os_random::random_usize(1, 100);
2209/// assert!((1..=100).contains(&value));
2210/// # }
2211/// ```
2212#[cfg(any(feature = "core", feature = "send_only", feature = "constrained"))]
2213pub fn random_usize(min: usize, max: usize) -> usize {
2214 RandomGenerator::get_simple_random_usize_one_time(min, max)
2215}
2216
2217/// Generates a random string of printable ASCII characters.
2218///
2219/// # Arguments
2220///
2221/// * `len` - Length of the string
2222///
2223/// # Returns
2224///
2225/// A `String` of length `len` containing random printable characters.
2226///
2227/// # Examples
2228///
2229/// ```rust
2230/// # #[cfg(feature = "core")]
2231/// # {
2232/// let s = product_os_random::random_string(10);
2233/// assert_eq!(s.len(), 10);
2234/// # }
2235/// ```
2236#[cfg(any(feature = "core", feature = "send_only", feature = "constrained"))]
2237pub fn random_string(len: usize) -> String {
2238 RandomGenerator::get_simple_random_string_one_time(len)
2239}
2240
2241/// Generates a random alphanumeric string (a-z, A-Z, 0-9).
2242///
2243/// # Arguments
2244///
2245/// * `len` - Length of the string
2246///
2247/// # Returns
2248///
2249/// A `String` of length `len` containing only alphanumeric characters.
2250///
2251/// # Examples
2252///
2253/// ```rust
2254/// # #[cfg(feature = "core")]
2255/// # {
2256/// let s = product_os_random::random_alphanumeric(10);
2257/// assert_eq!(s.len(), 10);
2258/// assert!(s.chars().all(|c| c.is_alphanumeric()));
2259/// # }
2260/// ```
2261#[cfg(any(feature = "core", feature = "send_only", feature = "constrained"))]
2262pub fn random_alphanumeric(len: usize) -> String {
2263 RandomGenerator::get_simple_random_alphanumeric_one_time(len)
2264}
2265
2266/// Generates random bytes.
2267///
2268/// # Arguments
2269///
2270/// * `len` - Number of bytes to generate
2271///
2272/// # Returns
2273///
2274/// A `Vec<u8>` containing `len` random bytes (0-255).
2275///
2276/// # Examples
2277///
2278/// ```rust
2279/// # #[cfg(feature = "core")]
2280/// # {
2281/// let bytes = product_os_random::random_bytes(16);
2282/// assert_eq!(bytes.len(), 16);
2283/// # }
2284/// ```
2285#[cfg(any(feature = "core", feature = "send_only", feature = "constrained"))]
2286pub fn random_bytes(len: usize) -> Vec<u8> {
2287 RandomGenerator::get_simple_random_bytes_one_time(len)
2288}
2289
2290/// Generates a random password string of printable ASCII characters.
2291///
2292/// # Arguments
2293///
2294/// * `len` - Length of the password
2295///
2296/// # Returns
2297///
2298/// A `String` of length `len` containing random characters suitable for passwords.
2299///
2300/// # Examples
2301///
2302/// ```rust
2303/// # #[cfg(feature = "core")]
2304/// # {
2305/// let pw = product_os_random::random_password(16);
2306/// assert_eq!(pw.len(), 16);
2307/// # }
2308/// ```
2309#[cfg(any(feature = "core", feature = "send_only", feature = "constrained"))]
2310pub fn random_password(len: usize) -> String {
2311 RandomGenerator::get_simple_random_password_one_time(len)
2312}
2313
2314/// Generates a random string from a given character set.
2315///
2316/// # Arguments
2317///
2318/// * `len` - Length of the string
2319/// * `characters` - String containing the character set to choose from
2320///
2321/// # Returns
2322///
2323/// A `String` of length `len` with characters randomly selected from `characters`.
2324///
2325/// # Examples
2326///
2327/// ```rust
2328/// # #[cfg(feature = "core")]
2329/// # {
2330/// let s = product_os_random::random_from_characters(8, "abc123");
2331/// assert_eq!(s.len(), 8);
2332/// assert!(s.chars().all(|c| "abc123".contains(c)));
2333/// # }
2334/// ```
2335#[cfg(any(feature = "core", feature = "send_only", feature = "constrained"))]
2336pub fn random_from_characters(len: usize, characters: &str) -> String {
2337 RandomGenerator::get_simple_random_from_characters_one_time(len, characters)
2338}
2339
2340/// Generates a cryptographic key of the specified length.
2341///
2342/// # Arguments
2343///
2344/// * `len` - Length of the key in bytes
2345///
2346/// # Returns
2347///
2348/// A `Vec<u8>` containing `len` random bytes suitable for cryptographic use.
2349///
2350/// # Examples
2351///
2352/// ```rust
2353/// # #[cfg(feature = "core")]
2354/// # {
2355/// let key = product_os_random::generate_random_key(32);
2356/// assert_eq!(key.len(), 32);
2357/// # }
2358/// ```
2359#[cfg(any(feature = "core", feature = "send_only", feature = "constrained"))]
2360pub fn generate_random_key(len: usize) -> Vec<u8> {
2361 RandomGenerator::generate_simple_key_one_time(len)
2362}