use super::printer::Printer;
use std::rc::Rc;
use std::sync::atomic::{AtomicUsize, Ordering};
pub trait StringRef {
fn get_length(&self) -> usize;
fn get_text(self) -> String;
fn get_text_clone(&self) -> String;
}
impl StringRef for String {
fn get_length(&self) -> usize {
self.chars().count()
}
fn get_text(self) -> String {
self
}
fn get_text_clone(&self) -> String {
self.clone()
}
}
pub trait InfoRef {
fn get_unique_id(&self) -> usize;
fn get_name(&self) -> &'static str;
}
pub trait ConditionRef<TString, TInfo, TCondition> where TString : StringRef, TInfo : InfoRef, TCondition : ConditionRef<TString, TInfo, TCondition> {
fn get_unique_id(&self) -> usize;
fn get_name(&self) -> &'static str;
fn resolve(&self, context: &mut ConditionResolverContext<TString, TInfo, TCondition>) -> Option<bool>;
fn get_true_path(&self) -> Option<Rc<Vec<PrintItem<TString, TInfo, TCondition>>>>;
fn get_false_path(&self) -> Option<Rc<Vec<PrintItem<TString, TInfo, TCondition>>>>;
}
pub enum PrintItem<TString = String, TInfo = Info, TCondition = Condition<TString, TInfo>> where TString : StringRef, TInfo : InfoRef, TCondition : ConditionRef<TString, TInfo, TCondition> {
String(Rc<TString>),
Condition(Rc<TCondition>),
Info(Rc<TInfo>),
NewLine,
Tab,
PossibleNewLine,
SpaceOrNewLine,
ExpectNewLine,
StartIndent,
FinishIndent,
StartNewLineGroup,
FinishNewLineGroup,
SingleIndent,
StartIgnoringIndent,
FinishIgnoringIndent,
}
impl<TString, TInfo, TCondition> Clone for PrintItem<TString, TInfo, TCondition> where TString : StringRef, TInfo : InfoRef, TCondition : ConditionRef<TString, TInfo, TCondition> {
fn clone(&self) -> PrintItem<TString, TInfo, TCondition> {
match self {
PrintItem::String(text) => PrintItem::String(text.clone()),
PrintItem::Condition(condition) => PrintItem::Condition(condition.clone()),
PrintItem::Info(info) => PrintItem::Info(info.clone()),
PrintItem::NewLine => PrintItem::NewLine,
PrintItem::Tab => PrintItem::Tab,
PrintItem::PossibleNewLine => PrintItem::PossibleNewLine,
PrintItem::SpaceOrNewLine => PrintItem::SpaceOrNewLine,
PrintItem::ExpectNewLine => PrintItem::ExpectNewLine,
PrintItem::StartIndent => PrintItem:: StartIndent,
PrintItem::FinishIndent => PrintItem::FinishIndent,
PrintItem::StartNewLineGroup => PrintItem::StartNewLineGroup,
PrintItem::FinishNewLineGroup => PrintItem::FinishNewLineGroup,
PrintItem::SingleIndent => PrintItem::SingleIndent,
PrintItem::StartIgnoringIndent => PrintItem::StartIgnoringIndent,
PrintItem::FinishIgnoringIndent => PrintItem::FinishIgnoringIndent,
}
}
}
impl<TInfo, TCondition> Into<PrintItem<String, TInfo, TCondition>> for &str where TInfo : InfoRef, TCondition : ConditionRef<String, TInfo, TCondition> {
fn into(self) -> PrintItem<String, TInfo, TCondition> {
PrintItem::String(Rc::new(String::from(self)))
}
}
impl<TInfo, TCondition> Into<PrintItem<String, TInfo, TCondition>> for String where TInfo : InfoRef, TCondition : ConditionRef<String, TInfo, TCondition> {
fn into(self) -> PrintItem<String, TInfo, TCondition> {
PrintItem::String(Rc::new(self))
}
}
impl<TInfo, TCondition> Into<PrintItem<String, TInfo, TCondition>> for &String where TInfo : InfoRef, TCondition : ConditionRef<String, TInfo, TCondition> {
fn into(self) -> PrintItem<String, TInfo, TCondition> {
PrintItem::String(Rc::new(self.clone()))
}
}
#[derive(Clone)]
pub struct Info {
id: usize,
pub name: &'static str,
}
impl InfoRef for Info {
fn get_unique_id(&self) -> usize {
self.id
}
fn get_name(&self) -> &'static str {
self.name
}
}
impl<TString, TCondition> Into<PrintItem<TString, Info, TCondition>> for Info where TString : StringRef, TCondition : ConditionRef<TString, Info, TCondition> {
fn into(self) -> PrintItem<TString, Info, TCondition> {
PrintItem::Info(Rc::new(self))
}
}
static INFO_COUNTER: AtomicUsize = AtomicUsize::new(0);
impl Info {
pub fn new(name: &'static str) -> Info {
Info {
id: INFO_COUNTER.fetch_add(1, Ordering::SeqCst),
name
}
}
pub fn into_clone<TString, TCondition>(&self) -> PrintItem<TString, Info, TCondition> where TString : StringRef, TCondition : ConditionRef<TString, Info, TCondition> {
PrintItem::Info(Rc::new(self.clone()))
}
}
pub struct Condition<TString = String, TInfo = Info> where TString : StringRef, TInfo : InfoRef {
id: usize,
name: &'static str,
pub condition: Rc<Box<ConditionResolver<TString, TInfo, Condition<TString, TInfo>>>>,
pub true_path: Option<Rc<Vec<PrintItem<TString, TInfo, Condition<TString, TInfo>>>>>,
pub false_path: Option<Rc<Vec<PrintItem<TString, TInfo, Condition<TString, TInfo>>>>>,
}
impl<TString, TInfo> Clone for Condition<TString, TInfo> where TString : StringRef, TInfo : InfoRef {
fn clone(&self) -> Condition<TString, TInfo> {
Condition {
id: self.id,
name: self.name,
condition: self.condition.clone(),
true_path: self.true_path.as_ref().map(|x| x.clone()),
false_path: self.false_path.as_ref().map(|x| x.clone()),
}
}
}
static CONDITION_COUNTER: AtomicUsize = AtomicUsize::new(0);
impl<TString, TInfo> Condition<TString, TInfo> where TString : StringRef, TInfo : InfoRef {
pub fn new(name: &'static str, properties: ConditionProperties<TString, TInfo>) -> Condition<TString, TInfo> {
Condition {
id: CONDITION_COUNTER.fetch_add(1, Ordering::SeqCst),
name,
condition: Rc::new(properties.condition),
true_path: properties.true_path.map(|x| Rc::new(x)),
false_path: properties.false_path.map(|x| Rc::new(x)),
}
}
pub fn into_clone(&self) -> PrintItem<TString, TInfo, Condition<TString, TInfo>> {
PrintItem::Condition(Rc::new(self.clone()))
}
}
impl<TString, TInfo> ConditionRef<TString, TInfo, Condition<TString, TInfo>> for Condition<TString, TInfo> where TString : StringRef, TInfo : InfoRef {
fn get_unique_id(&self) -> usize {
self.id
}
fn get_name(&self) -> &'static str {
self.name
}
fn resolve(&self, context: &mut ConditionResolverContext<TString, TInfo, Self>) -> Option<bool> {
(self.condition)(context)
}
fn get_true_path(&self) -> Option<Rc<Vec<PrintItem<TString, TInfo, Self>>>> {
self.true_path.clone()
}
fn get_false_path(&self) -> Option<Rc<Vec<PrintItem<TString, TInfo, Self>>>> {
self.false_path.clone()
}
}
impl<TString, TInfo> Into<PrintItem<TString, TInfo, Condition<TString, TInfo>>> for Condition<TString, TInfo> where TString : StringRef, TInfo : InfoRef {
fn into(self) -> PrintItem<TString, TInfo, Condition<TString, TInfo>> {
PrintItem::Condition(Rc::new(self))
}
}
pub struct ConditionProperties<TString = String, TInfo = Info> where TString : StringRef, TInfo : InfoRef {
pub condition: Box<ConditionResolver<TString, TInfo, Condition<TString, TInfo>>>,
pub true_path: Option<Vec<PrintItem<TString, TInfo, Condition<TString, TInfo>>>>,
pub false_path: Option<Vec<PrintItem<TString, TInfo, Condition<TString, TInfo>>>>,
}
pub type ConditionResolver<TString, TInfo, TCondition> = dyn Fn(&mut ConditionResolverContext<TString, TInfo, TCondition>) -> Option<bool>;
pub struct ConditionResolverContext<'a, TString = String, TInfo = Info, TCondition = Condition> where TString : StringRef, TInfo : InfoRef, TCondition : ConditionRef<TString, TInfo, TCondition> {
printer: &'a mut Printer<TString, TInfo, TCondition>,
pub writer_info: WriterInfo,
}
impl<'a, TString, TInfo, TCondition> ConditionResolverContext<'a, TString, TInfo, TCondition> where TString : StringRef, TInfo : InfoRef, TCondition : ConditionRef<TString, TInfo, TCondition> {
pub fn new(printer: &'a mut Printer<TString, TInfo, TCondition>) -> Self {
let writer_info = printer.get_writer_info();
ConditionResolverContext {
printer,
writer_info,
}
}
pub fn get_resolved_condition(&mut self, condition: &TCondition) -> Option<bool> {
self.printer.get_resolved_condition(condition)
}
pub fn get_resolved_info(&mut self, info: &TInfo) -> Option<WriterInfo> {
self.printer.get_resolved_info(info)
}
}
#[derive(Clone)]
pub struct WriterInfo {
pub line_number: u32,
pub column_number: u32,
pub indent_level: u16,
pub line_start_indent_level: u16,
pub line_start_column_number: u32,
}