Upstream commit: 474dd0229cb20cf513036619781ed97bd8073c3f Enterprise-only files removed or emptied: 63 Enterprise-only snippets removed: 117 in 50 files Dangling module declarations removed: 5 Cargo edits turning enterprise off: 14 Verification: clean Enterprise feature gates left for rebuilt features: 19 in 18 files Produced by tools/fork/strip.py. The full report is in docs/fork/strip-reports/ on main.
524 lines
12 KiB
Rust
524 lines
12 KiB
Rust
/*
|
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
|
*
|
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
|
*/
|
|
|
|
use compact_str::CompactString;
|
|
use regex::Regex;
|
|
use registry::schema::{
|
|
enums::{ExpressionConstant, ExpressionVariable},
|
|
structs::Rate,
|
|
};
|
|
use std::{
|
|
borrow::Cow,
|
|
fmt::{Display, Formatter},
|
|
net::{IpAddr, Ipv4Addr, Ipv6Addr},
|
|
str::FromStr,
|
|
time::Duration,
|
|
};
|
|
use trc::MetricType;
|
|
use utils::cache::CacheItemWeight;
|
|
|
|
use crate::expr::if_block::IfBlock;
|
|
|
|
pub mod eval;
|
|
pub mod functions;
|
|
pub mod if_block;
|
|
pub mod parser;
|
|
pub mod tokenizer;
|
|
|
|
#[derive(Debug, PartialEq, Eq, Clone, Default)]
|
|
#[repr(transparent)]
|
|
pub struct Expression {
|
|
pub items: Box<[ExpressionItem]>,
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum ExpressionItem {
|
|
Variable(ExpressionVariable),
|
|
Global(CompactString),
|
|
System(SystemVariable),
|
|
Capture(u32),
|
|
Constant(Constant),
|
|
BinaryOperator(BinaryOperator),
|
|
UnaryOperator(UnaryOperator),
|
|
Regex(Regex),
|
|
JmpIf { val: bool, pos: u32 },
|
|
Function { id: u32, num_args: u32 },
|
|
ArrayAccess,
|
|
ArrayBuild(u32),
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum Variable<'x> {
|
|
String(StringCow<'x>),
|
|
Integer(i64),
|
|
Float(f64),
|
|
Array(Vec<Variable<'x>>),
|
|
Constant(ExpressionConstant),
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum StringCow<'x> {
|
|
Owned(CompactString),
|
|
Borrowed(&'x str),
|
|
}
|
|
|
|
impl Default for Variable<'_> {
|
|
fn default() -> Self {
|
|
Variable::String(StringCow::Borrowed(""))
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
pub enum Constant {
|
|
Static(ExpressionConstant),
|
|
Integer(i64),
|
|
Float(f64),
|
|
String(CompactString),
|
|
}
|
|
|
|
impl Eq for Constant {}
|
|
|
|
impl From<CompactString> for Constant {
|
|
fn from(value: CompactString) -> Self {
|
|
Constant::String(value)
|
|
}
|
|
}
|
|
|
|
impl From<bool> for Constant {
|
|
fn from(value: bool) -> Self {
|
|
Constant::Integer(value as i64)
|
|
}
|
|
}
|
|
|
|
impl From<i64> for Constant {
|
|
fn from(value: i64) -> Self {
|
|
Constant::Integer(value)
|
|
}
|
|
}
|
|
|
|
impl From<i32> for Constant {
|
|
fn from(value: i32) -> Self {
|
|
Constant::Integer(value as i64)
|
|
}
|
|
}
|
|
|
|
impl From<i16> for Constant {
|
|
fn from(value: i16) -> Self {
|
|
Constant::Integer(value as i64)
|
|
}
|
|
}
|
|
|
|
impl From<f64> for Constant {
|
|
fn from(value: f64) -> Self {
|
|
Constant::Float(value)
|
|
}
|
|
}
|
|
|
|
impl From<usize> for Constant {
|
|
fn from(value: usize) -> Self {
|
|
Constant::Integer(value as i64)
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
|
pub enum BinaryOperator {
|
|
Add,
|
|
Subtract,
|
|
Multiply,
|
|
Divide,
|
|
|
|
And,
|
|
Or,
|
|
Xor,
|
|
|
|
Eq,
|
|
Ne,
|
|
Lt,
|
|
Le,
|
|
Gt,
|
|
Ge,
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
|
pub enum UnaryOperator {
|
|
Not,
|
|
Minus,
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum Token {
|
|
Variable(ExpressionVariable),
|
|
Global(CompactString),
|
|
Capture(u32),
|
|
Function {
|
|
name: Cow<'static, str>,
|
|
id: u32,
|
|
num_args: u32,
|
|
},
|
|
Constant(Constant),
|
|
System(SystemVariable),
|
|
Regex(Regex),
|
|
BinaryOperator(BinaryOperator),
|
|
UnaryOperator(UnaryOperator),
|
|
OpenParen,
|
|
CloseParen,
|
|
OpenBracket,
|
|
CloseBracket,
|
|
Comma,
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum SystemVariable {
|
|
Hostname,
|
|
Domain,
|
|
NodeId,
|
|
NodeHostname,
|
|
NodeRole,
|
|
Metric(MetricType),
|
|
}
|
|
|
|
impl From<usize> for Variable<'_> {
|
|
fn from(value: usize) -> Self {
|
|
Variable::Integer(value as i64)
|
|
}
|
|
}
|
|
|
|
impl From<i64> for Variable<'_> {
|
|
fn from(value: i64) -> Self {
|
|
Variable::Integer(value)
|
|
}
|
|
}
|
|
|
|
impl From<u64> for Variable<'_> {
|
|
fn from(value: u64) -> Self {
|
|
Variable::Integer(value as i64)
|
|
}
|
|
}
|
|
|
|
impl From<i32> for Variable<'_> {
|
|
fn from(value: i32) -> Self {
|
|
Variable::Integer(value as i64)
|
|
}
|
|
}
|
|
|
|
impl From<u32> for Variable<'_> {
|
|
fn from(value: u32) -> Self {
|
|
Variable::Integer(value as i64)
|
|
}
|
|
}
|
|
|
|
impl From<u16> for Variable<'_> {
|
|
fn from(value: u16) -> Self {
|
|
Variable::Integer(value as i64)
|
|
}
|
|
}
|
|
|
|
impl From<i16> for Variable<'_> {
|
|
fn from(value: i16) -> Self {
|
|
Variable::Integer(value as i64)
|
|
}
|
|
}
|
|
|
|
impl From<f64> for Variable<'_> {
|
|
fn from(value: f64) -> Self {
|
|
Variable::Float(value)
|
|
}
|
|
}
|
|
|
|
impl<'x> From<&'x str> for Variable<'x> {
|
|
fn from(value: &'x str) -> Self {
|
|
Variable::String(StringCow::Borrowed(value))
|
|
}
|
|
}
|
|
|
|
impl From<CompactString> for Variable<'_> {
|
|
fn from(value: CompactString) -> Self {
|
|
Variable::String(StringCow::Owned(value))
|
|
}
|
|
}
|
|
|
|
impl<'x> From<Vec<Variable<'x>>> for Variable<'x> {
|
|
fn from(value: Vec<Variable<'x>>) -> Self {
|
|
Variable::Array(value)
|
|
}
|
|
}
|
|
|
|
impl From<bool> for Variable<'_> {
|
|
fn from(value: bool) -> Self {
|
|
Variable::Integer(value as i64)
|
|
}
|
|
}
|
|
|
|
impl<T: Into<Constant>> From<T> for Expression {
|
|
fn from(value: T) -> Self {
|
|
Expression {
|
|
items: Box::new([ExpressionItem::Constant(value.into())]),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl PartialEq for ExpressionItem {
|
|
fn eq(&self, other: &Self) -> bool {
|
|
match (self, other) {
|
|
(Self::Variable(l0), Self::Variable(r0)) => l0 == r0,
|
|
(Self::Constant(l0), Self::Constant(r0)) => l0 == r0,
|
|
(Self::BinaryOperator(l0), Self::BinaryOperator(r0)) => l0 == r0,
|
|
(Self::UnaryOperator(l0), Self::UnaryOperator(r0)) => l0 == r0,
|
|
(Self::Regex(_), Self::Regex(_)) => true,
|
|
(
|
|
Self::JmpIf {
|
|
val: l_val,
|
|
pos: l_pos,
|
|
},
|
|
Self::JmpIf {
|
|
val: r_val,
|
|
pos: r_pos,
|
|
},
|
|
) => l_val == r_val && l_pos == r_pos,
|
|
(
|
|
Self::Function {
|
|
id: l_id,
|
|
num_args: l_num_args,
|
|
},
|
|
Self::Function {
|
|
id: r_id,
|
|
num_args: r_num_args,
|
|
},
|
|
) => l_id == r_id && l_num_args == r_num_args,
|
|
(Self::ArrayBuild(l0), Self::ArrayBuild(r0)) => l0 == r0,
|
|
_ => core::mem::discriminant(self) == core::mem::discriminant(other),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Eq for ExpressionItem {}
|
|
|
|
impl PartialEq for Token {
|
|
fn eq(&self, other: &Self) -> bool {
|
|
match (self, other) {
|
|
(Self::Variable(l0), Self::Variable(r0)) => l0 == r0,
|
|
(
|
|
Self::Function {
|
|
name: l_name,
|
|
id: l_id,
|
|
num_args: l_num_args,
|
|
},
|
|
Self::Function {
|
|
name: r_name,
|
|
id: r_id,
|
|
num_args: r_num_args,
|
|
},
|
|
) => l_name == r_name && l_id == r_id && l_num_args == r_num_args,
|
|
(Self::Constant(l0), Self::Constant(r0)) => l0 == r0,
|
|
(Self::Regex(_), Self::Regex(_)) => true,
|
|
(Self::BinaryOperator(l0), Self::BinaryOperator(r0)) => l0 == r0,
|
|
(Self::UnaryOperator(l0), Self::UnaryOperator(r0)) => l0 == r0,
|
|
_ => core::mem::discriminant(self) == core::mem::discriminant(other),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Eq for Token {}
|
|
|
|
impl From<()> for Constant {
|
|
fn from(_: ()) -> Self {
|
|
Constant::Integer(0)
|
|
}
|
|
}
|
|
|
|
impl<'x> TryFrom<Variable<'x>> for () {
|
|
type Error = ();
|
|
|
|
fn try_from(_: Variable<'x>) -> Result<Self, Self::Error> {
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl<'x> TryFrom<Variable<'x>> for Duration {
|
|
type Error = ();
|
|
|
|
fn try_from(value: Variable<'x>) -> Result<Self, Self::Error> {
|
|
match value {
|
|
Variable::Integer(value) if value > 0 => Ok(Duration::from_millis(value as u64)),
|
|
Variable::Float(value) if value > 0.0 => Ok(Duration::from_millis(value as u64)),
|
|
Variable::String(value) if !value.is_empty() => {
|
|
registry::types::duration::Duration::from_str(value.as_str())
|
|
.map(|v| v.into_inner())
|
|
.map_err(|_| ())
|
|
}
|
|
_ => Err(()),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl StringCow<'_> {
|
|
pub fn as_str(&self) -> &str {
|
|
match self {
|
|
StringCow::Owned(s) => s.as_str(),
|
|
StringCow::Borrowed(s) => s,
|
|
}
|
|
}
|
|
|
|
pub fn as_bytes(&self) -> &[u8] {
|
|
match self {
|
|
StringCow::Owned(s) => s.as_bytes(),
|
|
StringCow::Borrowed(s) => s.as_bytes(),
|
|
}
|
|
}
|
|
|
|
pub fn is_empty(&self) -> bool {
|
|
match self {
|
|
StringCow::Owned(s) => s.is_empty(),
|
|
StringCow::Borrowed(s) => s.is_empty(),
|
|
}
|
|
}
|
|
|
|
pub fn len(&self) -> usize {
|
|
match self {
|
|
StringCow::Owned(s) => s.len(),
|
|
StringCow::Borrowed(s) => s.len(),
|
|
}
|
|
}
|
|
|
|
pub fn into_owned(self) -> CompactString {
|
|
match self {
|
|
StringCow::Owned(s) => s,
|
|
StringCow::Borrowed(s) => s.into(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'x> From<Cow<'x, str>> for StringCow<'x> {
|
|
fn from(value: Cow<'x, str>) -> Self {
|
|
match value {
|
|
Cow::Borrowed(s) => StringCow::Borrowed(s),
|
|
Cow::Owned(s) => StringCow::Owned(s.into()),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<CompactString> for StringCow<'_> {
|
|
fn from(value: CompactString) -> Self {
|
|
StringCow::Owned(value)
|
|
}
|
|
}
|
|
|
|
impl AsRef<str> for StringCow<'_> {
|
|
fn as_ref(&self) -> &str {
|
|
self.as_str()
|
|
}
|
|
}
|
|
|
|
impl AsRef<[u8]> for StringCow<'_> {
|
|
fn as_ref(&self) -> &[u8] {
|
|
self.as_str().as_bytes()
|
|
}
|
|
}
|
|
|
|
impl Display for StringCow<'_> {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
match self {
|
|
StringCow::Owned(s) => write!(f, "{}", s),
|
|
StringCow::Borrowed(s) => write!(f, "{}", s),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<Duration> for Constant {
|
|
fn from(value: Duration) -> Self {
|
|
Constant::Integer(value.as_millis() as i64)
|
|
}
|
|
}
|
|
|
|
impl<'x> TryFrom<Variable<'x>> for Rate {
|
|
type Error = ();
|
|
|
|
fn try_from(value: Variable<'x>) -> Result<Self, Self::Error> {
|
|
match value {
|
|
Variable::Array(items) if items.len() == 2 => {
|
|
let requests = items[0].to_integer().ok_or(())?;
|
|
let period = items[1].to_integer().ok_or(())?;
|
|
|
|
if requests > 0 && period > 0 {
|
|
Ok(Rate {
|
|
count: requests as u64,
|
|
period: registry::types::duration::Duration::from_millis(period as u64),
|
|
})
|
|
} else {
|
|
Err(())
|
|
}
|
|
}
|
|
_ => Err(()),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'x> TryFrom<Variable<'x>> for Ipv4Addr {
|
|
type Error = ();
|
|
|
|
fn try_from(value: Variable<'x>) -> Result<Self, Self::Error> {
|
|
match value {
|
|
Variable::String(value) => value.as_str().parse().map_err(|_| ()),
|
|
_ => Err(()),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'x> TryFrom<Variable<'x>> for Ipv6Addr {
|
|
type Error = ();
|
|
|
|
fn try_from(value: Variable<'x>) -> Result<Self, Self::Error> {
|
|
match value {
|
|
Variable::String(value) => value.as_str().parse().map_err(|_| ()),
|
|
_ => Err(()),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'x> TryFrom<Variable<'x>> for IpAddr {
|
|
type Error = ();
|
|
|
|
fn try_from(value: Variable<'x>) -> Result<Self, Self::Error> {
|
|
match value {
|
|
Variable::String(value) => value.as_str().parse().map_err(|_| ()),
|
|
_ => Err(()),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'x, T: TryFrom<Variable<'x>>> TryFrom<Variable<'x>> for Vec<T>
|
|
where
|
|
Result<Vec<T>, ()>: FromIterator<Result<T, <T as TryFrom<Variable<'x>>>::Error>>,
|
|
{
|
|
type Error = ();
|
|
|
|
fn try_from(value: Variable<'x>) -> Result<Self, Self::Error> {
|
|
value
|
|
.into_array()
|
|
.into_iter()
|
|
.map(|v| T::try_from(v))
|
|
.collect()
|
|
}
|
|
}
|
|
|
|
impl CacheItemWeight for Expression {
|
|
fn weight(&self) -> u64 {
|
|
self.items.len() as u64 * std::mem::size_of::<ExpressionItem>() as u64
|
|
}
|
|
}
|
|
|
|
impl CacheItemWeight for IfBlock {
|
|
fn weight(&self) -> u64 {
|
|
std::mem::size_of::<IfBlock>() as u64
|
|
+ self
|
|
.if_then
|
|
.iter()
|
|
.map(|if_then| if_then.expr.weight() + if_then.then.weight())
|
|
.sum::<u64>()
|
|
+ self.default.weight()
|
|
}
|
|
}
|