sbrd_gen/generator/evaluate/
eval_generator.rs

1use crate::builder::GeneratorBuilder;
2use crate::error::{BuildError, GenerateError};
3use crate::eval::{EvalResult, Evaluator};
4use crate::generator::{GeneratorBase, Randomizer};
5use crate::value::{DataValue, DataValueMap, SbrdBool, SbrdInt, SbrdReal, SbrdString};
6use crate::GeneratorType;
7use std::marker::PhantomData;
8
9/// The generator with generate value as a type by specified `script` with evaluating by [`Evaluator`]
10///
11/// [`Evaluator`]: ../../eval/struct.Evaluator.html
12#[derive(Debug, PartialEq, Clone)]
13pub struct EvalGenerator<T> {
14    nullable: bool,
15    script: String,
16    _calculated_type: PhantomData<T>,
17}
18
19impl<R: Randomizer + ?Sized, F: ForEvalGeneratorType> GeneratorBase<R> for EvalGenerator<F> {
20    fn create(builder: GeneratorBuilder) -> Result<Self, BuildError>
21    where
22        Self: Sized,
23    {
24        let GeneratorBuilder {
25            generator_type,
26            nullable,
27            script,
28            ..
29        } = builder;
30
31        if generator_type != F::get_generator_type() {
32            return Err(BuildError::InvalidType(generator_type));
33        }
34
35        match script {
36            None => Err(BuildError::NotExistValueOf("script".to_string())),
37            Some(_script) => Ok(Self {
38                nullable,
39                script: _script,
40                _calculated_type: PhantomData,
41            }),
42        }
43    }
44
45    fn is_nullable(&self) -> bool {
46        self.nullable
47    }
48
49    fn generate_without_null(
50        &self,
51        _rng: &mut R,
52        context: &DataValueMap<&str>,
53    ) -> Result<DataValue, GenerateError> {
54        F::eval_script(&self.script, context).map_err(|e| {
55            GenerateError::FailEval(
56                e,
57                self.script.clone(),
58                context
59                    .iter()
60                    .map(|(k, v)| (k.to_string(), v.clone()))
61                    .collect::<DataValueMap<String>>(),
62            )
63        })
64    }
65}
66
67/// Helper traits for generators that generate evaluable values
68pub trait ForEvalGeneratorType {
69    /// The type of the generator
70    fn get_generator_type() -> GeneratorType;
71
72    /// Evaluate the script with the context
73    fn eval_script<'a>(script: &'a str, context: &'a DataValueMap<&str>) -> EvalResult<DataValue>;
74}
75
76impl ForEvalGeneratorType for SbrdInt {
77    fn get_generator_type() -> GeneratorType {
78        GeneratorType::EvalInt
79    }
80
81    fn eval_script<'a>(script: &'a str, context: &'a DataValueMap<&str>) -> EvalResult<DataValue> {
82        let evaluator = Evaluator::new(context);
83        evaluator.eval_int(script).map(|v| v.into())
84    }
85}
86impl ForEvalGeneratorType for SbrdReal {
87    fn get_generator_type() -> GeneratorType {
88        GeneratorType::EvalReal
89    }
90
91    fn eval_script<'a>(script: &'a str, context: &'a DataValueMap<&str>) -> EvalResult<DataValue> {
92        let evaluator = Evaluator::new(context);
93        evaluator.eval_real(script).map(|v| v.into())
94    }
95}
96impl ForEvalGeneratorType for SbrdBool {
97    fn get_generator_type() -> GeneratorType {
98        GeneratorType::EvalBool
99    }
100
101    fn eval_script<'a>(script: &'a str, context: &'a DataValueMap<&str>) -> EvalResult<DataValue> {
102        let evaluator = Evaluator::new(context);
103        evaluator.eval_bool(script).map(|v| v.into())
104    }
105}
106impl ForEvalGeneratorType for SbrdString {
107    fn get_generator_type() -> GeneratorType {
108        GeneratorType::EvalString
109    }
110
111    fn eval_script<'a>(script: &'a str, context: &'a DataValueMap<&str>) -> EvalResult<DataValue> {
112        let evaluator = Evaluator::new(context);
113        evaluator.eval_string(script).map(|v| v.into())
114    }
115}