use super::printer::Printer;
use std::rc::Rc;
use std::cell::UnsafeCell;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::mem;
pub struct PrintItems {
pub(super) first_node: Option<PrintItemPath>,
last_node: Option<PrintItemPath>,
}
impl PrintItems {
pub fn new() -> PrintItems {
PrintItems {
first_node: None,
last_node: None,
}
}
pub fn into_rc_path(self) -> Option<PrintItemPath> {
self.first_node
}
pub fn push_item(&mut self, item: PrintItem) {
self.push_item_internal(item);
}
#[inline]
fn push_item_internal(&mut self, item: PrintItem) {
let node = Rc::new(PrintNodeCell::new(item));
if let Some(first_node) = &self.first_node {
let new_last_node = node.get_last_next().unwrap_or(node.clone());
self.last_node.as_ref().unwrap_or(first_node).set_next(Some(node));
self.last_node = Some(new_last_node);
} else {
self.last_node = node.get_last_next();
self.first_node = Some(node);
}
}
}
impl PrintItems {
pub fn extend(&mut self, items: PrintItems) {
if let Some(first_node) = &self.first_node {
self.last_node.as_ref().unwrap_or(first_node).set_next(items.first_node.clone());
self.last_node = items.last_node.or(items.first_node.or(self.last_node.clone()));
} else {
self.first_node = items.first_node;
self.last_node = items.last_node;
}
}
pub fn push_str(&mut self, item: &str) {
self.push_item_internal(PrintItem::String(Rc::from(StringContainer::new(String::from(item)))));
}
pub fn push_condition(&mut self, condition: Condition) {
self.push_item_internal(PrintItem::Condition(Rc::from(condition)));
}
pub fn push_info(&mut self, info: Info) {
self.push_item_internal(PrintItem::Info(Rc::from(info)));
}
pub fn push_signal(&mut self, signal: Signal) {
self.push_item_internal(PrintItem::Signal(signal));
}
pub fn push_path(&mut self, path: PrintItemPath) {
self.push_item_internal(PrintItem::RcPath(path))
}
pub fn push_optional_path(&mut self, path: Option<PrintItemPath>) {
if let Some(path) = path {
self.push_path(path);
}
}
pub fn is_empty(&self) -> bool {
self.first_node.is_none()
}
#[cfg(debug_assertions)]
pub fn get_as_text(&self) -> String {
return if let Some(first_node) = &self.first_node {
get_items_as_text(first_node.clone(), String::from(""))
} else {
String::new()
};
fn get_items_as_text(items: PrintItemPath, indent_text: String) -> String {
let mut text = String::new();
for item in PrintItemsIterator::new(items) {
match item {
PrintItem::Signal(signal) => text.push_str(&get_line(format!("Signal::{:?}", signal), &indent_text)),
PrintItem::Info(info) => text.push_str(&get_line(format!("Info: {}", info.name), &indent_text)),
PrintItem::Condition(condition) => {
text.push_str(&get_line(format!("Condition: {}", condition.name), &indent_text));
if let Some(true_path) = &condition.true_path {
text.push_str(&get_line(String::from(" true:"), &indent_text));
text.push_str(&get_items_as_text(true_path.clone(), format!("{} ", &indent_text)));
}
if let Some(false_path) = &condition.false_path {
text.push_str(&get_line(String::from(" false:"), &indent_text));
text.push_str(&get_items_as_text(false_path.clone(), format!("{} ", &indent_text)));
}
},
PrintItem::String(str_text) => text.push_str(&get_line(format!("`{}`", str_text.text.to_string()), &indent_text)),
PrintItem::RcPath(path) => text.push_str(&get_items_as_text(path.clone(), indent_text.clone())),
}
}
return text;
fn get_line(text: String, indent_text: &String) -> String {
format!("{}{}\n", indent_text, text)
}
}
}
pub fn iter(&self) -> PrintItemsIterator {
PrintItemsIterator {
node: self.first_node.clone(),
}
}
}
pub struct PrintItemsIterator {
node: Option<PrintItemPath>,
}
impl PrintItemsIterator {
pub fn new(path: PrintItemPath) -> PrintItemsIterator {
PrintItemsIterator {
node: Some(path),
}
}
}
impl Iterator for PrintItemsIterator {
type Item = PrintItem;
fn next(&mut self) -> Option<PrintItem> {
let node = self.node.take();
match node {
Some(node) => {
self.node = node.get_next();
Some(node.get_item())
},
None => None
}
}
}
impl Into<PrintItems> for &str {
fn into(self) -> PrintItems {
let mut items = PrintItems::new();
items.push_str(self);
items
}
}
impl Into<PrintItems> for String {
fn into(self) -> PrintItems {
let mut items = PrintItems::new();
items.push_str(&self);
items
}
}
impl Into<PrintItems> for &String {
fn into(self) -> PrintItems {
let mut items = PrintItems::new();
items.push_str(self);
items
}
}
impl Into<PrintItems> for Condition {
fn into(self) -> PrintItems {
let mut items = PrintItems::new();
items.push_condition(self);
items
}
}
impl Into<PrintItems> for Signal {
fn into(self) -> PrintItems {
let mut items = PrintItems::new();
items.push_signal(self);
items
}
}
impl Into<PrintItems> for Option<PrintItemPath> {
fn into(self) -> PrintItems {
let mut items = PrintItems::new();
if let Some(path) = self {
items.push_path(path);
}
items
}
}
pub struct PrintNode {
pub(super) next: Option<PrintItemPath>,
pub(super) item: PrintItem,
}
impl Drop for PrintNode {
fn drop(&mut self) {
let mut next = mem::replace(&mut self.next, None);
loop {
next = match next {
Some(node) => match Rc::try_unwrap(node) {
Ok(node) => node.take_next(),
Err(_) => break,
},
None => break
}
}
}
}
impl PrintNode {
fn new(item: PrintItem) -> PrintNode {
PrintNode {
item,
next: None,
}
}
fn set_next(&mut self, new_next: Option<PrintItemPath>) {
let past_next = mem::replace(&mut self.next, new_next.clone());
if let Some(past_next) = past_next {
if let Some(new_next) = new_next {
new_next.get_last_next().unwrap_or(new_next).set_next(Some(past_next));
}
}
}
}
pub struct PrintNodeCell {
value: UnsafeCell<PrintNode>,
}
impl PrintNodeCell {
pub(super) fn new(item: PrintItem) -> PrintNodeCell {
PrintNodeCell {
value: UnsafeCell::new(PrintNode::new(item))
}
}
#[inline]
pub(super) fn get_item(&self) -> PrintItem {
unsafe {
(*self.value.get()).item.clone()
}
}
#[inline]
pub(super) fn get_next(&self) -> Option<PrintItemPath> {
unsafe {
(*self.value.get()).next.clone()
}
}
#[inline]
pub(super) fn set_next(&self, new_next: Option<PrintItemPath>) {
unsafe {
(*self.value.get()).set_next(new_next);
}
}
#[inline]
pub(super) fn get_last_next(&self) -> Option<PrintItemPath> {
let mut current = self.get_next();
loop {
if let Some(last) = ¤t {
if let Some(next) = last.get_next() {
current.replace(next);
continue;
}
}
break;
}
return current;
}
#[inline]
pub(super) unsafe fn get_node(&self) -> *mut PrintNode {
self.value.get()
}
#[inline]
pub fn take_next(self) -> Option<PrintItemPath> {
self.value.into_inner().next.take()
}
}
pub type PrintItemPath = Rc<PrintNodeCell>;
#[derive(Clone)]
pub enum PrintItem {
String(Rc<StringContainer>),
Condition(Rc<Condition>),
Info(Rc<Info>),
Signal(Signal),
RcPath(PrintItemPath),
}
#[derive(Clone, PartialEq, Copy, Debug)]
pub enum Signal {
NewLine,
Tab,
PossibleNewLine,
SpaceOrNewLine,
ExpectNewLine,
StartIndent,
FinishIndent,
StartNewLineGroup,
FinishNewLineGroup,
SingleIndent,
StartIgnoringIndent,
FinishIgnoringIndent,
StartForceNoNewLines,
FinishForceNoNewLines,
SpaceIfNotTrailing,
}
#[derive(Clone, PartialEq, Copy, Debug)]
pub struct Info {
id: usize,
name: &'static str,
}
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
}
}
#[inline]
pub fn get_unique_id(&self) -> usize {
self.id
}
#[inline]
pub fn get_name(&self) -> &'static str {
self.name
}
}
#[derive(Clone)]
pub struct Condition {
id: usize,
name: &'static str,
pub(super) is_stored: bool,
pub(super) condition: Rc<Box<ConditionResolver>>,
pub(super) true_path: Option<PrintItemPath>,
pub(super) false_path: Option<PrintItemPath>,
pub(super) dependent_infos: Option<Vec<Info>>,
}
static CONDITION_COUNTER: AtomicUsize = AtomicUsize::new(0);
impl Condition {
pub fn new(name: &'static str, properties: ConditionProperties) -> Condition {
Condition::new_internal(name, properties, None)
}
pub fn new_true() -> Condition {
Condition::new_internal("trueCondition", ConditionProperties {
condition: Box::new(|_| Some(true)),
true_path: None,
false_path: None,
}, None)
}
pub fn new_false() -> Condition {
Condition::new_internal("falseCondition", ConditionProperties {
condition: Box::new(|_| Some(false)),
true_path: None,
false_path: None,
}, None)
}
pub fn new_with_dependent_infos(name: &'static str, properties: ConditionProperties, dependent_infos: Vec<Info>) -> Condition {
Condition::new_internal(name, properties, Some(dependent_infos))
}
fn new_internal(name: &'static str, properties: ConditionProperties, dependent_infos: Option<Vec<Info>>) -> Condition {
Condition {
id: CONDITION_COUNTER.fetch_add(1, Ordering::SeqCst),
is_stored: dependent_infos.is_some(),
name,
condition: Rc::new(properties.condition),
true_path: properties.true_path.map(|x| x.first_node).flatten(),
false_path: properties.false_path.map(|x| x.first_node).flatten(),
dependent_infos,
}
}
#[inline]
pub fn get_unique_id(&self) -> usize {
self.id
}
#[inline]
pub fn get_name(&self) -> &'static str {
self.name
}
#[inline]
pub fn get_true_path(&self) -> &Option<PrintItemPath> {
&self.true_path
}
#[inline]
pub fn get_false_path(&self) -> &Option<PrintItemPath> {
&self.false_path
}
#[inline]
pub(super) fn resolve(&self, context: &mut ConditionResolverContext) -> Option<bool> {
(self.condition)(context)
}
pub fn get_reference(&mut self) -> ConditionReference {
self.is_stored = true;
ConditionReference::new(self.name, self.id)
}
}
#[derive(Clone, PartialEq, Copy, Debug)]
pub struct ConditionReference {
pub(super) name: &'static str,
pub(super) id: usize,
}
impl ConditionReference {
pub(super) fn new(name: &'static str, id: usize) -> ConditionReference {
ConditionReference { name, id }
}
pub fn create_resolver(&self) -> impl Fn(&mut ConditionResolverContext) -> Option<bool> + Clone + 'static {
let captured_self = self.clone();
move |condition_context: &mut ConditionResolverContext| {
condition_context.get_resolved_condition(&captured_self)
}
}
}
pub struct ConditionProperties {
pub condition: Box<ConditionResolver>,
pub true_path: Option<PrintItems>,
pub false_path: Option<PrintItems>,
}
pub type ConditionResolver = dyn Fn(&mut ConditionResolverContext) -> Option<bool>;
pub struct ConditionResolverContext<'a> {
printer: &'a mut Printer,
pub writer_info: WriterInfo,
}
impl<'a> ConditionResolverContext<'a> {
pub(super) fn new(printer: &'a mut Printer, writer_info: WriterInfo) -> Self {
ConditionResolverContext {
printer,
writer_info,
}
}
pub fn get_resolved_condition(&mut self, condition_reference: &ConditionReference) -> Option<bool> {
self.printer.get_resolved_condition(condition_reference)
}
pub fn get_resolved_info(&self, info: &Info) -> Option<&WriterInfo> {
self.printer.get_resolved_info(info)
}
pub fn clear_info(&mut self, info: &Info) {
self.printer.clear_info(info)
}
}
#[derive(Clone)]
pub struct StringContainer {
pub text: String,
pub(super) char_count: u32,
}
impl StringContainer {
pub fn new(text: String) -> StringContainer {
let char_count = text.chars().count() as u32;
StringContainer {
text,
char_count
}
}
}
#[derive(Clone, Debug)]
pub struct WriterInfo {
pub line_number: u32,
pub column_number: u32,
pub indent_level: u8,
pub line_start_indent_level: u8,
pub line_start_column_number: u32,
}
impl WriterInfo {
pub fn is_start_of_line(&self) -> bool {
self.column_number == self.line_start_column_number
}
pub fn get_line_and_column(&self) -> (u32, u32) {
(self.line_number, self.column_number)
}
}