Skip to main content

bolero_generator_hydro/alloc/
string.rs

1use crate::{
2    alloc_generators::{CollectionGenerator, DEFAULT_LEN_RANGE},
3    Driver, TypeGenerator, TypeGeneratorWithParams, TypeValueGenerator, ValueGenerator,
4};
5use alloc::string::String;
6use core::ops::RangeInclusive;
7
8pub struct StringGenerator<C, L> {
9    chars: C,
10    len: L,
11}
12
13impl<C, L> StringGenerator<C, L> {
14    pub fn chars<Gen: ValueGenerator<Output = char>>(self, chars: Gen) -> StringGenerator<Gen, L> {
15        StringGenerator {
16            chars,
17            len: self.len,
18        }
19    }
20
21    pub fn map_chars<Gen: ValueGenerator<Output = char>, F: Fn(C) -> Gen>(
22        self,
23        map: F,
24    ) -> StringGenerator<Gen, L> {
25        StringGenerator {
26            chars: map(self.chars),
27            len: self.len,
28        }
29    }
30
31    pub fn len<Gen: ValueGenerator<Output = usize>>(self, len: Gen) -> StringGenerator<C, Gen> {
32        StringGenerator {
33            chars: self.chars,
34            len,
35        }
36    }
37
38    pub fn map_len<Gen: ValueGenerator<Output = usize>, F: Fn(L) -> Gen>(
39        self,
40        map: F,
41    ) -> StringGenerator<C, Gen> {
42        StringGenerator {
43            chars: self.chars,
44            len: map(self.len),
45        }
46    }
47}
48
49impl<G: ValueGenerator<Output = char>, L: ValueGenerator<Output = usize>> ValueGenerator
50    for StringGenerator<G, L>
51{
52    type Output = String;
53
54    fn generate<D: Driver>(&self, driver: &mut D) -> Option<Self::Output> {
55        let mut value = String::default();
56        self.mutate(driver, &mut value)?;
57        Some(value)
58    }
59
60    fn mutate<D: Driver>(&self, driver: &mut D, value: &mut Self::Output) -> Option<()> {
61        driver.enter_list::<Self::Output, _, _, _>(&self.len, |driver, len| {
62            CollectionGenerator::mutate_collection(value, driver, len, &self.chars)
63        })
64    }
65}
66
67impl CollectionGenerator for String {
68    type Item = char;
69
70    fn mutate_collection<D: Driver, G>(
71        &mut self,
72        driver: &mut D,
73        new_len: usize,
74        item_gen: &G,
75    ) -> Option<()>
76    where
77        G: ValueGenerator<Output = Self::Item>,
78    {
79        let prev = core::mem::take(self);
80
81        let to_mutate = self.len().min(new_len);
82        let to_append = new_len.saturating_sub(to_mutate);
83
84        for mut c in prev.chars().take(to_mutate) {
85            item_gen.mutate(driver, &mut c)?;
86            self.push(c);
87        }
88
89        for _ in 0..to_append {
90            self.push(item_gen.generate(driver)?);
91        }
92
93        // make sure the char count is correct
94        #[cfg(test)]
95        assert_eq!(self.chars().count(), new_len);
96
97        Some(())
98    }
99}
100
101impl TypeGenerator for String {
102    fn generate<D: Driver>(driver: &mut D) -> Option<Self> {
103        String::gen_with().generate(driver)
104    }
105}
106
107impl TypeGeneratorWithParams for String {
108    type Output = StringGenerator<TypeValueGenerator<char>, RangeInclusive<usize>>;
109
110    fn gen_with() -> Self::Output {
111        StringGenerator {
112            chars: Default::default(),
113            len: DEFAULT_LEN_RANGE,
114        }
115    }
116}
117
118impl ValueGenerator for String {
119    type Output = Self;
120
121    fn generate<D: Driver>(&self, _driver: &mut D) -> Option<Self> {
122        Some(self.clone())
123    }
124}
125
126#[test]
127fn string_type_test() {
128    let _ = generator_test!(produce::<String>());
129}
130
131#[test]
132fn string_with_test() {
133    let results = generator_test!(produce::<String>().with().len(32usize));
134    assert!(results.into_iter().any(|s| s.chars().count() == 32));
135}