macro_toolset/string/
rand.rs1use rand::{distributions::Slice, Rng};
4
5use super::{NumStr, StringExtT, StringT};
6use crate::random::fast_random;
7
8#[macro_export]
9macro_rules! random_str {
29 ($range:expr, $charset:expr) => {{
30 $crate::string::rand::RandStr::<$range>::with_charset($charset)
31 }};
32 (HEX) => {{
33 $crate::string::rand::RandHexStr::new_default()
34 }};
35 (HEX: $l:expr) => {{
36 $crate::string::rand::RandHexStr::<$l>::new()
37 }};
38 (HEX: $l:expr, $rp:expr) => {{
39 $crate::string::rand::RandHexStr::<$l, $rp>::new()
40 }};
41 (HEX: $l:expr, $rp:expr, $lp:expr) => {{
42 $crate::string::rand::RandHexStr::<$l, $rp, $lp>::new()
43 }};
44}
45
46#[derive(Debug, Clone, Copy, Default)]
47pub struct RandHexStr<const L: usize = 16, const RP: usize = 1, const LP: usize = 0>;
69
70impl<const L: usize, const RP: usize, const LP: usize> StringT for RandHexStr<L, RP, LP> {
71 #[inline]
72 fn encode_to_buf(self, string: &mut Vec<u8>) {
73 match L {
74 1..=16 => {
75 for _ in 0..RP {
76 NumStr::hex_default(fast_random())
77 .set_resize_len::<L>()
78 .encode_to_buf(string);
79 }
80
81 if LP > 0 {
82 debug_assert!(LP <= 16, "LP should be 0..=16");
83
84 NumStr::hex_default(fast_random())
85 .set_resize_len::<LP>()
86 .encode_to_buf(string);
87 }
88 }
89 0 => {}
90 _ => {
91 #[cfg(any(debug_assertions, test))]
92 unreachable!("L should be 0..=16");
93
94 #[cfg(not(any(debug_assertions, test)))]
95 string.extend(
98 rand::thread_rng()
99 .sample_iter(&Slice::new(b"0123456789abcdef").unwrap())
100 .take(L * RP + LP),
101 );
102 }
103 }
104 }
105
106 #[inline]
107 fn encode_to_buf_with_separator(self, string: &mut Vec<u8>, separator: &str) {
108 self.encode_to_buf(string);
109 string.extend(separator.as_bytes());
110 }
111
112 #[inline]
113 fn encode_to_bytes_buf(self, string: &mut bytes::BytesMut) {
114 match L {
115 1..=16 => {
116 for _ in 0..RP {
117 NumStr::hex_default(fast_random())
118 .set_resize_len::<L>()
119 .encode_to_bytes_buf(string);
120 }
121
122 if LP > 0 {
123 debug_assert!(LP <= 16, "LP should be 0..=16");
124
125 NumStr::hex_default(fast_random())
126 .set_resize_len::<LP>()
127 .encode_to_bytes_buf(string);
128 }
129 }
130 0 => {}
131 _ => {
132 #[cfg(any(debug_assertions, test))]
133 unreachable!("L should be 0..=16");
134
135 #[cfg(not(any(debug_assertions, test)))]
136 string.extend(
139 rand::thread_rng()
140 .sample_iter(&Slice::new(b"0123456789abcdef").unwrap())
141 .take(L * RP + LP),
142 );
143 }
144 }
145 }
146
147 #[inline]
148 fn encode_to_bytes_buf_with_separator(self, string: &mut bytes::BytesMut, separator: &str) {
149 self.encode_to_bytes_buf(string);
150 string.extend(separator.as_bytes());
151 }
152}
153
154impl<const L: usize, const RP: usize, const LP: usize> StringExtT for RandHexStr<L, RP, LP> {}
155
156impl RandHexStr {
157 #[inline]
158 pub const fn new_default() -> Self {
169 Self
170 }
171}
172
173impl<const L: usize, const RP: usize, const LP: usize> RandHexStr<L, RP, LP> {
174 #[inline]
175 pub const fn new() -> Self {
186 RandHexStr
187 }
188
189 #[inline]
190 pub const fn with_l<const NL: usize>(self) -> RandHexStr<NL, RP, LP> {
194 RandHexStr
195 }
196
197 #[inline]
198 pub const fn with_rp<const NRP: usize>(self) -> RandHexStr<L, NRP, LP> {
202 RandHexStr
203 }
204
205 #[inline]
206 pub const fn with_lp<const NLP: usize>(self) -> RandHexStr<L, RP, NLP> {
210 RandHexStr
211 }
212}
213
214#[derive(Debug, Clone, Copy)]
215#[repr(transparent)]
216pub struct RandStr<'r, const L: usize = 32>(&'r [u8]);
228
229impl<const L: usize> StringT for RandStr<'_, L> {
230 #[inline]
231 fn encode_to_buf(self, string: &mut Vec<u8>) {
232 if self.0.is_empty() {
233 return;
234 }
235
236 string.extend(
237 rand::thread_rng()
238 .sample_iter(Slice::new(self.0).unwrap())
239 .take(L),
240 );
241 }
242
243 #[inline]
244 fn encode_to_buf_with_separator(self, string: &mut Vec<u8>, separator: &str) {
245 if self.0.is_empty() {
246 return;
247 }
248
249 string.extend(
250 rand::thread_rng()
251 .sample_iter(Slice::new(self.0).unwrap())
252 .take(L),
253 );
254
255 string.extend(separator.as_bytes());
256 }
257
258 #[inline]
259 fn encode_to_bytes_buf(self, string: &mut bytes::BytesMut) {
260 if self.0.is_empty() {
261 return;
262 }
263
264 string.extend(
265 rand::thread_rng()
266 .sample_iter(Slice::new(self.0).unwrap())
267 .take(L),
268 );
269 }
270
271 #[inline]
272 fn encode_to_bytes_buf_with_separator(self, string: &mut bytes::BytesMut, separator: &str) {
273 if self.0.is_empty() {
274 return;
275 }
276
277 string.extend(
278 rand::thread_rng()
279 .sample_iter(Slice::new(self.0).unwrap())
280 .take(L),
281 );
282
283 string.extend(separator.as_bytes());
284 }
285}
286
287impl<const L: usize> StringExtT for RandStr<'_, L> {}
288
289impl<'r> RandStr<'r> {
290 #[inline]
291 pub const fn with_charset_default(charset: &'r [u8]) -> Self {
294 Self(charset)
295 }
296}
297
298impl<'r, const L: usize> RandStr<'r, L> {
299 #[inline]
300 pub const fn with_charset(charset: &'r [u8]) -> Self {
303 Self(charset)
304 }
305
306 #[inline]
307 pub const fn with_l<const NL: usize>(self) -> RandStr<'r, NL> {
309 RandStr(self.0)
310 }
311}