1use peg::parser;
2
3use serde::de::{Deserialize, Deserializer, Visitor};
4use std::str;
5use std::time::Duration;
6
7#[derive(Debug, PartialEq)]
8pub enum Scalar {
9 Size(u64),
10 Time(Duration),
11}
12
13impl Scalar {
14 pub fn is_size(&self) -> bool {
15 match self {
16 Scalar::Size(_) => true,
17 _ => false,
18 }
19 }
20
21 pub fn is_time(&self) -> bool {
22 match self {
23 Scalar::Time(_) => true,
24 _ => false,
25 }
26 }
27}
28
29#[derive(Debug, PartialEq)]
30pub enum Token {
31 Size,
32 Age,
33}
34
35#[derive(Debug, PartialEq)]
36pub enum Operator {
37 Greater,
38 GreaterEqual,
39 Lesser,
40 LesserEqual,
41 Equal,
42 NotEqual,
43}
44
45impl Operator {
46 pub fn compare<T>(&self, lhs: &T, rhs: &T) -> bool
47 where
48 T: PartialOrd<T>,
49 {
50 match self {
51 Operator::Greater => lhs > rhs,
52 Operator::GreaterEqual => lhs >= rhs,
53 Operator::Equal => lhs == rhs,
54 Operator::Lesser => lhs < rhs,
55 Operator::LesserEqual => lhs <= rhs,
56 Operator::NotEqual => lhs != rhs,
57 }
58 }
59}
60
61#[derive(Debug, PartialEq)]
62pub enum Predicate {
63 Comparison {
64 token: Token,
65 operator: Operator,
66 value: Scalar,
67 },
68}
69
70impl str::FromStr for Predicate {
71 type Err = ();
72 fn from_str(s: &str) -> Result<Self, Self::Err> {
73 Ok(predicates::predicate(s).unwrap())
74 }
75}
76
77struct PredicateVisitor;
78impl<'de> Visitor<'de> for PredicateVisitor {
79 type Value = Predicate;
80
81 fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
82 write!(f, "AAAAAAAAAAAAAA")
83 }
84
85 fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
86 where
87 E: serde::de::Error,
88 {
89 Ok(s.parse::<Predicate>().unwrap())
90 }
91}
92
93impl<'de> Deserialize<'de> for Predicate {
94 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
95 where
96 D: Deserializer<'de>,
97 {
98 deserializer.deserialize_str(PredicateVisitor)
99 }
100}
101
102parser! {
103 grammar predicates() for str {
104 rule token() -> Token
105 = "age" { Token::Age }
106 / "size" { Token::Size }
107
108 rule number() -> u64
109 = n:$(['0'..='9']) { n.parse().unwrap() }
110
111 rule scalar_size() -> Scalar
112 = n:number() " "? q:scalar_size_quantif() { Scalar::Size(n * q) }
113
114 rule scalar_size_quantif() -> u64
115 = "B" { 1 }
116 / "KB" { 2u64.pow(10) }
117 / "MB" { 2u64.pow(10 * 2) }
118 / "GB" { 2u64.pow(10 * 3) }
119
120 rule duration_quantif() -> u64
121 = ("seconds" / "second" / "secs" / "sec" / "s") { 1 }
122 / ("minutes" / "minute" / "min" / "m") { 60 }
123 / ("hours" / "hour" / "h") { 60 * 60 }
124 / ("days" / "day" / "d") { 24 * 60 * 60 }
125 / ("weeks" / "week" / "w") { 7 * 24 * 60 * 60 }
126
127 rule scalar_age() -> Scalar
128 = n:number() " " q:duration_quantif() { Scalar::Time(Duration::from_secs(n as u64 * q)) }
129
130 rule scalar() -> Scalar
131 = scalar_size() / scalar_age()
132
133 rule operator() -> Operator
134 = ">" { Operator::Greater }
135 / "<" { Operator::Lesser }
136 / ">=" { Operator::GreaterEqual }
137 / "<=" { Operator::LesserEqual }
138 / "==" { Operator::Equal }
139 / "!=" { Operator::NotEqual }
140
141 pub rule predicate() -> Predicate
142 = t:token() " " operator() " " s:scalar() { Predicate::Comparison { token: t, operator: Operator::Greater, value: s } }
143 }
144}
145
146#[test]
147fn can_parse_size_predicate() {
148 assert_eq!(
149 predicates::predicate("size > 1 MB").unwrap(),
150 Predicate::Comparison {
151 token: Token::Size,
152 operator: Operator::Greater,
153 value: Scalar::Size(1024 * 1024)
154 },
155 )
156}
157
158#[test]
159fn can_parse_time_predicates() {
160 assert_eq!(
161 predicates::predicate("age > 1 h").unwrap(),
162 Predicate::Comparison {
163 token: Token::Age,
164 operator: Operator::Greater,
165 value: Scalar::Time(Duration::from_secs(60 * 60))
166 },
167 )
168}