strander_core/
lib.rs

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    /// Generated distr trait
43    pub trait FooDistribution: Distribution<Foo> {
44        /// Return a new `FooDistribution` using the provided distribution for the `bar` field.
45        fn with_bar(self, bar: impl Distribution<String>) -> impl FooDistribution;
46        /// Return a new `FooDistribution` using the provided distribution for the `baz` field.
47        fn with_baz(self, baz: impl Distribution<u8>) -> impl FooDistribution;
48    }
49
50    /// Generated distr struct
51    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}