openfare_lib/lock/plan/conditions/
employees_count.rs

1use super::common;
2use anyhow::{format_err, Result};
3use lazy_regex::regex;
4use std::convert::TryFrom;
5
6#[derive(Debug, Clone, Eq, PartialEq)]
7pub struct EmployeesCount {
8    operator: common::Operator,
9    count: usize,
10}
11
12impl std::convert::TryFrom<&str> for EmployeesCount {
13    type Error = anyhow::Error;
14    fn try_from(value: &str) -> Result<Self, Self::Error> {
15        let (operator, count) = parse_value(&value)?;
16        Ok(Self { operator, count })
17    }
18}
19
20impl EmployeesCount {
21    pub fn evaluate(&self, parameters: &crate::lock::plan::conditions::Parameters) -> Result<bool> {
22        let employees_count = parameters.employees_count.ok_or(format_err!(
23            "Attempting to evaluate plan conditions using unset parameter `employees-count`."
24        ))?;
25        let result =
26            common::evaluate_operator::<usize>(&employees_count, &self.operator, &self.count);
27        Ok(result)
28    }
29}
30
31impl serde::Serialize for EmployeesCount {
32    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
33    where
34        S: serde::Serializer,
35    {
36        serializer.serialize_str(format!("{} {}", self.operator.to_string(), self.count,).as_str())
37    }
38}
39
40struct Visitor {
41    marker: std::marker::PhantomData<fn() -> EmployeesCount>,
42}
43
44impl Visitor {
45    fn new() -> Self {
46        Visitor {
47            marker: std::marker::PhantomData,
48        }
49    }
50}
51
52impl<'de> serde::de::Visitor<'de> for Visitor {
53    type Value = EmployeesCount;
54
55    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
56        formatter.write_str("a string such as '> 100'")
57    }
58
59    fn visit_str<E>(self, value: &str) -> core::result::Result<Self::Value, E>
60    where
61        E: serde::de::Error,
62    {
63        let (operator, count) = parse_value(&value).expect("parse employee-count condition value");
64        Ok(Self::Value { operator, count })
65    }
66}
67
68impl<'de> serde::Deserialize<'de> for EmployeesCount {
69    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
70    where
71        D: serde::Deserializer<'de>,
72    {
73        deserializer.deserialize_str(Visitor::new())
74    }
75}
76
77fn parse_value(value: &str) -> Result<(common::Operator, usize)> {
78    let re = regex!(r"(?P<operator>(>=)|(<=)|(<)|(>)|(=))\s*(?P<quantity>[0-9]+)");
79    let captures = re
80        .captures(value)
81        .ok_or(format_err!("Regex failed to capture field."))?;
82
83    let operator_match = captures
84        .name("operator")
85        .expect("extract operator from regex capture")
86        .as_str();
87    let operator = common::Operator::try_from(operator_match)?;
88
89    let quantity_match = captures
90        .name("quantity")
91        .expect("extract quantity from regex capture")
92        .as_str();
93    let quantity = quantity_match.parse::<usize>()?;
94
95    Ok((operator, quantity))
96}
97
98#[test]
99fn test_from_str() -> Result<()> {
100    let mut parameters = crate::lock::plan::conditions::Parameters::default();
101    parameters.employees_count = Some(99);
102
103    let employees_count = EmployeesCount::try_from("<= 99")?;
104    assert!(employees_count.evaluate(&parameters)?);
105    Ok(())
106}