sbrd_gen/generator/primitive/
time_generator.rs

1use crate::builder::{GeneratorBuilder, ValueBound};
2use crate::error::{BuildError, GenerateError};
3use crate::eval::Evaluator;
4use crate::generator::{GeneratorBase, Randomizer};
5use crate::value::{DataValue, DataValueMap, SbrdTime, TIME_DEFAULT_FORMAT};
6use crate::GeneratorType;
7use chrono::Duration;
8use std::ops::AddAssign;
9
10/// The generator with generate [`SbrdTime`] value as [`DataValue::String`] with the format
11///
12/// See [`format::strftime` module] for more information on `format` option.
13/// The default for `format` and the format when parsing is [`TIME_DEFAULT_FORMAT`].
14///
15/// [`SbrdTime`]: ../../value/type.SbrdTime.html
16/// [`DataValue::String`]: ../../value/enum.DataValue.html#variant.String
17/// [`format::strftime` module]: https://docs.rs/chrono/0.4.19/chrono/format/strftime/index.html#specifiers
18/// [`TIME_DEFAULT_FORMAT`]: ../../value/constant.TIME_DEFAULT_FORMAT.html
19#[derive(Debug, PartialEq, Clone)]
20pub struct TimeGenerator {
21    nullable: bool,
22    format: String,
23    range: ValueBound<SbrdTime>,
24}
25
26impl<R: Randomizer + ?Sized> GeneratorBase<R> for TimeGenerator {
27    fn create(builder: GeneratorBuilder) -> Result<Self, BuildError>
28    where
29        Self: Sized,
30    {
31        let GeneratorBuilder {
32            generator_type,
33            nullable,
34            range,
35            format,
36            ..
37        } = builder;
38
39        if generator_type != GeneratorType::Time {
40            return Err(BuildError::InvalidType(generator_type));
41        }
42
43        let default_range = Self::default_range();
44        let _range = match range {
45            None => default_range,
46            Some(r) => r
47                .try_convert_with(|s| {
48                    SbrdTime::parse_from_str(&s.to_parse_string(), TIME_DEFAULT_FORMAT).map_err(
49                        |e| {
50                            BuildError::FailParseValue(
51                                s.to_parse_string(),
52                                "Time".to_string(),
53                                e.to_string(),
54                            )
55                        },
56                    )
57                })
58                .map(|range| {
59                    // If it is not specified so that it can be generated in an appropriate range, use the default boundary.
60                    range.without_no_bound_from_other(default_range)
61                })?,
62        };
63        if _range.is_empty() {
64            return Err(BuildError::RangeEmpty(_range.convert_into()));
65        }
66
67        Ok(Self {
68            nullable,
69            format: format.unwrap_or_else(|| TIME_DEFAULT_FORMAT.to_string()),
70            range: _range,
71        })
72    }
73
74    fn is_nullable(&self) -> bool {
75        self.nullable
76    }
77
78    fn generate_without_null(
79        &self,
80        rng: &mut R,
81        context: &DataValueMap<&str>,
82    ) -> Result<DataValue, GenerateError> {
83        let upper_bound = self
84            .range
85            .get_end()
86            .expect("Exist upper bound is not exist");
87        let lower_bound = self
88            .range
89            .get_start()
90            .expect("Exist lower bound is not exist");
91        let since_duration_seconds = upper_bound.signed_duration_since(lower_bound).num_seconds();
92        let diff_seconds = rng.gen_range(ValueBound::new(
93            Some(0),
94            Some((self.range.is_include_end(), since_duration_seconds)),
95        ));
96        let mut time_value = lower_bound;
97        time_value.add_assign(Duration::seconds(diff_seconds));
98
99        let evaluator = Evaluator::new(context);
100        let format = evaluator.format_script(&self.format).map_err(|e| {
101            GenerateError::FailEval(
102                e,
103                self.format.to_string(),
104                context
105                    .clone()
106                    .into_iter()
107                    .map(|(k, v)| (k.to_string(), v))
108                    .collect::<DataValueMap<String>>(),
109            )
110        })?;
111
112        Ok(DataValue::String(time_value.format(&format).to_string()))
113    }
114}
115
116impl TimeGenerator {
117    #[inline]
118    fn min_time() -> SbrdTime {
119        SbrdTime::from_hms(0, 0, 0)
120    }
121    #[inline]
122    fn max_time() -> SbrdTime {
123        SbrdTime::from_hms(23, 59, 59)
124    }
125
126    fn default_range() -> ValueBound<SbrdTime> {
127        ValueBound::new(Some(Self::min_time()), Some((true, Self::max_time())))
128    }
129}