openfare_lib/lock/plan/conditions/
employees_count.rs1use 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(¶meters)?);
105 Ok(())
106}