use super::{FilterExpr, Value};
use alloc::boxed::Box;
use alloc::string::String;
use alloc::vec::Vec;
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum FormulaExpr {
Constant {
value: f64,
},
Variable {
name: String,
},
Sum {
left: Box<FormulaExpr>,
right: Box<FormulaExpr>,
},
Sub {
left: Box<FormulaExpr>,
right: Box<FormulaExpr>,
},
Mul {
left: Box<FormulaExpr>,
right: Box<FormulaExpr>,
},
Div {
left: Box<FormulaExpr>,
right: Box<FormulaExpr>,
by_zero_default: Option<f64>,
},
Neg {
operand: Box<FormulaExpr>,
},
Abs {
x: Box<FormulaExpr>,
},
Sqrt {
x: Box<FormulaExpr>,
},
Log {
x: Box<FormulaExpr>,
},
Ln {
x: Box<FormulaExpr>,
},
Exp {
x: Box<FormulaExpr>,
},
Acosh {
x: Box<FormulaExpr>,
},
Pow {
base: Box<FormulaExpr>,
exponent: Box<FormulaExpr>,
},
Max {
args: Vec<FormulaExpr>,
},
Min {
args: Vec<FormulaExpr>,
},
GeoDistance {
lat: f64,
lon: f64,
field: String,
},
Decay {
kind: String,
x: Box<FormulaExpr>,
target: Option<Box<FormulaExpr>>,
scale: Option<f64>,
midpoint: Option<f64>,
},
Case {
cond: Box<FilterExpr>,
then_: Box<FormulaExpr>,
else_: Box<FormulaExpr>,
},
MatchCondition {
field: String,
values: Vec<Value>,
},
Datetime {
value: String,
},
DatetimeKey {
key: String,
},
}
pub fn looks_like_iso_datetime(s: &str) -> bool {
let bytes = s.as_bytes();
if bytes.len() < 10 {
return false;
}
if !bytes[0..4].iter().all(u8::is_ascii_digit)
|| bytes[4] != b'-'
|| !bytes[5..7].iter().all(u8::is_ascii_digit)
|| bytes[7] != b'-'
|| !bytes[8..10].iter().all(u8::is_ascii_digit)
{
return false;
}
if bytes.len() == 10 {
return true;
}
let sep = bytes[10];
if sep != b'T' && sep != b't' && sep != b' ' {
return false;
}
if bytes.len() < 19 {
return false;
}
if !bytes[11..13].iter().all(u8::is_ascii_digit)
|| bytes[13] != b':'
|| !bytes[14..16].iter().all(u8::is_ascii_digit)
|| bytes[16] != b':'
|| !bytes[17..19].iter().all(u8::is_ascii_digit)
{
return false;
}
let mut i = 19;
if i < bytes.len() && bytes[i] == b'.' {
i += 1;
let frac_start = i;
while i < bytes.len() && bytes[i].is_ascii_digit() {
i += 1;
}
if i == frac_start {
return false; }
}
if i == bytes.len() {
return true;
}
if bytes[i] == b'Z' || bytes[i] == b'z' {
return i + 1 == bytes.len();
}
if bytes[i] == b'+' || bytes[i] == b'-' {
i += 1;
let tz_start = i;
while i < bytes.len() && (bytes[i].is_ascii_digit() || bytes[i] == b':') {
i += 1;
}
let tz_len = i - tz_start;
if (tz_len == 2 || tz_len == 4 || tz_len == 5) && i == bytes.len() {
return true;
}
return false;
}
false
}