1use std::{fmt::Display, ops::Index, slice::SliceIndex, str::FromStr};
2
3use serde::{Deserialize, Serialize};
4
5use crate::expr::{
6 atomics::AtomicLocationRuleExpr,
7 eval::{BeOperator, BooleanOperator, EvalPolishError, Evaluable, VM},
8 parse::{self, TokenStream},
9};
10
11#[derive(Debug, Clone, PartialEq, Eq)]
12pub enum Part<Operator, Expr> {
13 Operator(Operator),
14 Expr(Expr),
15}
16
17impl<Operator: Display, Expr: Display> Display for Part<Operator, Expr> {
18 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
19 match self {
20 Part::Operator(operator) => operator.fmt(f),
21 Part::Expr(expr) => expr.fmt(f),
22 }
23 }
24}
25
26#[derive(Debug, Clone, PartialEq, Eq)]
27pub struct Exprs<Operator, Expr> {
28 parts: Vec<Part<Operator, Expr>>,
29}
30
31impl<Operator, Expr, I> Index<I> for Exprs<Operator, Expr>
32where
33 I: SliceIndex<[Part<Operator, Expr>]>,
34{
35 type Output = <[Part<Operator, Expr>] as Index<I>>::Output;
36
37 fn index(&self, index: I) -> &Self::Output {
38 self.parts.index(index)
39 }
40}
41
42impl<Operator, Expr> IntoIterator for Exprs<Operator, Expr> {
43 type Item = Part<Operator, Expr>;
44
45 type IntoIter = std::vec::IntoIter<Part<Operator, Expr>>;
46
47 fn into_iter(self) -> Self::IntoIter {
48 self.parts.into_iter()
49 }
50}
51
52impl<'e, Operator, Expr> IntoIterator for &'e Exprs<Operator, Expr> {
53 type Item = &'e Part<Operator, Expr>;
54
55 type IntoIter = std::slice::Iter<'e, Part<Operator, Expr>>;
56
57 fn into_iter(self) -> Self::IntoIter {
58 self.parts.iter()
59 }
60}
61
62impl<Operator, Expr> From<Vec<Part<Operator, Expr>>> for Exprs<Operator, Expr> {
63 fn from(parts: Vec<Part<Operator, Expr>>) -> Self {
64 Self { parts }
65 }
66}
67
68impl<Operator, Expr> From<Part<Operator, Expr>> for Exprs<Operator, Expr> {
69 fn from(value: Part<Operator, Expr>) -> Self {
70 vec![value].into()
71 }
72}
73
74impl<Operator, Expr> Default for Exprs<Operator, Expr> {
75 fn default() -> Self {
76 Self {
77 parts: Default::default(),
78 }
79 }
80}
81
82impl<Operator, Expr> FromIterator<Part<Operator, Expr>> for Exprs<Operator, Expr> {
83 fn from_iter<T: IntoIterator<Item = Part<Operator, Expr>>>(iter: T) -> Self {
84 Self {
85 parts: iter.into_iter().collect(),
86 }
87 }
88}
89
90impl<Value, Operator, Expr, State> Evaluable<State> for Exprs<Operator, Expr>
91where
92 Operator: BeOperator<Value> + Clone,
93 Expr: Evaluable<State, Value = Value>,
94 State: ?Sized,
95{
96 type Value = Result<Value, EvalPolishError>;
97
98 fn eval(&self, state: &State) -> Self::Value {
99 self.try_eval(state)
100 }
101}
102
103impl<Operator, Expr> Exprs<Operator, Expr> {
104 pub fn try_eval<Value, State>(&self, state: &State) -> Result<Value, EvalPolishError>
105 where
106 Operator: BeOperator<Value> + Clone,
107 Expr: Evaluable<State, Value = Value>,
108 State: ?Sized,
109 {
110 VM::new().try_run(self.parts.iter().map(|part| match part {
111 Part::Operator(op) => Part::Operator(op.clone()),
112 Part::Expr(a) => Part::Expr(a.eval(state)),
113 }))
114 }
115
116 pub fn validate_arity(&self) -> Result<(), EvalPolishError>
117 where
118 Operator: BeOperator<()> + Clone,
119 {
120 VM::new()
121 .try_run(self.parts.iter().map(|part| match part {
122 Part::Operator(op) => Part::Operator(op.clone()),
123 Part::Expr(_) => Part::Expr(()),
124 }))
125 .map(|_| ())
126 }
127}
128
129#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
130pub struct LocationRuleExprs {
131 infix: String,
132 polish: Exprs<BooleanOperator, AtomicLocationRuleExpr>,
133}
134
135impl LocationRuleExprs {
136 pub fn infix(&self) -> &str {
137 &self.infix
138 }
139
140 pub fn polish(&self) -> &Exprs<BooleanOperator, AtomicLocationRuleExpr> {
141 &self.polish
142 }
143}
144
145impl Display for LocationRuleExprs {
146 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
147 let Self { infix, .. } = self;
148 write!(f, "{infix}")
149 }
150}
151
152crate::orm_new_type!(@json LocationRuleExprs);
153
154impl<Operator: Display, Expr: Display> Serialize for Exprs<Operator, Expr> {
155 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
156 where
157 S: serde::Serializer,
158 {
159 let mut s = String::new();
160 self.parts
161 .iter()
162 .try_for_each(|part| {
163 use std::fmt::Write;
164 write!(s, "{part} ")
165 })
166 .map_err(serde::ser::Error::custom)?;
167 serializer.serialize_str(&s)
168 }
169}
170
171mod deserialize_exprs {
172 use peg::{error::ParseError, str::LineCol};
173 use serde::Deserializer;
174 use snafu::ResultExt;
175
176 use super::*;
177 use crate::expr::parse::InvalidPatternExpr;
178
179 #[derive(snafu::Snafu, Debug)]
180 pub enum DeserializeExprsError {
181 String {
183 message: String,
184 },
185 #[snafu(display(
186 "failed to deserialize rule exprs while lexing `{input}` (internal error, database changed?)"
187 ))]
188 Lex {
189 input: String,
190 source: ParseError<LineCol>,
191 },
192 #[snafu(display(
193 "failed to deserialize rule exprs while parsing `{input}` (internal error, database changed?)"
194 ))]
195 Parse {
196 input: String,
197 source: ParseError<LineCol>,
198 },
199 #[snafu(display(
200 "failed to deserialize rule exprs while parsing pattern (internal error, database changed?)"
201 ))]
202 PatternParse {
203 source: InvalidPatternExpr,
204 },
205 #[snafu(display(
206 "failed to deserialize rule exprs while validating polish notation (internal error, database changed?)"
207 ))]
208 InvalidPolish {
209 source: EvalPolishError,
210 },
211 }
212
213 impl<'de> Deserialize<'de> for Exprs<BooleanOperator, AtomicLocationRuleExpr> {
214 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
215 where
216 D: Deserializer<'de>,
217 {
218 (|| -> Result<_, DeserializeExprsError> {
219 let polish = String::deserialize(deserializer).map_err(|e| {
220 let message =
221 format!("Deserialize rule exprs failed in deserializing string: {e}");
222 StringSnafu { message }.build()
223 })?;
224 let tokens = TokenStream::new(&polish).context(LexSnafu { input: &polish })?;
225 let exprs = parse::polish_location_rule_exprs(&tokens)
226 .context(ParseSnafu { input: &polish })?
227 .context(PatternParseSnafu)?;
228 exprs.validate_arity().context(InvalidPolishSnafu)?;
229 Ok(exprs)
230 })()
231 .map_err(serde::de::Error::custom)
232 }
233 }
234}
235
236pub use deserialize_exprs::*;
237
238mod parse_exprs {
239 use peg::{error::ParseError, str::LineCol};
240 use snafu::ResultExt;
241
242 use super::*;
243 use crate::expr::parse::{self, InvalidPatternExpr};
244
245 #[derive(snafu::Snafu, Debug)]
246 pub enum ParseExprsError {
247 #[snafu(display("failed to parse rule exprs"))]
248 Pattern { source: InvalidPatternExpr },
249 #[snafu(display("failed to parse rule exprs `{input}`"))]
250 Incomplete {
251 input: String,
252 source: ParseError<LineCol>,
253 },
254 }
255
256 impl FromStr for LocationRuleExprs {
257 type Err = ParseExprsError;
258
259 fn from_str(infix: &str) -> Result<Self, Self::Err> {
260 let infix = infix.to_string();
261 let tokens =
262 parse::TokenStream::new(&infix).context(IncompleteSnafu { input: &infix })?;
263 let polish = parse::infix_location_rule_exprs(&tokens)
264 .context(IncompleteSnafu { input: &infix })?
265 .context(PatternSnafu)?;
266 Ok(Self { infix, polish })
267 }
268 }
269}
270
271#[cfg(feature = "cli")]
272impl clap::Args for LocationRuleExprs {
273 fn augment_args(cmd: clap::Command) -> clap::Command {
274 cmd.arg(
275 clap::Arg::new("expr")
276 .help("The expression to filter requests")
277 .required(true)
278 .num_args(1..)
279 .action(clap::ArgAction::Append),
280 )
281 }
282
283 fn augment_args_for_update(cmd: clap::Command) -> clap::Command {
284 Self::augment_args(cmd)
285 }
286}
287
288#[cfg(feature = "cli")]
289impl clap::FromArgMatches for LocationRuleExprs {
290 fn from_arg_matches(matches: &clap::ArgMatches) -> Result<Self, clap::Error> {
291 use clap::{Error, error::ErrorKind};
292
293 let patrs = matches
294 .get_many::<String>("expr")
295 .unwrap()
296 .cloned()
297 .collect::<Vec<_>>();
298
299 patrs
300 .join(" ")
301 .parse()
302 .map_err(snafu::Report::from_error)
303 .map_err(|e| Error::raw(ErrorKind::InvalidValue, e))
304 }
305
306 fn update_from_arg_matches(&mut self, matches: &clap::ArgMatches) -> Result<(), clap::Error> {
307 *self = Self::from_arg_matches(matches)?;
308 Ok(())
309 }
310}