sbrd_gen/generator/
generator_base.rs

1use crate::builder::{ChildGeneratorBuilder, GeneratorBuilder, Weight};
2use crate::error::{BuildError, GenerateError};
3use crate::eval::Evaluator;
4use crate::file::open_sbrd_file;
5use crate::value::{DataValue, DataValueMap};
6use either::Either;
7use rand::seq::SliceRandom;
8use rand::Rng;
9use std::io::{BufRead, BufReader};
10use std::path::PathBuf;
11
12/// Core of random data generator
13pub trait Randomizer: 'static + Rng {}
14impl<R: 'static + Rng> Randomizer for R {}
15
16/// Base trait for a generator
17pub trait GeneratorBase<R: Randomizer + ?Sized> {
18    /// Create generator from builder
19    fn create(builder: GeneratorBuilder) -> Result<Self, BuildError>
20    where
21        Self: Sized;
22
23    /// Can generate null flag
24    fn is_nullable(&self) -> bool;
25
26    /// Cannot generate null flag
27    fn is_required(&self) -> bool {
28        !self.is_nullable()
29    }
30
31    /// Generate dummy data considering nullable
32    fn generate(
33        &self,
34        rng: &mut R,
35        context: &DataValueMap<&str>,
36    ) -> Result<DataValue, GenerateError> {
37        if self.is_required() {
38            self.generate_without_null(rng, context)
39        } else {
40            if rng.gen_bool(0.1) {
41                return Ok(DataValue::Null);
42            }
43
44            self.generate_without_null(rng, context)
45        }
46    }
47
48    /// Generate dummy data not considering nullable
49    fn generate_without_null(
50        &self,
51        rng: &mut R,
52        context: &DataValueMap<&str>,
53    ) -> Result<DataValue, GenerateError>;
54}
55
56/// Child generator with condition
57pub type CasedChild<R> = (Option<String>, Box<dyn GeneratorBase<R>>);
58/// Base trait for a generator use child generators with condition.
59///
60/// If a child generator's condition is [`Option::Some`], then evaluate it's condition.
61/// If a child generator's condition is [`Option::None`], then default condition. Default condition always must exist.
62///
63/// [`Option::Some`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.Some
64/// [`Option::None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None
65pub trait CasedChildGeneratorBase<R: Randomizer + ?Sized> {
66    /// Build selectable child generator list
67    fn build_selectable(
68        children: Option<Vec<ChildGeneratorBuilder>>,
69    ) -> Result<Vec<CasedChild<R>>, BuildError> {
70        match children {
71            None => Err(BuildError::NotExistValueOf("children".to_string())),
72            Some(children) => {
73                let mut _children: Vec<(Option<String>, Box<dyn GeneratorBase<R>>)> = Vec::new();
74                let mut has_default_case = false;
75                for child_builder in children.into_iter() {
76                    let ChildGeneratorBuilder {
77                        condition, builder, ..
78                    } = child_builder;
79                    has_default_case = has_default_case || condition.is_none();
80                    _children.push((condition, builder.build()?));
81                }
82
83                if _children.is_empty() {
84                    return Err(BuildError::EmptySelectableChildren);
85                }
86
87                if !has_default_case {
88                    return Err(BuildError::NotExistDefaultCase);
89                }
90
91                Ok(_children)
92            }
93        }
94    }
95
96    /// Get selectable child generators
97    fn get_children(&self) -> &[CasedChild<R>];
98
99    /// Generate dummy data considering nullable from picked out child generator
100    fn generate_from_children(
101        &self,
102        rng: &mut R,
103        context: &DataValueMap<&str>,
104    ) -> Result<DataValue, GenerateError> {
105        for (condition, generator) in self.get_children().iter() {
106            return match condition {
107                None => generator.generate(rng, context),
108                Some(_condition) => {
109                    let evaluator = Evaluator::new(context);
110                    let is_satisfy = evaluator.eval_bool(_condition).map_err(|e| {
111                        GenerateError::FailEval(
112                            e,
113                            _condition.clone(),
114                            context
115                                .iter()
116                                .map(|(k, v)| (k.to_string(), v.clone()))
117                                .collect::<DataValueMap<String>>(),
118                        )
119                    })?;
120                    if !is_satisfy {
121                        continue;
122                    }
123
124                    generator.generate(rng, context)
125                }
126            };
127        }
128
129        Err(GenerateError::FailGenerate(
130            "No match case condition".to_string(),
131        ))
132    }
133}
134
135/// Child generator with weight
136pub type WeightedChild<R> = (Weight, Box<dyn GeneratorBase<R>>);
137/// Base trait for a generator use child generator with weight
138pub trait WeightedChildGeneratorBase<R: Randomizer + ?Sized> {
139    /// Build selectable child generator with weight
140    fn build_selectable(
141        children: Option<Vec<ChildGeneratorBuilder>>,
142    ) -> Result<Vec<WeightedChild<R>>, BuildError> {
143        match children {
144            None => Err(BuildError::NotExistValueOf("children".to_string())),
145            Some(children) => {
146                let mut select_values = Vec::new();
147                for child_builder in children.into_iter() {
148                    let ChildGeneratorBuilder {
149                        weight, builder, ..
150                    } = child_builder;
151                    select_values.push((weight.unwrap_or(1), builder.build()?));
152                }
153
154                if select_values.is_empty() {
155                    return Err(BuildError::EmptySelectableChildren);
156                }
157
158                if select_values.iter().fold(0, |acc, item| acc + item.0) == 0 {
159                    return Err(BuildError::AllWeightsZero);
160                }
161
162                Ok(select_values)
163            }
164        }
165    }
166
167    /// Get selectable list
168    fn get_selectable(&self) -> &[WeightedChild<R>];
169
170    /// Generate value from picked out child generator
171    fn generate_from_children(
172        &self,
173        rng: &mut R,
174        context: &DataValueMap<&str>,
175    ) -> Result<DataValue, GenerateError> {
176        let item = self
177            .get_selectable()
178            .choose_weighted(rng, |item| item.0)
179            .map_err(|err| GenerateError::FailGenerate(err.to_string()))?;
180
181        item.1.generate(rng, context)
182    }
183}
184
185/// Base trait for a generator from input values
186pub trait ValueGeneratorBase<R: Randomizer + ?Sized, T> {
187    /// Function of parser the input value
188    fn parse(input: &str) -> Result<T, BuildError>;
189
190    /// Build selectable value
191    fn build_selectable(
192        chars: Option<String>,
193        values: Option<Vec<DataValue>>,
194        filepath: Option<PathBuf>,
195    ) -> Result<Vec<T>, BuildError> {
196        let mut selectable_values: Vec<T> = Vec::new();
197        if let Some(chars) = chars {
198            for c in chars.chars() {
199                selectable_values.push(Self::parse(&c.to_string())?);
200            }
201        }
202
203        if let Some(values) = values {
204            for value in values.into_iter() {
205                selectable_values.push(Self::parse(&value.to_parse_string())?);
206            }
207        }
208
209        if let Some(filepath) = filepath {
210            let file = open_sbrd_file(filepath.as_path())
211                .map_err(|e| BuildError::FileError(e, filepath.clone()))?;
212            let reader = BufReader::new(file);
213            for line in reader.lines() {
214                let line = line.map_err(|e| BuildError::FileError(e, filepath.clone()))?;
215                selectable_values.push(Self::parse(&line)?);
216            }
217        }
218
219        if selectable_values.is_empty() {
220            return Err(BuildError::EmptySelectableChildren);
221        }
222
223        Ok(selectable_values)
224    }
225}
226
227/// Value as String or Child for a generator.
228///
229/// Usually, this structure is used by a generator which generate value as string,
230/// because input value's type is unknown and a type of the generated value by child generator is also unknown.
231pub type ValueOrChild<R> = Either<String, Box<dyn GeneratorBase<R>>>;
232/// Base trait for a generator use picked out value from input values or generated value picked out child generator
233pub trait ValueChildGeneratorBase<R: Randomizer + ?Sized> {
234    /// Build selectable value and child generator
235    fn build_selectable(
236        children: Option<Vec<ChildGeneratorBuilder>>,
237        chars: Option<String>,
238        values: Option<Vec<DataValue>>,
239        filepath: Option<PathBuf>,
240    ) -> Result<Vec<ValueOrChild<R>>, BuildError> {
241        let mut select_values = Vec::new();
242        if let Some(children) = children {
243            for child_builder in children.into_iter() {
244                let ChildGeneratorBuilder { builder, .. } = child_builder;
245                select_values.push(Either::Right(builder.build()?));
246            }
247        }
248
249        if let Some(chars) = chars {
250            select_values.extend(chars.chars().map(|c| Either::Left(c.to_string())));
251        }
252
253        if let Some(values) = values {
254            select_values.extend(values.into_iter().map(|v| Either::Left(v.to_string())));
255        }
256
257        if let Some(filepath) = filepath {
258            let file = open_sbrd_file(filepath.as_path())
259                .map_err(|e| BuildError::FileError(e, filepath.clone()))?;
260            let reader = BufReader::new(file);
261            for line in reader.lines() {
262                let line = line.map_err(|e| BuildError::FileError(e, filepath.clone()))?;
263                select_values.push(Either::Left(line));
264            }
265        }
266
267        if select_values.is_empty() {
268            return Err(BuildError::EmptySelectable);
269        }
270
271        Ok(select_values)
272    }
273
274    /// Get selectable list
275    fn get_selectable(&self) -> &[ValueOrChild<R>];
276
277    /// Pick out value from input values or generated value picked out child generator
278    fn generate_from_values_or_children(
279        &self,
280        rng: &mut R,
281        context: &DataValueMap<&str>,
282    ) -> Result<DataValue, GenerateError> {
283        self.get_selectable()
284            .choose_weighted(rng, |_| 1)
285            .map_err(|err| GenerateError::FailGenerate(err.to_string()))
286            .and_then(|either| match either {
287                Either::Left(item) => Ok(item.clone().into()),
288                Either::Right(item) => item.generate(rng, context),
289            })
290    }
291}