use crate::rules::eval_context::EventRecord;
use crate::rules::exprs::SliceDisplay;
use crate::rules::path_value::PathAwareValue;
use crate::rules::values::{CmpOperator, RangeType, LOWER_INCLUSIVE, UPPER_INCLUSIVE};
use crate::rules::{BlockCheck, ClauseCheck, QueryResult, RecordType, Status};
use std::fmt::{Display, Formatter};
use std::rc::Rc;
pub(crate) fn display_comparison((cmp, not): (CmpOperator, bool)) -> String {
format!("{} {}", if not { "not" } else { "" }, cmp)
}
fn write_range<T: Display + PartialOrd>(
formatter: &mut Formatter<'_>,
range: &RangeType<T>,
) -> std::fmt::Result {
if range.inclusive & LOWER_INCLUSIVE != 0 {
formatter.write_str("[")?;
} else {
formatter.write_str("(")?;
}
range.lower.fmt(formatter)?;
formatter.write_str(",")?;
range.upper.fmt(formatter)?;
if range.inclusive & UPPER_INCLUSIVE != 0 {
formatter.write_str("]")?;
} else {
formatter.write_str(")")?;
}
Ok(())
}
pub(crate) struct ValueOnlyDisplay(pub(crate) Rc<PathAwareValue>);
impl std::fmt::Debug for ValueOnlyDisplay {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let as_display = self as &dyn Display;
as_display.fmt(f)
}
}
impl Display for ValueOnlyDisplay {
fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
match &*self.0 {
PathAwareValue::Null(_path) => formatter.write_str("\"NULL\"")?,
PathAwareValue::String((_path, value)) => {
formatter.write_fmt(format_args!("\"{}\"", value))?
}
PathAwareValue::Regex((_path, value)) => {
formatter.write_fmt(format_args!("\"/{}/\"", value))?
}
PathAwareValue::Bool((_path, value)) => {
formatter.write_fmt(format_args!("{}", value))?
}
PathAwareValue::Int((_path, value)) => {
formatter.write_fmt(format_args!("{}", value))?
}
PathAwareValue::Float((_path, value)) => {
formatter.write_fmt(format_args!("{}", value))?
}
PathAwareValue::Char((_path, value)) => {
formatter.write_fmt(format_args!("\'{}\'", value))?
}
PathAwareValue::List((_path, list)) => {
formatter.write_str("[")?;
if !list.is_empty() {
let last = list.len() - 1;
for (idx, each) in list.iter().enumerate() {
ValueOnlyDisplay(Rc::new(each.clone())).fmt(formatter)?;
if last != idx {
formatter.write_str(",")?;
}
}
}
formatter.write_str("]")?;
}
PathAwareValue::Map((_path, map)) => {
formatter.write_str("{")?;
if !map.is_empty() {
let last = map.values.len() - 1;
for (idx, (key, value)) in map.values.iter().enumerate() {
formatter.write_fmt(format_args!("\"{}\"", key))?;
formatter.write_str(":")?;
ValueOnlyDisplay(Rc::new(value.clone())).fmt(formatter)?;
if last != idx {
formatter.write_str(",")?;
}
}
}
formatter.write_str("}")?;
}
PathAwareValue::RangeInt((_path, value)) => write_range(formatter, value)?,
PathAwareValue::RangeFloat((_path, value)) => write_range(formatter, value)?,
PathAwareValue::RangeChar((_path, value)) => write_range(formatter, value)?,
}
Ok(())
}
}
impl std::fmt::Display for PathAwareValue {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!("Path={} Value=", self.self_path()))?;
ValueOnlyDisplay(Rc::new(self.clone())).fmt(f)
}
}
impl std::fmt::Display for QueryResult {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
QueryResult::Literal(l) => {
f.write_fmt(format_args!("literal, {}", l))?;
}
QueryResult::Resolved(r) => {
f.write_fmt(format_args!("(resolved, {})", r))?;
}
QueryResult::UnResolved(ur) => {
f.write_fmt(format_args!("(unresolved, {})", ur.traversed_to))?;
}
}
Ok(())
}
}
impl<'value> std::fmt::Display for ClauseCheck<'value> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
ClauseCheck::Success => {
f.write_fmt(format_args!(
"GuardClauseValueCheck(Status={})",
Status::PASS
))?;
}
ClauseCheck::NoValueForEmptyCheck(message) => {
f.write_fmt(format_args!(
"GuardClause(Status={}, Empty, {})",
Status::FAIL,
message.as_ref().map_or("", |s| s.as_ref())
))?;
}
ClauseCheck::MissingBlockValue(missing) => {
f.write_fmt(format_args!(
"GuardBlockValueMissing(Status={}, Reason={}, {})",
missing.status,
missing.message.as_ref().map_or("", String::as_str),
missing
.from
.unresolved_traversed_to()
.map_or(String::from(""), |p| (*p).self_path().0.to_string())
))?;
}
ClauseCheck::DependentRule(dependent) => {
f.write_fmt(format_args!(
"GuardClauseDependentRule(Rule={}, Status={})",
dependent.rule, dependent.status,
))?;
}
ClauseCheck::Unary(unary) => {
f.write_fmt(format_args!(
"GuardClauseUnaryCheck(Status={}, Comparison={}, Value-At={})",
unary.value.status,
display_comparison(unary.comparison),
unary.value.from
))?;
}
ClauseCheck::Comparison(check) => {
f.write_fmt(format_args!(
"GuardClauseBinaryCheck(Status={}, Comparison={}, from={}, to={})",
check.status,
display_comparison(check.comparison),
check.from,
match &check.to {
Some(exists) => format!("{}", exists),
None => "".to_string(),
}
))?;
}
ClauseCheck::InComparison(check) => {
f.write_fmt(format_args!(
"GuardClauseInBinaryCheck(Status={}, Comparison={}, from={}, to={})",
check.status,
display_comparison(check.comparison),
check.from,
SliceDisplay(&check.to),
))?;
}
}
Ok(())
}
}
impl<'value> std::fmt::Display for RecordType<'value> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
RecordType::FileCheck(status) => {
f.write_fmt(format_args!(
"File({}, Status={})",
status.name, status.status
))?;
}
RecordType::RuleCheck(status) => {
f.write_fmt(format_args!(
"Rule({}, Status={})",
status.name, status.status
))?;
}
RecordType::RuleCondition(status) => {
f.write_fmt(format_args!("Rule/When(Status={})", status))?;
}
RecordType::TypeCheck(block_check) => {
f.write_fmt(format_args!(
"Type({}, Status={})",
block_check.type_name, block_check.block.status
))?;
}
RecordType::TypeCondition(status) => {
f.write_fmt(format_args!("TypeBlock/When Status={})", status))?;
}
RecordType::TypeBlock(status) => {
f.write_fmt(format_args!("TypeBlock/Block Status={})", status))?;
}
RecordType::Filter(status) => {
f.write_fmt(format_args!("Filter/ConjunctionsBlock(Status={})", status))?;
}
RecordType::WhenCheck(BlockCheck { status, .. }) => {
f.write_fmt(format_args!("WhenConditionalBlock(Status = {})", status))?;
}
RecordType::WhenCondition(status) => {
f.write_fmt(format_args!("WhenCondition(Status = {})", status))?;
}
RecordType::Disjunction(BlockCheck { status, .. }) => {
f.write_fmt(format_args!("Disjunction(Status = {})", status))?;
}
RecordType::BlockGuardCheck(BlockCheck { status, .. }) => {
f.write_fmt(format_args!("GuardValueBlockCheck(Status = {})", status))?;
}
RecordType::GuardClauseBlockCheck(BlockCheck { status, .. }) => {
f.write_fmt(format_args!("GuardClauseBlock(Status = {})", status))?;
}
RecordType::ClauseValueCheck(check) => {
check.fmt(f)?;
}
}
Ok(())
}
}
impl<'value> std::fmt::Display for EventRecord<'value> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!(
"{}[Context={}]",
self.container.as_ref().unwrap(),
self.context
))?;
Ok(())
}
}