use std::fmt::Debug;
use std::fmt::Display;
use anyhow::Result;
use serde::Serialize;
use serde::ser::SerializeMap;
use crate::escaping::Escaper;
pub trait Rule: RuleClone + Debug + Send {
fn kind(&self) -> &'static str;
fn matches(&self, line: &[u8]) -> bool;
fn unmake(&self) -> (String, Vec<u8>);
fn to_expression_string(&self, optional: bool, multiline: bool, escaper: &Escaper) -> String {
let (quantifier, equal_quantifier) = if optional {
if multiline {
("*", " (*)")
} else {
("?", " (?)")
}
} else if multiline {
("+", " (+)")
} else {
("", "")
};
let (kind, expression) = self.unmake();
let rendered = escaper.escaped_printable(&expression);
if kind == "equal" {
if escaper.has_unprintable(&expression) {
format!("{rendered} (escaped{quantifier})")
} else {
format!("{rendered}{equal_quantifier}")
}
} else {
format!("{rendered} ({kind}{quantifier})")
}
}
}
impl Display for Box<dyn Rule> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let (kind, expression) = self.unmake();
let expression = Escaper::Unicode.escaped_printable(&expression);
write!(f, "{kind}::{expression}")
}
}
impl PartialEq<Box<dyn Rule>> for Box<dyn Rule> {
fn eq(&self, other: &Box<dyn Rule>) -> bool {
format!("{self}") == format!("{other}")
}
}
impl Clone for Box<dyn Rule> {
fn clone(&self) -> Self {
self.clone_box()
}
}
impl Serialize for Box<dyn Rule> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let (kind, expression) = self.unmake();
let expression = Escaper::Unicode.escaped_printable(&expression);
let mut map = serializer.serialize_map(Some(2))?;
map.serialize_entry("kind", &kind)?;
map.serialize_entry("expression", &expression)?;
map.end()
}
}
pub trait RuleClone {
fn clone_box(&self) -> Box<dyn Rule>;
}
impl<T: 'static + Rule + Clone> RuleClone for T {
fn clone_box(&self) -> Box<dyn Rule> {
Box::new(self.clone())
}
}
pub trait RuleMaker {
fn make(expression: &str) -> Result<Box<dyn Rule>>;
}
pub type MakeRule = fn(&str) -> Result<Box<dyn Rule>>;