1#[cfg(feature = "random")]
2#[cfg(test)]
3macro_rules! assert_uniform_distribution {
4 ($bins:expr) => {{
5 let bins = &$bins;
6
7 for (i, &bin) in bins.iter().enumerate() {
8 if bin < 5 {
9 panic!("{}[{}] < 5: {:?}", stringify!($bins), i, bins);
10 }
11 }
12 const P_LIMIT: f64 = 0.01; let p_value = crate::random_sampling::test_utils::uniform_distribution_test(bins);
14 if p_value < P_LIMIT {
15 panic!(
16 "distribution of {} is not uniform enough (p-value {} < {}): {:?}",
17 stringify!($bins),
18 p_value,
19 P_LIMIT,
20 bins
21 );
22 }
23 }};
24}
25
26#[cfg(test)]
27macro_rules! test_uniform_distribution {
28 (
29 $ty:path $(as $base_ty:path)? {
30 $($component:ident: ($component_min:expr, $component_max:expr)),+$(,)?
31 },
32 min: $min:expr,
33 max: $max:expr$(,)?
34 ) => {
35 #[cfg(feature = "random")]
36 #[test]
37 fn uniform_distribution_rng_gen() {
38 use rand::Rng;
39
40 const BINS: usize = crate::random_sampling::test_utils::BINS;
41 const SAMPLES: usize = crate::random_sampling::test_utils::SAMPLES;
42
43 $(let mut $component = [0; BINS];)+
44
45 let mut rng = rand_mt::Mt::new(1234); for _ in 0..SAMPLES {
48 let color: $ty = rng.gen();
49 $(let color: $base_ty = crate::convert::IntoColorUnclamped::into_color_unclamped(color);)?
50
51 if $(color.$component < $component_min || color.$component > $component_max)||+ {
52 continue;
53 }
54
55 $({
56 let min: f32 = $component_min;
57 let max: f32 = $component_max;
58 let range = max - min;
59 let normalized = (color.$component - min) / range;
60 $component[((normalized * BINS as f32) as usize).min(BINS - 1)] += 1;
61 })+
62 }
63
64 $(assert_uniform_distribution!($component);)+
65 }
66
67 #[cfg(feature = "random")]
68 #[test]
69 fn uniform_distribution_uniform_sample() {
70 use rand::distributions::uniform::Uniform;
71 use rand::Rng;
72
73 const BINS: usize = crate::random_sampling::test_utils::BINS;
74 const SAMPLES: usize = crate::random_sampling::test_utils::SAMPLES;
75
76 $(let mut $component = [0; BINS];)+
77
78 let mut rng = rand_mt::Mt::new(1234); let uniform_sampler = Uniform::new($min, $max);
80
81 for _ in 0..SAMPLES {
82 let color: $ty = rng.sample(&uniform_sampler);
83 $(let color: $base_ty = crate::convert::IntoColorUnclamped::into_color_unclamped(color);)?
84
85 if $(color.$component < $component_min || color.$component > $component_max)||+ {
86 continue;
87 }
88
89 $({
90 let min: f32 = $component_min;
91 let max: f32 = $component_max;
92 let range = max - min;
93 let normalized = (color.$component - min) / range;
94 $component[((normalized * BINS as f32) as usize).min(BINS - 1)] += 1;
95 })+
96 }
97
98 $(assert_uniform_distribution!($component);)+
99 }
100
101 #[cfg(feature = "random")]
102 #[test]
103 fn uniform_distribution_uniform_sample_inclusive() {
104 use rand::distributions::uniform::Uniform;
105 use rand::Rng;
106
107 const BINS: usize = crate::random_sampling::test_utils::BINS;
108 const SAMPLES: usize = crate::random_sampling::test_utils::SAMPLES;
109
110 $(let mut $component = [0; BINS];)+
111
112 let mut rng = rand_mt::Mt::new(1234); let uniform_sampler = Uniform::new_inclusive($min, $max);
114
115 for _ in 0..SAMPLES {
116 let color: $ty = rng.sample(&uniform_sampler);
117 $(let color: $base_ty = crate::convert::IntoColorUnclamped::into_color_unclamped(color);)?
118
119 if $(color.$component < $component_min || color.$component > $component_max)||+ {
120 continue;
121 }
122
123 $({
124 let min: f32 = $component_min;
125 let max: f32 = $component_max;
126 let range = max - min;
127 let normalized = (color.$component - min) / range;
128 $component[((normalized * BINS as f32) as usize).min(BINS - 1)] += 1;
129 })+
130 }
131
132 $(assert_uniform_distribution!($component);)+
133 }
134 };
135}
136
137macro_rules! __apply_map_fn {
138 ($value: expr) => {
139 $value
140 };
141 ($value: expr, $map_fn: expr) => {
142 $map_fn($value)
143 };
144}
145
146macro_rules! impl_rand_traits_cartesian {
147 (
148 $uniform_ty: ident,
149 $ty: ident
150 {$($component: ident $(=> [$map_fn: expr])?),+}
151 $(phantom: $phantom: ident : PhantomData<$phantom_ty: ident>)?
152 $(where $($where: tt)+)?
153 ) => {
154 impl_rand_traits_cartesian!(
155 $uniform_ty,
156 $ty<>
157 {$($component $( => [$map_fn])?),+}
158 $(phantom: $phantom : PhantomData<$phantom_ty>)?
159 $(where $($where)+)?);
160 };
161 (
162 $uniform_ty: ident,
163 $ty: ident <$($ty_param: ident),*>
164 {$($component: ident $(=> [$map_fn: expr])?),+}
165 $(phantom: $phantom: ident : PhantomData<$phantom_ty: ident>)?
166 $(where $($where: tt)+)?
167 ) => {
168 #[cfg(feature = "random")]
169 impl<$($ty_param,)* T> rand::distributions::Distribution<$ty<$($ty_param,)* T>> for rand::distributions::Standard
170 where
171 rand::distributions::Standard: rand::distributions::Distribution<T>,
172 $($($where)+)?
173 {
174 #[allow(clippy::redundant_closure_call)]
175 fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> $ty<$($ty_param,)* T> {
176 $ty {
177 $($component: __apply_map_fn!(rng.gen::<T>() $(, $map_fn)?),)+
178 $($phantom: core::marker::PhantomData,)?
179 }
180 }
181 }
182
183 #[cfg(feature = "random")]
185 pub struct $uniform_ty<$($ty_param,)* T>
186 where
187 T: rand::distributions::uniform::SampleUniform,
188 {
189 $($component: rand::distributions::uniform::Uniform<T>,)+
190 $($phantom: core::marker::PhantomData<$phantom_ty>,)?
191 }
192
193 #[cfg(feature = "random")]
194 impl<$($ty_param,)* T> rand::distributions::uniform::SampleUniform for $ty<$($ty_param,)* T>
195 where
196 T: rand::distributions::uniform::SampleUniform + Clone,
197 {
198 type Sampler = $uniform_ty<$($ty_param,)* T>;
199 }
200
201 #[cfg(feature = "random")]
202 impl<$($ty_param,)* T> rand::distributions::uniform::UniformSampler for $uniform_ty<$($ty_param,)* T>
203 where
204 T: rand::distributions::uniform::SampleUniform + Clone,
205 {
206 type X = $ty<$($ty_param,)* T>;
207
208 fn new<B1, B2>(low_b: B1, high_b: B2) -> Self
209 where
210 B1: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
211 B2: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
212 {
213 let low = low_b.borrow();
214 let high = high_b.borrow();
215
216 Self {
217 $($component: rand::distributions::uniform::Uniform::new::<_, T>(low.$component.clone(), high.$component.clone()),)+
218 $($phantom: core::marker::PhantomData,)?
219 }
220 }
221
222 fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Self
223 where
224 B1: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
225 B2: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
226 {
227 let low = low_b.borrow();
228 let high = high_b.borrow();
229
230 Self {
231 $($component: rand::distributions::uniform::Uniform::new_inclusive::<_, T>(low.$component.clone(), high.$component.clone()),)+
232 $($phantom: core::marker::PhantomData,)?
233 }
234 }
235
236 fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> $ty<$($ty_param,)* T> {
237 use rand::distributions::Distribution;
238
239 $ty {
240 $($component: self.$component.sample(rng),)+
241 $($phantom: core::marker::PhantomData,)?
242 }
243 }
244 }
245 };
246}
247
248macro_rules! impl_rand_traits_cylinder {
249 (
250 $uniform_ty: ident,
251 $ty: ident
252 {
253 hue: $hue_uniform_ty: ident => $hue_ty: ident,
254 height: $height: ident $(=> [$height_map_fn: expr])?,
255 radius: $radius: ident $(=> [$radius_map_fn: expr])?
256 }
257 $(phantom: $phantom: ident : PhantomData<$phantom_ty: ident>)?
258 $(where $($where: tt)+)?
259 ) => {
260 impl_rand_traits_cylinder!(
261 $uniform_ty,
262 $ty<>
263 {
264 hue: $hue_uniform_ty => $hue_ty,
265 height: $height $(=> [$height_map_fn])?,
266 radius: $radius $(=> [$radius_map_fn])?
267 }
268 $(phantom: $phantom : PhantomData<$phantom_ty>)?
269 $(where $($where)+)?);
270 };
271 (
272 $uniform_ty: ident,
273 $ty: ident <$($ty_param: ident),*>
274 {
275 hue: $hue_uniform_ty: ident => $hue_ty: ident,
276 height: $height: ident $(=> [$height_map_fn: expr])?,
277 radius: $radius: ident $(=> [$radius_map_fn: expr])?
278 }
279 $(phantom: $phantom: ident : PhantomData<$phantom_ty: ident>)?
280 $(where $($where: tt)+)?
281 ) => {
282 #[cfg(feature = "random")]
283 impl<$($ty_param,)* T> rand::distributions::Distribution<$ty<$($ty_param,)* T>> for rand::distributions::Standard
284 where
285 T: crate::num::Sqrt,
286 rand::distributions::Standard: rand::distributions::Distribution<T> + rand::distributions::Distribution<$hue_ty<T>>,
287 $($($where)+)?
288 {
289 #[allow(clippy::redundant_closure_call)]
290 fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> $ty<$($ty_param,)* T> {
291 $ty {
292 hue: rng.gen::<$hue_ty<T>>(),
293 $height: __apply_map_fn!(rng.gen::<T>() $(, $height_map_fn)?),
294 $radius: __apply_map_fn!(rng.gen::<T>().sqrt() $(, $radius_map_fn)?),
295 $($phantom: core::marker::PhantomData,)?
296 }
297 }
298 }
299
300 #[cfg(feature = "random")]
302 pub struct $uniform_ty<$($ty_param,)* T>
303 where
304 T: rand::distributions::uniform::SampleUniform,
305 {
306 hue: crate::hues::$hue_uniform_ty<T>,
307 $height: rand::distributions::uniform::Uniform<T>,
308 $radius: rand::distributions::uniform::Uniform<T>,
309 $($phantom: core::marker::PhantomData<$phantom_ty>,)?
310 }
311
312 #[cfg(feature = "random")]
313 impl<$($ty_param,)* T> rand::distributions::uniform::SampleUniform for $ty<$($ty_param,)* T>
314 where
315 T: crate::num::Sqrt + core::ops::Mul<Output = T> + Clone + rand::distributions::uniform::SampleUniform,
316 $hue_ty<T>: rand::distributions::uniform::SampleBorrow<$hue_ty<T>>,
317 crate::hues::$hue_uniform_ty<T>: rand::distributions::uniform::UniformSampler<X = $hue_ty<T>>,
318 {
319 type Sampler = $uniform_ty<$($ty_param,)* T>;
320 }
321
322 #[cfg(feature = "random")]
323 impl<$($ty_param,)* T> rand::distributions::uniform::UniformSampler for $uniform_ty<$($ty_param,)* T>
324 where
325 T: crate::num::Sqrt + core::ops::Mul<Output = T> + Clone + rand::distributions::uniform::SampleUniform,
326 $hue_ty<T>: rand::distributions::uniform::SampleBorrow<$hue_ty<T>>,
327 crate::hues::$hue_uniform_ty<T>: rand::distributions::uniform::UniformSampler<X = $hue_ty<T>>,
328 {
329 type X = $ty<$($ty_param,)* T>;
330
331 fn new<B1, B2>(low_b: B1, high_b: B2) -> Self
332 where
333 B1: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
334 B2: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
335 {
336 let low = low_b.borrow().clone();
337 let high = high_b.borrow().clone();
338
339 $uniform_ty {
340 $height: rand::distributions::uniform::Uniform::new::<_, T>(low.$height, high.$height),
341 $radius: rand::distributions::uniform::Uniform::new::<_, T>(
342 low.$radius.clone() * low.$radius,
343 high.$radius.clone() * high.$radius,
344 ),
345 hue: crate::hues::$hue_uniform_ty::new(low.hue, high.hue),
346 $($phantom: core::marker::PhantomData,)?
347 }
348 }
349
350 fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Self
351 where
352 B1: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
353 B2: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
354 {
355 let low = low_b.borrow().clone();
356 let high = high_b.borrow().clone();
357
358 $uniform_ty {
359 $height: rand::distributions::uniform::Uniform::new_inclusive::<_, T>(low.$height, high.$height),
360 $radius: rand::distributions::uniform::Uniform::new_inclusive::<_, T>(
361 low.$radius.clone() * low.$radius,
362 high.$radius.clone() * high.$radius,
363 ),
364 hue: crate::hues::$hue_uniform_ty::new_inclusive(low.hue, high.hue),
365 $($phantom: core::marker::PhantomData,)?
366 }
367 }
368
369 fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> $ty<$($ty_param,)* T> {
370 use rand::distributions::Distribution;
371
372 $ty {
373 $height: self.$height.sample(rng),
374 $radius: self.$radius.sample(rng).sqrt(),
375 hue: self.hue.sample(rng),
376 $($phantom: core::marker::PhantomData,)?
377 }
378 }
379 }
380 };
381}
382
383macro_rules! impl_rand_traits_hsv_cone {
384 (
385 $uniform_ty: ident,
386 $ty: ident
387 {
388 hue: $hue_uniform_ty: ident => $hue_ty: ident,
389 height: $height: ident,
390 radius: $radius: ident
391 }
392 $(phantom: $phantom: ident : PhantomData<$phantom_ty: ident>)?
393 $(where $($where: tt)+)?
394 ) => {
395 impl_rand_traits_hsv_cone!(
396 $uniform_ty,
397 $ty<>
398 {
399 hue: $hue_uniform_ty => $hue_ty,
400 height: $height,
401 radius: $radius
402 }
403 $(phantom: $phantom : PhantomData<$phantom_ty>)?
404 $(where $($where)+)?);
405 };
406 (
407 $uniform_ty: ident,
408 $ty: ident <$($ty_param: ident),*>
409 {
410 hue: $hue_uniform_ty: ident => $hue_ty: ident,
411 height: $height: ident,
412 radius: $radius: ident
413 }
414 $(phantom: $phantom: ident : PhantomData<$phantom_ty: ident>)?
415 $(where $($where: tt)+)?
416 ) => {
417 #[cfg(feature = "random")]
418 impl<$($ty_param,)* T> rand::distributions::Distribution<$ty<$($ty_param,)* T>> for rand::distributions::Standard
419 where
420 T: crate::num::Cbrt + crate::num::Sqrt,
421 rand::distributions::Standard: rand::distributions::Distribution<T> + rand::distributions::Distribution<$hue_ty<T>>,
422 {
423 fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> $ty<$($ty_param,)* T> {
424 let hue = rng.gen::<$hue_ty<T>>();
425 let crate::random_sampling::HsvSample { saturation: $radius, value: $height } =
426 crate::random_sampling::sample_hsv(rng.gen(), rng.gen());
427
428 $ty {
429 hue,
430 $radius,
431 $height,
432 $($phantom: core::marker::PhantomData,)?
433 }
434 }
435 }
436
437 #[cfg(feature = "random")]
439 pub struct $uniform_ty<$($ty_param,)* T>
440 where
441 T: rand::distributions::uniform::SampleUniform,
442 {
443 hue: crate::hues::$hue_uniform_ty<T>,
444 u1: rand::distributions::uniform::Uniform<T>,
445 u2: rand::distributions::uniform::Uniform<T>,
446 $($phantom: core::marker::PhantomData<$phantom_ty>,)?
447 }
448
449 #[cfg(feature = "random")]
450 impl<$($ty_param,)* T> rand::distributions::uniform::SampleUniform for $ty<$($ty_param,)* T>
451 where
452 T: crate::num::Cbrt + crate::num::Sqrt + crate::num::Powi + Clone + rand::distributions::uniform::SampleUniform,
453 $hue_ty<T>: rand::distributions::uniform::SampleBorrow<$hue_ty<T>>,
454 crate::hues::$hue_uniform_ty<T>: rand::distributions::uniform::UniformSampler<X = $hue_ty<T>>,
455 {
456 type Sampler = $uniform_ty<$($ty_param,)* T>;
457 }
458
459 #[cfg(feature = "random")]
460 impl<$($ty_param,)* T> rand::distributions::uniform::UniformSampler for $uniform_ty<$($ty_param,)* T>
461 where
462 T: crate::num::Cbrt + crate::num::Sqrt + crate::num::Powi + Clone + rand::distributions::uniform::SampleUniform,
463 $hue_ty<T>: rand::distributions::uniform::SampleBorrow<$hue_ty<T>>,
464 crate::hues::$hue_uniform_ty<T>: rand::distributions::uniform::UniformSampler<X = $hue_ty<T>>,
465 {
466 type X = $ty<$($ty_param,)* T>;
467
468 fn new<B1, B2>(low_b: B1, high_b: B2) -> Self
469 where
470 B1: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
471 B2: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
472 {
473 let low = low_b.borrow().clone();
474 let high = high_b.borrow().clone();
475
476 let (r1_min, r2_min) =
477 crate::random_sampling::invert_hsv_sample(crate::random_sampling::HsvSample {
478 value: low.$height,
479 saturation: low.$radius,
480 });
481 let (r1_max, r2_max) =
482 crate::random_sampling::invert_hsv_sample(crate::random_sampling::HsvSample {
483 value: high.$height,
484 saturation: high.$radius,
485 });
486
487 $uniform_ty {
488 hue: crate::hues::$hue_uniform_ty::new(low.hue, high.hue),
489 u1: rand::distributions::uniform::Uniform::new::<_, T>(r1_min, r1_max),
490 u2: rand::distributions::uniform::Uniform::new::<_, T>(r2_min, r2_max),
491 $($phantom: core::marker::PhantomData,)?
492 }
493 }
494
495 fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Self
496 where
497 B1: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
498 B2: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
499 {
500 let low = low_b.borrow().clone();
501 let high = high_b.borrow().clone();
502
503 let (r1_min, r2_min) =
504 crate::random_sampling::invert_hsv_sample(crate::random_sampling::HsvSample {
505 value: low.$height,
506 saturation: low.$radius,
507 });
508 let (r1_max, r2_max) =
509 crate::random_sampling::invert_hsv_sample(crate::random_sampling::HsvSample {
510 value: high.$height,
511 saturation: high.$radius,
512 });
513
514 $uniform_ty {
515 hue: crate::hues::$hue_uniform_ty::new_inclusive(low.hue, high.hue),
516 u1: rand::distributions::uniform::Uniform::new_inclusive::<_, T>(r1_min, r1_max),
517 u2: rand::distributions::uniform::Uniform::new_inclusive::<_, T>(r2_min, r2_max),
518 $($phantom: core::marker::PhantomData,)?
519 }
520 }
521
522 fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> $ty<$($ty_param,)* T> {
523 use rand::distributions::Distribution;
524
525 let hue = self.hue.sample(rng);
526 let crate::random_sampling::HsvSample { saturation: $radius, value: $height } =
527 crate::random_sampling::sample_hsv(self.u1.sample(rng), self.u2.sample(rng));
528
529 $ty {
530 hue,
531 $radius,
532 $height,
533 $($phantom: core::marker::PhantomData,)?
534 }
535 }
536 }
537 }
538}
539
540macro_rules! impl_rand_traits_hsl_bicone {
541 (
542 $uniform_ty: ident,
543 $ty: ident
544 {
545 hue: $hue_uniform_ty: ident => $hue_ty: ident,
546 height: $height: ident $(=> [$height_map_fn: expr, $height_unmap_fn: expr])?,
547 radius: $radius: ident $(=> [$radius_map_fn: expr, $radius_unmap_fn: expr])?
548 }
549 $(phantom: $phantom: ident : PhantomData<$phantom_ty: ident>)?
550 $(where $($where: tt)+)?
551 ) => {
552 impl_rand_traits_hsl_bicone!(
553 $uniform_ty,
554 $ty<>
555 {
556 hue: $hue_uniform_ty => $hue_ty,
557 height: $height $(=> [$height_map_fn, $height_unmap_fn])?,
558 radius: $radius $(=> [$radius_map_fn, $radius_unmap_fn])?
559 }
560 $(phantom: $phantom : PhantomData<$phantom_ty>)?
561 $(where $($where)+)?);
562 };
563 (
564 $uniform_ty: ident,
565 $ty: ident <$($ty_param: ident),*>
566 {
567 hue: $hue_uniform_ty: ident => $hue_ty: ident,
568 height: $height: ident $(=> [$height_map_fn: expr, $height_unmap_fn: expr])?,
569 radius: $radius: ident $(=> [$radius_map_fn: expr, $radius_unmap_fn: expr])?
570 }
571 $(phantom: $phantom: ident : PhantomData<$phantom_ty: ident>)?
572 $(where $($where: tt)+)?
573 ) => {
574 #[cfg(feature = "random")]
575 impl<$($ty_param,)* T> rand::distributions::Distribution<$ty<$($ty_param,)* T>> for rand::distributions::Standard
576 where
577 T: crate::num::Real + crate::num::One + crate::num::Cbrt + crate::num::Sqrt + crate::num::Arithmetics + crate::num::PartialCmp + Clone,
578 T::Mask: crate::bool_mask::LazySelect<T> + Clone,
579 rand::distributions::Standard: rand::distributions::Distribution<T> + rand::distributions::Distribution<$hue_ty<T>>,
580 {
581 #[allow(clippy::redundant_closure_call)]
582 fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> $ty<$($ty_param,)* T> {
583 let hue = rng.gen::<$hue_ty<T>>();
584 let crate::random_sampling::HslSample { saturation, lightness } =
585 crate::random_sampling::sample_hsl(rng.gen(), rng.gen());
586
587 $ty {
588 hue,
589 $radius: __apply_map_fn!(saturation $(, $radius_map_fn)?),
590 $height: __apply_map_fn!(lightness $(, $height_map_fn)?),
591 $($phantom: core::marker::PhantomData,)?
592 }
593 }
594 }
595
596 #[cfg(feature = "random")]
598 pub struct $uniform_ty<$($ty_param,)* T>
599 where
600 T: rand::distributions::uniform::SampleUniform,
601 {
602 hue: crate::hues::$hue_uniform_ty<T>,
603 u1: rand::distributions::uniform::Uniform<T>,
604 u2: rand::distributions::uniform::Uniform<T>,
605 $($phantom: core::marker::PhantomData<$phantom_ty>,)?
606 }
607
608 #[cfg(feature = "random")]
609 impl<$($ty_param,)* T> rand::distributions::uniform::SampleUniform for $ty<$($ty_param,)* T>
610 where
611 T: crate::num::Real + crate::num::One + crate::num::Cbrt + crate::num::Sqrt + crate::num::Powi + crate::num::Arithmetics + crate::num::PartialCmp + Clone + rand::distributions::uniform::SampleUniform,
612 T::Mask: crate::bool_mask::LazySelect<T> + Clone,
613 $hue_ty<T>: rand::distributions::uniform::SampleBorrow<$hue_ty<T>>,
614 crate::hues::$hue_uniform_ty<T>: rand::distributions::uniform::UniformSampler<X = $hue_ty<T>>,
615 {
616 type Sampler = $uniform_ty<$($ty_param,)* T>;
617 }
618
619 #[cfg(feature = "random")]
620 impl<$($ty_param,)* T> rand::distributions::uniform::UniformSampler for $uniform_ty<$($ty_param,)* T>
621 where
622 T: crate::num::Real + crate::num::One + crate::num::Cbrt + crate::num::Sqrt + crate::num::Powi + crate::num::Arithmetics + crate::num::PartialCmp + Clone + rand::distributions::uniform::SampleUniform,
623 T::Mask: crate::bool_mask::LazySelect<T> + Clone,
624 $hue_ty<T>: rand::distributions::uniform::SampleBorrow<$hue_ty<T>>,
625 crate::hues::$hue_uniform_ty<T>: rand::distributions::uniform::UniformSampler<X = $hue_ty<T>>,
626 {
627 type X = $ty<$($ty_param,)* T>;
628
629 #[allow(clippy::redundant_closure_call)]
630 fn new<B1, B2>(low_b: B1, high_b: B2) -> Self
631 where
632 B1: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
633 B2: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
634 {
635 let low = low_b.borrow().clone();
636 let high = high_b.borrow().clone();
637
638 let (r1_min, r2_min) =
639 crate::random_sampling::invert_hsl_sample(crate::random_sampling::HslSample {
640 lightness: __apply_map_fn!(low.$height $(, $radius_unmap_fn)?),
641 saturation: __apply_map_fn!(low.$radius $(, $height_unmap_fn)?),
642 });
643 let (r1_max, r2_max) =
644 crate::random_sampling::invert_hsl_sample(crate::random_sampling::HslSample {
645 lightness: __apply_map_fn!(high.$height $(, $radius_unmap_fn)?),
646 saturation: __apply_map_fn!(high.$radius $(, $height_unmap_fn)?),
647 });
648
649 $uniform_ty {
650 hue: crate::hues::$hue_uniform_ty::new(low.hue, high.hue),
651 u1: rand::distributions::uniform::Uniform::new::<_, T>(r1_min, r1_max),
652 u2: rand::distributions::uniform::Uniform::new::<_, T>(r2_min, r2_max),
653 $($phantom: core::marker::PhantomData,)?
654 }
655 }
656
657 #[allow(clippy::redundant_closure_call)]
658 fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Self
659 where
660 B1: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
661 B2: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
662 {
663 let low = low_b.borrow().clone();
664 let high = high_b.borrow().clone();
665
666 let (r1_min, r2_min) =
667 crate::random_sampling::invert_hsl_sample(crate::random_sampling::HslSample {
668 lightness: __apply_map_fn!(low.$height $(, $radius_unmap_fn)?),
669 saturation: __apply_map_fn!(low.$radius $(, $height_unmap_fn)?),
670 });
671 let (r1_max, r2_max) =
672 crate::random_sampling::invert_hsl_sample(crate::random_sampling::HslSample {
673 lightness: __apply_map_fn!(high.$height $(, $radius_unmap_fn)?),
674 saturation: __apply_map_fn!(high.$radius $(, $height_unmap_fn)?),
675 });
676
677 $uniform_ty {
678 hue: crate::hues::$hue_uniform_ty::new_inclusive(low.hue, high.hue),
679 u1: rand::distributions::uniform::Uniform::new_inclusive::<_, T>(r1_min, r1_max),
680 u2: rand::distributions::uniform::Uniform::new_inclusive::<_, T>(r2_min, r2_max),
681 $($phantom: core::marker::PhantomData,)?
682 }
683 }
684
685 #[allow(clippy::redundant_closure_call)]
686 fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> $ty<$($ty_param,)* T> {
687 use rand::distributions::Distribution;
688
689 let hue = self.hue.sample(rng);
690 let crate::random_sampling::HslSample { saturation, lightness } =
691 crate::random_sampling::sample_hsl(self.u1.sample(rng), self.u2.sample(rng));
692
693 $ty {
694 hue,
695 $radius: __apply_map_fn!(saturation $(, $radius_map_fn)?),
696 $height: __apply_map_fn!(lightness $(, $height_map_fn)?),
697 $($phantom: core::marker::PhantomData,)?
698 }
699 }
700 }
701 }
702}
703
704macro_rules! impl_rand_traits_hwb_cone {
705 (
706 $uniform_ty: ident,
707 $ty: ident,
708 $hsv_uniform_ty: ident,
709 $hsv_ty: ident
710 {
711 height: $height: ident,
712 radius: $radius: ident
713 }
714 $(phantom: $phantom: ident : PhantomData<$phantom_ty: ident>)?
715 $(where $($where: tt)+)?
716 ) => {
717 impl_rand_traits_hwb_cone!(
718 $uniform_ty,
719 $ty<>,
720 $hsv_uniform_ty,
721 $hsv_ty
722 {
723 height: $height,
724 radius: $radius
725 }
726 $(phantom: $phantom : PhantomData<$phantom_ty>)?
727 $(where $($where)+)?);
728 };
729 (
730 $uniform_ty: ident,
731 $ty: ident <$($ty_param: ident),*>,
732 $hsv_uniform_ty: ident,
733 $hsv_ty: ident
734 {
735 height: $height: ident,
736 radius: $radius: ident
737 }
738 $(phantom: $phantom: ident : PhantomData<$phantom_ty: ident>)?
739 $(where $($where: tt)+)?
740 ) => {
741 #[cfg(feature = "random")]
742 impl<$($ty_param,)* T> rand::distributions::Distribution<$ty<$($ty_param,)* T>> for rand::distributions::Standard
743 where
744 rand::distributions::Standard: rand::distributions::Distribution<$hsv_ty<$($ty_param,)* T>>,
745 $ty<$($ty_param,)* T>: crate::convert::FromColorUnclamped<$hsv_ty<$($ty_param,)* T>>,
746 {
747 fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> $ty<$($ty_param,)* T> {
748 use crate::convert::FromColorUnclamped;
749 $ty::from_color_unclamped(rng.gen::<$hsv_ty<$($ty_param,)* T>>())
750 }
751 }
752
753 #[cfg(feature = "random")]
755 pub struct $uniform_ty<$($ty_param,)* T>
756 where
757 T: rand::distributions::uniform::SampleUniform,
758 {
759 sampler: $hsv_uniform_ty<$($ty_param,)* T>,
760 $($phantom: core::marker::PhantomData<$phantom_ty>,)?
761 }
762
763 #[cfg(feature = "random")]
764 impl<$($ty_param,)* T> rand::distributions::uniform::SampleUniform for $ty<$($ty_param,)* T>
765 where
766 T: crate::num::MinMax + Clone + rand::distributions::uniform::SampleUniform,
767 $hsv_ty<$($ty_param,)* T>: crate::convert::FromColorUnclamped<$ty<$($ty_param,)* T>> + rand::distributions::uniform::SampleBorrow<$hsv_ty<$($ty_param,)* T>>,
768 $ty<$($ty_param,)* T>: crate::convert::FromColorUnclamped<$hsv_ty<$($ty_param,)* T>>,
769 $hsv_uniform_ty<$($ty_param,)* T>: rand::distributions::uniform::UniformSampler<X = $hsv_ty<$($ty_param,)* T>>,
770 {
771 type Sampler = $uniform_ty<$($ty_param,)* T>;
772 }
773
774 #[cfg(feature = "random")]
775 impl<$($ty_param,)* T> rand::distributions::uniform::UniformSampler for $uniform_ty<$($ty_param,)* T>
776 where
777 T: crate::num::MinMax + Clone + rand::distributions::uniform::SampleUniform,
778 $hsv_ty<$($ty_param,)* T>: crate::convert::FromColorUnclamped<$ty<$($ty_param,)* T>> + rand::distributions::uniform::SampleBorrow<$hsv_ty<$($ty_param,)* T>>,
779 $ty<$($ty_param,)* T>: crate::convert::FromColorUnclamped<$hsv_ty<$($ty_param,)* T>>,
780 $hsv_uniform_ty<$($ty_param,)* T>: rand::distributions::uniform::UniformSampler<X = $hsv_ty<$($ty_param,)* T>>,
781 {
782 type X = $ty<$($ty_param,)* T>;
783
784 fn new<B1, B2>(low_b: B1, high_b: B2) -> Self
785 where
786 B1: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
787 B2: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
788 {
789 use crate::convert::FromColorUnclamped;
790 let low_input = $hsv_ty::from_color_unclamped(low_b.borrow().clone());
791 let high_input = $hsv_ty::from_color_unclamped(high_b.borrow().clone());
792
793 let (low_saturation, high_saturation) = low_input.saturation.min_max(high_input.saturation);
794 let (low_value, high_value) = low_input.value.min_max(high_input.value);
795
796 let low = $hsv_ty{
797 hue: low_input.hue,
798 $radius: low_saturation,
799 $height: low_value,
800 $($phantom: core::marker::PhantomData,)?
801 };
802 let high = $hsv_ty{
803 hue: high_input.hue,
804 $radius: high_saturation,
805 $height: high_value,
806 $($phantom: core::marker::PhantomData,)?
807 };
808
809 let sampler = $hsv_uniform_ty::<$($ty_param,)* T>::new(low, high);
810
811 $uniform_ty {
812 sampler,
813 $($phantom: core::marker::PhantomData,)?
814 }
815 }
816
817 fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Self
818 where
819 B1: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
820 B2: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
821 {
822 use crate::convert::FromColorUnclamped;
823 let low_input = $hsv_ty::from_color_unclamped(low_b.borrow().clone());
824 let high_input = $hsv_ty::from_color_unclamped(high_b.borrow().clone());
825
826 let (low_saturation, high_saturation) = low_input.saturation.min_max(high_input.saturation);
827 let (low_value, high_value) = low_input.value.min_max(high_input.value);
828
829 let low = $hsv_ty{
830 hue: low_input.hue,
831 $radius: low_saturation,
832 $height: low_value,
833 $($phantom: core::marker::PhantomData,)?
834 };
835 let high = $hsv_ty{
836 hue: high_input.hue,
837 $radius: high_saturation,
838 $height: high_value,
839 $($phantom: core::marker::PhantomData,)?
840 };
841
842 let sampler = $hsv_uniform_ty::<$($ty_param,)* T>::new_inclusive(low, high);
843
844 $uniform_ty {
845 sampler,
846 $($phantom: core::marker::PhantomData,)?
847 }
848 }
849
850 fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> $ty<$($ty_param,)* T> {
851 use crate::convert::FromColorUnclamped;
852 $ty::from_color_unclamped(self.sampler.sample(rng))
853 }
854 }
855 };
856}