use bigdecimal::BigDecimal; use regex::Regex; use crate::formula_reader::FormulaReader; use crate::formula_string::FormulaString; use crate::formula_string::OperatorPriority; use crate::formula_writer::FormulaWriter; use crate::generic::*; use crate::types::*; use crate::value::EnumValueFormula; use crate::{ BoolArrayFormula, BoolFormula, DateArrayFormula, DateFormula, DateFormulas, DateTimeArrayFormula, DateTimeFormula, DateTimeFormulas, DecimalArrayFormula, DecimalFormula, DecimalFormulas, DeserializationError, DeserializedResult, ExecutionResult, Formula, FormulaContext, IntArrayFormula, IntFormula, IntFormulas, ObjectArrayFormula, ObjectFormula, StringArrayFormula, StringFormula, StringFormulas, }; const BOOL_OP_FALSE: u8 = 0x10; const BOOL_OP_TRUE: u8 = 0x11; const BOOL_OP_NOT: u8 = 0x12; const BOOL_OP_AND: u8 = 0x13; const BOOL_OP_OR: u8 = 0x14; const BOOL_OP_XOR: u8 = 0x15; const BOOL_OP_COMPARE_INT: u8 = 0x16; const BOOL_OP_COMPARE_DECIMAL: u8 = 0x17; const BOOL_OP_COMPARE_STRING: u8 = 0x18; const BOOL_OP_COMPARE_DATE: u8 = 0x19; const BOOL_OP_COMPARE_DATETIME: u8 = 0x1A; const BOOL_OP_MATCH_STRING_REGEX: u8 = 0x1B; const BOOL_EMPTY_BOOLARRAY: u8 = 0x1C; const BOOL_EMPTY_INTARRAY: u8 = 0x1D; const BOOL_EMPTY_DECIMALARRAY: u8 = 0x1E; const BOOL_EMPTY_STRINGARRAY: u8 = 0x1F; const BOOL_EMPTY_DATEARRAY: u8 = 0x20; const BOOL_EMPTY_DATETIMEARRAY: u8 = 0x21; const BOOL_EMPTY_OBJECTARRAY: u8 = 0x22; pub struct BoolFormulas {} impl BoolFormulas { pub fn from_bytes(bytes: &[u8]) -> Result { let mut reader = FormulaReader::new(bytes); Self::from_reader(&mut reader) } pub fn from_reader(reader: &mut FormulaReader) -> Result { let operator = reader.read_byte()?; match operator { GENERIC_OP_INVALID => InvalidFormula::::deserialize(reader), GENERIC_OP_DEFINE_LOCALS => DefineLocals::::deserialize(reader), GENERIC_OP_LOCAL => LocalVariable::::deserialize(reader), GENERIC_OP_OBJECT_FIELD => ObjectField::::deserialize(reader), GENERIC_OP_OBJECT_METHOD_CALL => ObjectMethodCall::::deserialize(reader), GENERIC_OP_ARRAY_ELEMENT => ArrayElement::::deserialize(reader), GENERIC_OP_ARRAY_ELEMENT_OR_DEFAULT => { ArrayElementOrDefault::::deserialize(reader) } GENERIC_OP_ARRAY_FIRST => ArrayFirst::::deserialize(reader), GENERIC_OP_ARRAY_LAST => ArrayLast::::deserialize(reader), GENERIC_OP_TERNARY => Ternary::::deserialize(reader), BOOL_OP_FALSE => Ok(Box::new(BoolFalse {})), BOOL_OP_TRUE => Ok(Box::new(BoolTrue {})), BOOL_OP_NOT => BoolNot::deserialize(reader), BOOL_OP_AND => BoolAnd::deserialize(reader), BOOL_OP_OR => BoolOr::deserialize(reader), BOOL_OP_XOR => BoolXor::deserialize(reader), BOOL_OP_COMPARE_INT => BoolCompareInt::deserialize(reader), BOOL_OP_COMPARE_DECIMAL => BoolCompareDecimal::deserialize(reader), BOOL_OP_COMPARE_DATE => BoolCompareDate::deserialize(reader), BOOL_OP_COMPARE_DATETIME => BoolCompareDateTime::deserialize(reader), BOOL_OP_COMPARE_STRING => BoolCompareString::deserialize(reader), BOOL_OP_MATCH_STRING_REGEX => BoolMatchStringRegex::deserialize(reader), BOOL_EMPTY_BOOLARRAY => EmptyArray::::deserialize(reader), BOOL_EMPTY_INTARRAY => EmptyArray::::deserialize(reader), BOOL_EMPTY_DECIMALARRAY => EmptyArray::::deserialize(reader), BOOL_EMPTY_STRINGARRAY => EmptyArray::::deserialize(reader), BOOL_EMPTY_DATEARRAY => EmptyArray::::deserialize(reader), BOOL_EMPTY_DATETIMEARRAY => EmptyArray::::deserialize(reader), BOOL_EMPTY_OBJECTARRAY => EmptyArray::::deserialize(reader), other => Err(DeserializationError::UnknownOperator(Type::Bool, other)), } } pub fn invalid(formula: String) -> BoolFormula { InvalidFormula::::new(formula) } pub fn define_locals(locals: Vec, formula: BoolFormula) -> BoolFormula { DefineLocals::::new(locals, formula) } pub fn local(index: u32) -> BoolFormula { LocalVariable::::new(index) } pub fn object_field(object: ObjectFormula, field: String) -> BoolFormula { ObjectField::::new(object, field) } pub fn object_method_call( object: ObjectFormula, method: String, arguments: Vec, ) -> BoolFormula { ObjectMethodCall::::new(object, method, arguments) } pub fn array_element(array: BoolArrayFormula, index: IntFormula) -> BoolFormula { ArrayElement::::new(array, index) } pub fn array_element_or_default( array: BoolArrayFormula, index: IntFormula, default: BoolFormula, ) -> BoolFormula { ArrayElementOrDefault::::new(array, index, default) } pub fn array_first(array: BoolArrayFormula) -> BoolFormula { ArrayFirst::::new(array) } pub fn array_last(array: BoolArrayFormula) -> BoolFormula { ArrayLast::::new(array) } pub fn ternary( condition: BoolFormula, true_value: BoolFormula, false_value: BoolFormula, ) -> BoolFormula { Ternary::::new(condition, true_value, false_value) } pub fn constant(value: bool) -> BoolFormula { if value { BoolTrue::new() } else { BoolFalse::new() } } pub fn not(operand: BoolFormula) -> BoolFormula { BoolNot::new(operand) } pub fn and(left: BoolFormula, right: BoolFormula) -> BoolFormula { BoolAnd::new(left, right) } pub fn or(left: BoolFormula, right: BoolFormula) -> BoolFormula { BoolOr::new(left, right) } pub fn xor(left: BoolFormula, right: BoolFormula) -> BoolFormula { BoolXor::new(left, right) } pub fn compare_int(left: IntFormula, right: IntFormula, comparator: Comparator) -> BoolFormula { BoolCompareInt::new(left, right, comparator) } pub fn compare_decimal( left: DecimalFormula, right: DecimalFormula, comparator: Comparator, ) -> BoolFormula { BoolCompareDecimal::new(left, right, comparator) } pub fn compare_string( left: StringFormula, right: StringFormula, comparator: Comparator, ) -> BoolFormula { BoolCompareString::new(left, right, comparator) } pub fn compare_date( left: DateFormula, right: DateFormula, comparator: Comparator, ) -> BoolFormula { BoolCompareDate::new(left, right, comparator) } pub fn compare_datetime( left: DateTimeFormula, right: DateTimeFormula, comparator: Comparator, ) -> BoolFormula { BoolCompareDateTime::new(left, right, comparator) } pub fn match_string_regex(string: StringFormula, regex: Regex) -> BoolFormula { BoolMatchStringRegex::new(string, regex) } pub fn array_empty_bool(array: BoolArrayFormula) -> BoolFormula { EmptyArray::::new(array) } pub fn array_empty_int(array: IntArrayFormula) -> BoolFormula { EmptyArray::::new(array) } pub fn array_empty_decimal(array: DecimalArrayFormula) -> BoolFormula { EmptyArray::::new(array) } pub fn array_empty_string(array: StringArrayFormula) -> BoolFormula { EmptyArray::::new(array) } pub fn array_empty_date(array: DateArrayFormula) -> BoolFormula { EmptyArray::::new(array) } pub fn array_empty_datetime(array: DateTimeArrayFormula) -> BoolFormula { EmptyArray::::new(array) } pub fn array_empty_object(array: ObjectArrayFormula) -> BoolFormula { EmptyArray::::new(array) } } #[derive(Debug)] pub enum Comparator { Equal, NotEqual, LessThan, LessThanOrEqual, GreaterThan, GreaterThanOrEqual, } impl Comparator { pub fn deserialize(value: u8) -> Result { match value { 0 => Ok(Comparator::Equal), 1 => Ok(Comparator::NotEqual), 2 => Ok(Comparator::LessThan), 3 => Ok(Comparator::LessThanOrEqual), 4 => Ok(Comparator::GreaterThan), 5 => Ok(Comparator::GreaterThanOrEqual), other => Err(DeserializationError::UnknownComparator(other)), } } pub fn serialize(&self) -> u8 { match self { Comparator::Equal => 0, Comparator::NotEqual => 1, Comparator::LessThan => 2, Comparator::LessThanOrEqual => 3, Comparator::GreaterThan => 4, Comparator::GreaterThanOrEqual => 5, } } pub fn to_string(&self) -> &'static str { match self { Comparator::Equal => "=", Comparator::NotEqual => "!=", Comparator::LessThan => "<", Comparator::LessThanOrEqual => "<=", Comparator::GreaterThan => ">", Comparator::GreaterThanOrEqual => ">=", } } } struct BoolFalse {} impl BoolFalse { pub fn new() -> BoolFormula { Box::new(Self {}) } } impl Formula for BoolFalse { fn evaluate(&self, _context: &FormulaContext) -> ExecutionResult { Ok(false) } fn serialize_to(&self, writer: &mut FormulaWriter) { writer.write_byte(BOOL_OP_FALSE); } fn to_formula_string(&self) -> FormulaString { FormulaString::new("false".to_string(), OperatorPriority::Literal) } } struct BoolTrue {} impl BoolTrue { pub fn new() -> BoolFormula { Box::new(Self {}) } } impl Formula for BoolTrue { fn evaluate(&self, _context: &FormulaContext) -> ExecutionResult { Ok(true) } fn serialize_to(&self, writer: &mut FormulaWriter) { writer.write_byte(BOOL_OP_TRUE); } fn to_formula_string(&self) -> FormulaString { FormulaString::new("true".to_string(), OperatorPriority::Literal) } } struct BoolNot { operand: BoolFormula, } impl BoolNot { pub fn new(operand: BoolFormula) -> BoolFormula { Box::new(Self { operand }) } pub fn deserialize(reader: &mut FormulaReader) -> DeserializedResult { let operand = BoolFormulas::from_reader(reader)?; Ok(Box::new(Self { operand })) } } impl Formula for BoolNot { fn evaluate(&self, context: &FormulaContext) -> ExecutionResult { let operand = self.operand.evaluate(context)?; Ok(!operand) } fn serialize_to(&self, writer: &mut FormulaWriter) { writer.write_byte(BOOL_OP_NOT); self.operand.serialize_to(writer); } fn to_formula_string(&self) -> FormulaString { FormulaString::unary(self.operand.as_ref(), OperatorPriority::Unary, |operand| { format!("!{}", operand) }) } } struct BoolOr { left: BoolFormula, right: BoolFormula, } impl BoolOr { pub fn new(left: BoolFormula, right: BoolFormula) -> BoolFormula { Box::new(Self { left, right }) } pub fn deserialize(reader: &mut FormulaReader) -> DeserializedResult { let left = BoolFormulas::from_reader(reader)?; let right = BoolFormulas::from_reader(reader)?; Ok(Box::new(Self { left, right })) } } impl Formula for BoolOr { fn evaluate(&self, context: &FormulaContext) -> ExecutionResult { let left = self.left.evaluate(context)?; let right = self.right.evaluate(context)?; Ok(left || right) } fn serialize_to(&self, writer: &mut FormulaWriter) { writer.write_byte(BOOL_OP_OR); self.left.serialize_to(writer); self.right.serialize_to(writer); } fn to_formula_string(&self) -> FormulaString { FormulaString::binary( self.left.as_ref(), self.right.as_ref(), OperatorPriority::Or, |left, right| format!("{} || {}", left, right), ) } } struct BoolAnd { left: BoolFormula, right: BoolFormula, } impl BoolAnd { pub fn new(left: BoolFormula, right: BoolFormula) -> BoolFormula { Box::new(Self { left, right }) } pub fn deserialize(reader: &mut FormulaReader) -> DeserializedResult { let left = BoolFormulas::from_reader(reader)?; let right = BoolFormulas::from_reader(reader)?; Ok(Box::new(Self { left, right })) } } impl Formula for BoolAnd { fn evaluate(&self, context: &FormulaContext) -> ExecutionResult { let left = self.left.evaluate(context)?; let right = self.right.evaluate(context)?; Ok(left && right) } fn serialize_to(&self, writer: &mut FormulaWriter) { writer.write_byte(BOOL_OP_AND); self.left.serialize_to(writer); self.right.serialize_to(writer); } fn to_formula_string(&self) -> FormulaString { FormulaString::binary( self.left.as_ref(), self.right.as_ref(), OperatorPriority::And, |left, right| format!("{} && {}", left, right), ) } } struct BoolXor { left: BoolFormula, right: BoolFormula, } impl BoolXor { pub fn new(left: BoolFormula, right: BoolFormula) -> BoolFormula { Box::new(Self { left, right }) } pub fn deserialize(reader: &mut FormulaReader) -> DeserializedResult { let left = BoolFormulas::from_reader(reader)?; let right = BoolFormulas::from_reader(reader)?; Ok(Box::new(Self { left, right })) } } impl Formula for BoolXor { fn evaluate(&self, context: &FormulaContext) -> ExecutionResult { let left = self.left.evaluate(context)?; let right = self.right.evaluate(context)?; Ok(left ^ right) } fn serialize_to(&self, writer: &mut FormulaWriter) { writer.write_byte(BOOL_OP_XOR); self.left.serialize_to(writer); self.right.serialize_to(writer); } fn to_formula_string(&self) -> FormulaString { let left = self.left.to_formula_string(); let right = self.right.to_formula_string(); FormulaString::new( format!( "{} ^ {}", left.wrap(OperatorPriority::Or), right.wrap(OperatorPriority::Or) ), OperatorPriority::Or, ) } } struct BoolCompareInt { left: IntFormula, right: IntFormula, comparator: Comparator, } impl BoolCompareInt { pub fn new(left: IntFormula, right: IntFormula, comparator: Comparator) -> BoolFormula { Box::new(Self { left, right, comparator, }) } pub fn deserialize(reader: &mut FormulaReader) -> DeserializedResult { let comparator = Comparator::deserialize(reader.read_byte()?)?; let left = IntFormulas::from_reader(reader)?; let right = IntFormulas::from_reader(reader)?; Ok(Box::new(Self { left, right, comparator, })) } } impl Formula for BoolCompareInt { fn evaluate(&self, context: &FormulaContext) -> ExecutionResult { let left = self.left.evaluate(context)?; let right = self.right.evaluate(context)?; match self.comparator { Comparator::Equal => Ok(left == right), Comparator::NotEqual => Ok(left != right), Comparator::LessThan => Ok(left < right), Comparator::LessThanOrEqual => Ok(left <= right), Comparator::GreaterThan => Ok(left > right), Comparator::GreaterThanOrEqual => Ok(left >= right), } } fn serialize_to(&self, writer: &mut FormulaWriter) { writer.write_byte(BOOL_OP_COMPARE_INT); writer.write_byte(self.comparator.serialize()); self.left.serialize_to(writer); self.right.serialize_to(writer); } fn to_formula_string(&self) -> FormulaString { let left = self.left.to_formula_string(); let right = self.right.to_formula_string(); FormulaString::new( format!( "{} {} {}", left.wrap(OperatorPriority::Comparison), self.comparator.to_string(), right.wrap(OperatorPriority::Comparison) ), OperatorPriority::Comparison, ) } } struct BoolCompareDecimal { left: Box>, right: Box>, comparator: Comparator, } impl BoolCompareDecimal { pub fn new( left: Box>, right: Box>, comparator: Comparator, ) -> BoolFormula { Box::new(Self { left, right, comparator, }) } pub fn deserialize(reader: &mut FormulaReader) -> DeserializedResult { let comparator = Comparator::deserialize(reader.read_byte()?)?; let left = DecimalFormulas::from_reader(reader)?; let right = DecimalFormulas::from_reader(reader)?; Ok(Box::new(Self { left, right, comparator, })) } } impl Formula for BoolCompareDecimal { fn evaluate(&self, context: &FormulaContext) -> ExecutionResult { let left = self.left.evaluate(context)?; let right = self.right.evaluate(context)?; match self.comparator { Comparator::Equal => Ok(left == right), Comparator::NotEqual => Ok(left != right), Comparator::LessThan => Ok(left < right), Comparator::LessThanOrEqual => Ok(left <= right), Comparator::GreaterThan => Ok(left > right), Comparator::GreaterThanOrEqual => Ok(left >= right), } } fn serialize_to(&self, writer: &mut FormulaWriter) { writer.write_byte(BOOL_OP_COMPARE_DECIMAL); writer.write_byte(self.comparator.serialize()); self.left.serialize_to(writer); self.right.serialize_to(writer); } fn to_formula_string(&self) -> FormulaString { let left = self.left.to_formula_string(); let right = self.right.to_formula_string(); FormulaString::new( format!( "{} {} {}", left.wrap(OperatorPriority::Comparison), self.comparator.to_string(), right.wrap(OperatorPriority::Comparison) ), OperatorPriority::Comparison, ) } } struct BoolCompareString { left: StringFormula, right: StringFormula, comparator: Comparator, } impl BoolCompareString { pub fn new(left: StringFormula, right: StringFormula, comparator: Comparator) -> BoolFormula { Box::new(Self { left, right, comparator, }) } pub fn deserialize(reader: &mut FormulaReader) -> DeserializedResult { let comparator = Comparator::deserialize(reader.read_byte()?)?; let left = StringFormulas::from_reader(reader)?; let right = StringFormulas::from_reader(reader)?; Ok(Box::new(Self { left, right, comparator, })) } } impl Formula for BoolCompareString { fn evaluate(&self, context: &FormulaContext) -> ExecutionResult { let left = self.left.evaluate(context)?; let right = self.right.evaluate(context)?; match self.comparator { Comparator::Equal => Ok(left == right), Comparator::NotEqual => Ok(left != right), Comparator::LessThan => Ok(left < right), Comparator::LessThanOrEqual => Ok(left <= right), Comparator::GreaterThan => Ok(left > right), Comparator::GreaterThanOrEqual => Ok(left >= right), } } fn serialize_to(&self, writer: &mut FormulaWriter) { writer.write_byte(BOOL_OP_COMPARE_STRING); writer.write_byte(self.comparator.serialize()); self.left.serialize_to(writer); self.right.serialize_to(writer); } fn to_formula_string(&self) -> FormulaString { let left = self.left.to_formula_string(); let right = self.right.to_formula_string(); FormulaString::new( format!( "{} {} {}", left.wrap(OperatorPriority::Comparison), self.comparator.to_string(), right.wrap(OperatorPriority::Comparison) ), OperatorPriority::Comparison, ) } } struct BoolCompareDate { left: DateFormula, right: DateFormula, comparator: Comparator, } impl BoolCompareDate { pub fn new(left: DateFormula, right: DateFormula, comparator: Comparator) -> BoolFormula { Box::new(Self { left, right, comparator, }) } pub fn deserialize(reader: &mut FormulaReader) -> DeserializedResult { let comparator = Comparator::deserialize(reader.read_byte()?)?; let left = DateFormulas::from_reader(reader)?; let right = DateFormulas::from_reader(reader)?; Ok(Box::new(Self { left, right, comparator, })) } } impl Formula for BoolCompareDate { fn evaluate(&self, context: &FormulaContext) -> ExecutionResult { let left = self.left.evaluate(context)?; let right = self.right.evaluate(context)?; match self.comparator { Comparator::Equal => Ok(left == right), Comparator::NotEqual => Ok(left != right), Comparator::LessThan => Ok(left < right), Comparator::LessThanOrEqual => Ok(left <= right), Comparator::GreaterThan => Ok(left > right), Comparator::GreaterThanOrEqual => Ok(left >= right), } } fn serialize_to(&self, writer: &mut FormulaWriter) { writer.write_byte(BOOL_OP_COMPARE_DATE); writer.write_byte(self.comparator.serialize()); self.left.serialize_to(writer); self.right.serialize_to(writer); } fn to_formula_string(&self) -> FormulaString { let left = self.left.to_formula_string(); let right = self.right.to_formula_string(); FormulaString::new( format!( "{} {} {}", left.wrap(OperatorPriority::Comparison), self.comparator.to_string(), right.wrap(OperatorPriority::Comparison) ), OperatorPriority::Comparison, ) } } struct BoolCompareDateTime { left: DateTimeFormula, right: DateTimeFormula, comparator: Comparator, } impl BoolCompareDateTime { pub fn new( left: DateTimeFormula, right: DateTimeFormula, comparator: Comparator, ) -> BoolFormula { Box::new(Self { left, right, comparator, }) } pub fn deserialize(reader: &mut FormulaReader) -> DeserializedResult { let comparator = Comparator::deserialize(reader.read_byte()?)?; let left = DateTimeFormulas::from_reader(reader)?; let right = DateTimeFormulas::from_reader(reader)?; Ok(Box::new(Self { left, right, comparator, })) } } impl Formula for BoolCompareDateTime { fn evaluate(&self, context: &FormulaContext) -> ExecutionResult { let left = self.left.evaluate(context)?; let right = self.right.evaluate(context)?; match self.comparator { Comparator::Equal => Ok(left == right), Comparator::NotEqual => Ok(left != right), Comparator::LessThan => Ok(left < right), Comparator::LessThanOrEqual => Ok(left <= right), Comparator::GreaterThan => Ok(left > right), Comparator::GreaterThanOrEqual => Ok(left >= right), } } fn serialize_to(&self, writer: &mut FormulaWriter) { writer.write_byte(BOOL_OP_COMPARE_DATETIME); writer.write_byte(self.comparator.serialize()); self.left.serialize_to(writer); self.right.serialize_to(writer); } fn to_formula_string(&self) -> FormulaString { let left = self.left.to_formula_string(); let right = self.right.to_formula_string(); FormulaString::new( format!( "{} {} {}", left.wrap(OperatorPriority::Comparison), self.comparator.to_string(), right.wrap(OperatorPriority::Comparison) ), OperatorPriority::Comparison, ) } } struct BoolMatchStringRegex { string: StringFormula, regex: Regex, } impl BoolMatchStringRegex { pub fn new(string: StringFormula, regex: Regex) -> BoolFormula { Box::new(Self { string, regex }) } pub fn deserialize(reader: &mut FormulaReader) -> DeserializedResult { let string = StringFormulas::from_reader(reader)?; let regex = reader.read_string()?; let regex = Regex::new(®ex).map_err(|_| DeserializationError::InvalidRegex(regex))?; Ok(Box::new(Self { string, regex })) } } impl Formula for BoolMatchStringRegex { fn evaluate(&self, context: &FormulaContext) -> ExecutionResult { let string = self.string.evaluate(context)?; Ok(self.regex.is_match(&string)) } fn serialize_to(&self, writer: &mut FormulaWriter) { writer.write_byte(BOOL_OP_MATCH_STRING_REGEX); self.string.serialize_to(writer); writer.write_string(&self.regex.as_str()); } fn to_formula_string(&self) -> FormulaString { FormulaString::new( format!( "{}.match({})", self.string.to_string(), self.regex.as_str().replace("/", r"\/") ), OperatorPriority::Comparison, ) } } struct EmptyArray { array: Box>>, } impl EmptyArray { pub fn new(array: Box>>) -> BoolFormula { Box::new(Self { array }) } pub fn deserialize(reader: &mut FormulaReader) -> DeserializedResult { let array = T::ARRAY::formula_from_reader(reader)?; Ok(Self::new(array)) } } impl Formula for EmptyArray { fn evaluate(&self, context: &FormulaContext) -> ExecutionResult { let array = self.array.evaluate(context)?; Ok(array.is_empty()) } fn serialize_to(&self, writer: &mut FormulaWriter) { let op = match T::TYPE { Type::Bool => BOOL_EMPTY_BOOLARRAY, Type::Int => BOOL_EMPTY_INTARRAY, Type::Decimal => BOOL_EMPTY_DECIMALARRAY, Type::String => BOOL_EMPTY_STRINGARRAY, Type::Date => BOOL_EMPTY_DATEARRAY, Type::DateTime => BOOL_EMPTY_DATETIMEARRAY, Type::Object => BOOL_EMPTY_OBJECTARRAY, _ => unreachable!(), }; writer.write_byte(op); self.array.serialize_to(writer); } fn to_formula_string(&self) -> crate::formula_string::FormulaString { FormulaString::unary(self.array.as_ref(), OperatorPriority::Member, |array| { format!("{}.empty", array) }) } } #[cfg(test)] mod tests { use crate::{bool_formula::Comparator, object::TestObject, value::Value, ObjectFormulas}; #[test] fn test_local() { let formula = crate::BoolFormulas::local(0); let mut context = crate::FormulaContext::new_with_empty_root(); context.locals.push(Value::Bool(true)); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, true); let serialized = formula.serialize(); let deserialized = crate::BoolFormulas::from_bytes(&serialized).unwrap(); let result = deserialized.evaluate(&context).unwrap(); assert_eq!(result, true); } #[test] fn test_object_field() { let formula = crate::BoolFormulas::object_field( crate::ObjectFormulas::root(), "bool_true".to_string(), ); let context = crate::FormulaContext::new(TestObject::new(1)); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, true); let serialized = formula.serialize(); let deserialized = crate::BoolFormulas::from_bytes(&serialized).unwrap(); let result = deserialized.evaluate(&context).unwrap(); assert_eq!(result, true); } #[test] fn test_object_call() { let formula = crate::BoolFormulas::object_method_call( crate::ObjectFormulas::root(), "really".to_string(), vec![], ); let context = crate::FormulaContext::new(TestObject::new(1)); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, true); let serialized = formula.serialize(); let deserialized = crate::BoolFormulas::from_bytes(&serialized).unwrap(); let result = deserialized.evaluate(&context).unwrap(); assert_eq!(result, true); } #[test] fn test_false() { let formula = crate::BoolFormulas::constant(false); let context = crate::FormulaContext::new_with_empty_root(); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, false); let serialized = formula.serialize(); let deserialized = crate::BoolFormulas::from_bytes(&serialized).unwrap(); let result = deserialized.evaluate(&context).unwrap(); assert_eq!(result, false); } #[test] fn test_true() { let formula = crate::BoolFormulas::constant(true); let context = crate::FormulaContext::new_with_empty_root(); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, true); let serialized = formula.serialize(); let deserialized = crate::BoolFormulas::from_bytes(&serialized).unwrap(); let result = deserialized.evaluate(&context).unwrap(); assert_eq!(result, true); } #[test] fn test_not() { let formula = crate::BoolFormulas::not(crate::BoolFormulas::constant(true)); let context = crate::FormulaContext::new_with_empty_root(); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, false); let serialized = formula.serialize(); let deserialized = crate::BoolFormulas::from_bytes(&serialized).unwrap(); let result = deserialized.evaluate(&context).unwrap(); assert_eq!(result, false); } #[test] fn test_and() { let formula = crate::BoolFormulas::and( crate::BoolFormulas::constant(true), crate::BoolFormulas::constant(false), ); let context = crate::FormulaContext::new_with_empty_root(); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, false); let formula = crate::BoolFormulas::and( crate::BoolFormulas::constant(true), crate::BoolFormulas::constant(true), ); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, true); let formula = crate::BoolFormulas::and( crate::BoolFormulas::constant(false), crate::BoolFormulas::constant(false), ); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, false); let serialized = formula.serialize(); let deserialized = crate::BoolFormulas::from_bytes(&serialized).unwrap(); let result = deserialized.evaluate(&context).unwrap(); assert_eq!(result, false); } #[test] fn test_or() { let formula = crate::BoolFormulas::or( crate::BoolFormulas::constant(true), crate::BoolFormulas::constant(false), ); let context = crate::FormulaContext::new_with_empty_root(); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, true); let formula = crate::BoolFormulas::or( crate::BoolFormulas::constant(true), crate::BoolFormulas::constant(true), ); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, true); let formula = crate::BoolFormulas::or( crate::BoolFormulas::constant(false), crate::BoolFormulas::constant(false), ); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, false); let serialized = formula.serialize(); let deserialized = crate::BoolFormulas::from_bytes(&serialized).unwrap(); let result = deserialized.evaluate(&context).unwrap(); assert_eq!(result, false); } #[test] fn test_xor() { let formula = crate::BoolFormulas::xor( crate::BoolFormulas::constant(true), crate::BoolFormulas::constant(false), ); let context = crate::FormulaContext::new_with_empty_root(); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, true); let formula = crate::BoolFormulas::xor( crate::BoolFormulas::constant(true), crate::BoolFormulas::constant(true), ); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, false); let formula = crate::BoolFormulas::xor( crate::BoolFormulas::constant(false), crate::BoolFormulas::constant(false), ); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, false); let formula = crate::BoolFormulas::xor( crate::BoolFormulas::constant(false), crate::BoolFormulas::constant(true), ); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, true); let serialized = formula.serialize(); let deserialized = crate::BoolFormulas::from_bytes(&serialized).unwrap(); let result = deserialized.evaluate(&context).unwrap(); assert_eq!(result, true); } #[test] fn test_compare_int() { let formula = crate::BoolFormulas::compare_int( crate::IntFormulas::value(1), crate::IntFormulas::value(2), Comparator::Equal, ); let context = crate::FormulaContext::new_with_empty_root(); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, false); let formula = crate::BoolFormulas::compare_int( crate::IntFormulas::value(1), crate::IntFormulas::value(2), Comparator::NotEqual, ); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, true); let formula = crate::BoolFormulas::compare_int( crate::IntFormulas::value(1), crate::IntFormulas::value(2), Comparator::LessThan, ); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, true); let formula = crate::BoolFormulas::compare_int( crate::IntFormulas::value(1), crate::IntFormulas::value(2), Comparator::LessThanOrEqual, ); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, true); let formula = crate::BoolFormulas::compare_int( crate::IntFormulas::value(1), crate::IntFormulas::value(2), Comparator::GreaterThan, ); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, false); let formula = crate::BoolFormulas::compare_int( crate::IntFormulas::value(1), crate::IntFormulas::value(2), Comparator::GreaterThanOrEqual, ); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, false); let formula = crate::BoolFormulas::compare_int( crate::IntFormulas::value(2), crate::IntFormulas::value(2), Comparator::Equal, ); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, true); let serialized = formula.serialize(); let deserialized = crate::BoolFormulas::from_bytes(&serialized).unwrap(); let result = deserialized.evaluate(&context).unwrap(); assert_eq!(result, true); } #[test] fn test_compare_decimal() { let formula = crate::BoolFormulas::compare_decimal( crate::DecimalFormulas::value("1.0".parse().unwrap()), crate::DecimalFormulas::value("2.0".parse().unwrap()), Comparator::Equal, ); let context = crate::FormulaContext::new_with_empty_root(); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, false); let formula = crate::BoolFormulas::compare_decimal( crate::DecimalFormulas::value("1.0".parse().unwrap()), crate::DecimalFormulas::value("2.0".parse().unwrap()), Comparator::NotEqual, ); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, true); let formula = crate::BoolFormulas::compare_decimal( crate::DecimalFormulas::value("1.0".parse().unwrap()), crate::DecimalFormulas::value("2.0".parse().unwrap()), Comparator::LessThan, ); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, true); let formula = crate::BoolFormulas::compare_decimal( crate::DecimalFormulas::value("1.0".parse().unwrap()), crate::DecimalFormulas::value("2.0".parse().unwrap()), Comparator::LessThanOrEqual, ); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, true); let formula = crate::BoolFormulas::compare_decimal( crate::DecimalFormulas::value("1.0".parse().unwrap()), crate::DecimalFormulas::value("2.0".parse().unwrap()), Comparator::GreaterThan, ); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, false); let formula = crate::BoolFormulas::compare_decimal( crate::DecimalFormulas::value("1.0".parse().unwrap()), crate::DecimalFormulas::value("2.0".parse().unwrap()), Comparator::GreaterThanOrEqual, ); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, false); let formula = crate::BoolFormulas::compare_decimal( crate::DecimalFormulas::value("1.0".parse().unwrap()), crate::DecimalFormulas::value("2.0".parse().unwrap()), Comparator::Equal, ); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, true); let serialized = formula.serialize(); let deserialized = crate::BoolFormulas::from_bytes(&serialized).unwrap(); let result = deserialized.evaluate(&context).unwrap(); assert_eq!(result, true); } #[test] fn test_compare_date() { let formula = crate::BoolFormulas::compare_date( crate::DateFormulas::value("2020-01-01".parse().unwrap()), crate::DateFormulas::value("2020-01-02".parse().unwrap()), Comparator::Equal, ); let context = crate::FormulaContext::new_with_empty_root(); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, false); let formula = crate::BoolFormulas::compare_date( crate::DateFormulas::value("2020-01-01".parse().unwrap()), crate::DateFormulas::value("2020-01-02".parse().unwrap()), Comparator::NotEqual, ); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, true); let formula = crate::BoolFormulas::compare_date( crate::DateFormulas::value("2020-01-01".parse().unwrap()), crate::DateFormulas::value("2020-01-02".parse().unwrap()), Comparator::LessThan, ); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, true); let formula = crate::BoolFormulas::compare_date( crate::DateFormulas::value("2020-01-01".parse().unwrap()), crate::DateFormulas::value("2020-01-02".parse().unwrap()), Comparator::LessThanOrEqual, ); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, true); let formula = crate::BoolFormulas::compare_date( crate::DateFormulas::value("2020-01-01".parse().unwrap()), crate::DateFormulas::value("2020-01-02".parse().unwrap()), Comparator::GreaterThan, ); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, false); let formula = crate::BoolFormulas::compare_date( crate::DateFormulas::value("2020-01-01".parse().unwrap()), crate::DateFormulas::value("2020-01-02".parse().unwrap()), Comparator::GreaterThanOrEqual, ); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, false); let serialized = formula.serialize(); let deserialized = crate::BoolFormulas::from_bytes(&serialized).unwrap(); let result = deserialized.evaluate(&context).unwrap(); assert_eq!(result, false); } #[test] fn test_compare_datetime() { let formula = crate::BoolFormulas::compare_datetime( crate::DateTimeFormulas::value("2020-01-01T00:00:00Z".parse().unwrap()), crate::DateTimeFormulas::value("2020-01-01T00:00:01Z".parse().unwrap()), Comparator::Equal, ); let context = crate::FormulaContext::new_with_empty_root(); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, false); let formula = crate::BoolFormulas::compare_datetime( crate::DateTimeFormulas::value("2020-01-01T00:00:00Z".parse().unwrap()), crate::DateTimeFormulas::value("2020-01-01T00:00:01Z".parse().unwrap()), Comparator::NotEqual, ); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, true); let formula = crate::BoolFormulas::compare_datetime( crate::DateTimeFormulas::value("2020-01-01T00:00:00Z".parse().unwrap()), crate::DateTimeFormulas::value("2020-01-01T00:00:01Z".parse().unwrap()), Comparator::LessThan, ); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, true); let formula = crate::BoolFormulas::compare_datetime( crate::DateTimeFormulas::value("2020-01-01T00:00:00Z".parse().unwrap()), crate::DateTimeFormulas::value("2020-01-01T00:00:01Z".parse().unwrap()), Comparator::LessThanOrEqual, ); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, true); let formula = crate::BoolFormulas::compare_datetime( crate::DateTimeFormulas::value("2020-01-01T00:00:00Z".parse().unwrap()), crate::DateTimeFormulas::value("2020-01-01T00:00:01Z".parse().unwrap()), Comparator::GreaterThan, ); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, false); let formula = crate::BoolFormulas::compare_datetime( crate::DateTimeFormulas::value("2020-01-01T00:00:00Z".parse().unwrap()), crate::DateTimeFormulas::value("2020-01-01T00:00:01Z".parse().unwrap()), Comparator::GreaterThanOrEqual, ); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, false); let serialized = formula.serialize(); let deserialized = crate::BoolFormulas::from_bytes(&serialized).unwrap(); let result = deserialized.evaluate(&context).unwrap(); assert_eq!(result, false); } #[test] fn test_match_string_regex() { let formula = crate::BoolFormulas::match_string_regex( crate::StringFormulas::value("abc".to_string()), regex::Regex::new("abc").unwrap(), ); let context = crate::FormulaContext::new_with_empty_root(); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, true); let formula = crate::BoolFormulas::match_string_regex( crate::StringFormulas::value("abc".to_string()), regex::Regex::new("def").unwrap(), ); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, false); let formula = crate::BoolFormulas::match_string_regex( crate::StringFormulas::value("abc".to_string()), regex::Regex::new("a.c").unwrap(), ); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, true); let formula = crate::BoolFormulas::match_string_regex( crate::StringFormulas::value("abc".to_string()), regex::Regex::new("a.d").unwrap(), ); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, false); let formula = crate::BoolFormulas::match_string_regex( crate::StringFormulas::value("abc".to_string()), regex::Regex::new("a.*c").unwrap(), ); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, true); let formula = crate::BoolFormulas::match_string_regex( crate::StringFormulas::value("abc".to_string()), regex::Regex::new("a.*d").unwrap(), ); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, false); let formula = crate::BoolFormulas::match_string_regex( crate::StringFormulas::value("abc".to_string()), regex::Regex::new("a.*").unwrap(), ); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, true); let serialized = formula.serialize(); let deserialized = crate::BoolFormulas::from_bytes(&serialized).unwrap(); let result = deserialized.evaluate(&context).unwrap(); assert_eq!(result, true); } #[test] fn test_bool_array_empty() { let formula = crate::BoolFormulas::array_empty_bool(crate::BoolArrayFormulas::object_field( ObjectFormulas::root(), "bool_array".to_string(), )); let context = crate::FormulaContext::new(TestObject::new(1)); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, false); let formula = crate::BoolFormulas::array_empty_bool(crate::BoolArrayFormulas::object_field( ObjectFormulas::root(), "empty_bool_array".to_string(), )); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, true); let serialized = formula.serialize(); let deserialized = crate::BoolFormulas::from_bytes(&serialized).unwrap(); let result = deserialized.evaluate(&context).unwrap(); assert_eq!(result, true); } #[test] fn test_int_array_empty() { let formula = crate::BoolFormulas::array_empty_int(crate::IntArrayFormulas::object_field( ObjectFormulas::root(), "int_array".to_string(), )); let context = crate::FormulaContext::new(TestObject::new(1)); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, false); let formula = crate::BoolFormulas::array_empty_int(crate::IntArrayFormulas::object_field( ObjectFormulas::root(), "empty_int_array".to_string(), )); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, true); let serialized = formula.serialize(); let deserialized = crate::BoolFormulas::from_bytes(&serialized).unwrap(); let result = deserialized.evaluate(&context).unwrap(); assert_eq!(result, false); } #[test] fn test_decimal_array_empty() { let formula = crate::BoolFormulas::array_empty_decimal(crate::DecimalArrayFormulas::object_field( ObjectFormulas::root(), "decimal_array".to_string(), )); let context = crate::FormulaContext::new(TestObject::new(1)); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, false); let formula = crate::BoolFormulas::array_empty_decimal(crate::DecimalArrayFormulas::object_field( ObjectFormulas::root(), "empty_decimal_array".to_string(), )); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, true); let serialized = formula.serialize(); let deserialized = crate::BoolFormulas::from_bytes(&serialized).unwrap(); let result = deserialized.evaluate(&context).unwrap(); assert_eq!(result, true); } #[test] fn test_string_array_empty() { let formula = crate::BoolFormulas::array_empty_string(crate::StringArrayFormulas::object_field( ObjectFormulas::root(), "string_array".to_string(), )); let context = crate::FormulaContext::new(TestObject::new(1)); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, false); let formula = crate::BoolFormulas::array_empty_string(crate::StringArrayFormulas::object_field( ObjectFormulas::root(), "empty_string_array".to_string(), )); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, true); let serialized = formula.serialize(); let deserialized = crate::BoolFormulas::from_bytes(&serialized).unwrap(); let result = deserialized.evaluate(&context).unwrap(); assert_eq!(result, true); } #[test] fn test_date_array_empty() { let formula = crate::BoolFormulas::array_empty_date(crate::DateArrayFormulas::object_field( ObjectFormulas::root(), "date_array".to_string(), )); let context = crate::FormulaContext::new(TestObject::new(1)); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, false); let formula = crate::BoolFormulas::array_empty_date(crate::DateArrayFormulas::object_field( ObjectFormulas::root(), "empty_date_array".to_string(), )); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, true); let serialized = formula.serialize(); let deserialized = crate::BoolFormulas::from_bytes(&serialized).unwrap(); let result = deserialized.evaluate(&context).unwrap(); assert_eq!(result, true); } #[test] fn test_datetime_array_empty() { let formula = crate::BoolFormulas::array_empty_datetime(crate::DateTimeArrayFormulas::object_field( ObjectFormulas::root(), "datetime_array".to_string(), )); let context = crate::FormulaContext::new(TestObject::new(1)); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, false); let formula = crate::BoolFormulas::array_empty_datetime(crate::DateTimeArrayFormulas::object_field( ObjectFormulas::root(), "empty_datetime_array".to_string(), )); let result = formula.evaluate(&context).unwrap(); assert_eq!(result, true); let serialized = formula.serialize(); let deserialized = crate::BoolFormulas::from_bytes(&serialized).unwrap(); let result = deserialized.evaluate(&context).unwrap(); assert_eq!(result, true); } }