1pub use rand::Rng;
2use rand::distr::{Alphanumeric, Distribution, SampleString, StandardUniform};
3
4pub trait Strand: Sized {
5 fn strand() -> impl Distribution<Self>;
6}
7
8struct StringDistr;
9
10impl Distribution<String> for StringDistr {
11 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> String {
12 Alphanumeric.sample_string(rng, 8)
13 }
14}
15
16impl Strand for String {
17 fn strand() -> impl Distribution<Self> {
18 return StringDistr;
19 }
20}
21
22impl Strand for u8 {
23 fn strand() -> impl Distribution<Self> {
24 StandardUniform
25 }
26}
27
28#[cfg(test)]
29mod test {
30 #![allow(dead_code)]
31
32 use super::Strand;
33 use rand::Rng;
34 use rand::distr::Distribution;
35
36 #[derive(Debug)]
37 pub struct Foo {
38 pub bar: String,
39 pub baz: u8,
40 }
41
42 pub trait FooDistribution: Distribution<Foo> {
44 fn with_bar(self, bar: impl Distribution<String>) -> impl FooDistribution;
46 fn with_baz(self, baz: impl Distribution<u8>) -> impl FooDistribution;
48 }
49
50 struct FooDistr<A, B> {
52 bar: A,
53 baz: B,
54 }
55
56 impl<A, B> Distribution<Foo> for FooDistr<A, B>
57 where
58 A: Distribution<String>,
59 B: Distribution<u8>,
60 {
61 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Foo {
62 Foo {
63 bar: self.bar.sample(rng),
64 baz: self.baz.sample(rng),
65 }
66 }
67 }
68
69 impl<A, B> FooDistribution for FooDistr<A, B>
70 where
71 A: Distribution<String>,
72 B: Distribution<u8>,
73 {
74 fn with_bar(self, bar: impl Distribution<String>) -> impl FooDistribution {
75 FooDistr { bar, baz: self.baz }
76 }
77
78 fn with_baz(self, baz: impl Distribution<u8>) -> impl FooDistribution {
79 FooDistr { bar: self.bar, baz }
80 }
81 }
82
83 impl Strand for Foo {
84 #[allow(refining_impl_trait)]
85 fn strand() -> impl FooDistribution {
86 FooDistr {
87 bar: String::strand(),
88 baz: u8::strand(),
89 }
90 }
91 }
92
93 #[test]
94 fn foo_strand() {
95 let strand = Foo::strand();
96 let foo = strand.sample(&mut rand::rng());
97 println!("{:?}", foo);
98 }
99}