use std::borrow::Cow;
use std::cell::UnsafeCell;
use std::mem;
use std::rc::Rc;
use super::condition_resolvers;
use super::printer::Printer;
use super::thread_state;
#[derive(Default)]
pub struct PrintItems {
pub(super) first_node: Option<PrintItemPath>,
last_node: Option<PrintItemPath>,
}
impl PrintItems {
pub fn new() -> Self {
Self {
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 = thread_state::with_bump_allocator(|bump| bump.alloc_print_node_cell(PrintNodeCell::new(item)));
if let Some(first_node) = &self.first_node {
let new_last_node = node.get_last_next().unwrap_or(node);
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) = items.first_node {
if let Some(current_first_node) = &self.first_node {
self.last_node.as_ref().unwrap_or(current_first_node).set_next(Some(first_node));
if items.last_node.is_some() {
self.last_node = items.last_node;
} else if items.first_node.is_some() {
self.last_node = items.first_node;
}
} else {
self.first_node = items.first_node;
self.last_node = items.last_node;
}
}
}
pub fn push_str_runtime_width_computed(&mut self, item: &'static str) {
self.push_cow_string(Cow::Borrowed(item))
}
pub fn push_force_current_line_indentation(&mut self) {
const STR_EMPTY: StringContainer = StringContainer { text: "", char_count: 0 };
self.push_item_internal(PrintItem::String(&STR_EMPTY))
}
pub fn push_space(&mut self) {
const STR_SPACE: StringContainer = StringContainer { text: " ", char_count: 1 };
self.push_item_internal(PrintItem::String(&STR_SPACE))
}
pub fn push_sc(&mut self, item: &'static StringContainer) {
self.push_item_internal(PrintItem::String(item))
}
pub fn push_string(&mut self, item: String) {
self.push_cow_string(Cow::Owned(item))
}
fn push_cow_string(&mut self, item: Cow<'static, str>) {
let string_container = thread_state::with_bump_allocator(|bump| bump.alloc_string(item));
self.push_item_internal(PrintItem::String(string_container));
}
pub fn push_condition(&mut self, condition: Condition) {
let condition = thread_state::with_bump_allocator(|bump| bump.alloc_condition(condition));
self.push_item_internal(PrintItem::Condition(condition));
}
pub fn push_info(&mut self, info: impl Into<Info>) {
self.push_item_internal(PrintItem::Info(info.into()));
}
pub fn push_line_and_column(&mut self, line_and_col: LineAndColumn) {
self.push_info(line_and_col.line);
self.push_info(line_and_col.column);
}
pub fn push_anchor(&mut self, anchor: impl Into<Anchor>) {
self.push_item_internal(PrintItem::Anchor(anchor.into()));
}
pub fn push_reevaluation(&mut self, condition_reevaluation: ConditionReevaluation) {
self.push_item_internal(PrintItem::ConditionReevaluation(condition_reevaluation));
}
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, 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::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, 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, format!("{} ", &indent_text)));
}
}
PrintItem::String(str_text) => text.push_str(&get_line(format!("`{}`", str_text.text), &indent_text)),
PrintItem::RcPath(path) => text.push_str(&get_items_as_text(path, indent_text.clone())),
PrintItem::Anchor(Anchor::LineNumber(line_number_anchor)) => {
text.push_str(&get_line(format!("Line number anchor: {}", line_number_anchor.name()), &indent_text))
}
PrintItem::Info(info) => {
let (desc, name) = match info {
Info::LineNumber(info) => ("Line number", info.name()),
Info::ColumnNumber(info) => ("Column number", info.name()),
Info::IsStartOfLine(info) => ("Is start of line", info.name()),
Info::IndentLevel(info) => ("Indent level", info.name()),
Info::LineStartColumnNumber(info) => ("Line start column number", info.name()),
Info::LineStartIndentLevel(info) => ("Line start indent level", info.name()),
};
text.push_str(&get_line(format!("{}: {}", desc, name), &indent_text))
}
PrintItem::ConditionReevaluation(reevaluation) => text.push_str(&get_line(format!("Condition reevaluation: {}", reevaluation.name()), &indent_text)),
}
}
return text;
fn get_line(text: String, indent_text: &str) -> String {
format!("{}{}\n", indent_text, text)
}
}
}
pub fn iter(&self) -> PrintItemsIterator {
PrintItemsIterator { node: self.first_node }
}
}
pub struct PrintItemsIterator {
node: Option<PrintItemPath>,
}
impl PrintItemsIterator {
pub fn new(path: PrintItemPath) -> Self {
Self { 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 From<&'static str> for PrintItems {
fn from(value: &'static str) -> Self {
let mut items = PrintItems::new();
items.push_str_runtime_width_computed(value);
items
}
}
impl From<String> for PrintItems {
fn from(value: String) -> Self {
let mut items = PrintItems::new();
items.push_string(value);
items
}
}
impl From<Condition> for PrintItems {
fn from(value: Condition) -> Self {
let mut items = PrintItems::new();
items.push_condition(value);
items
}
}
impl From<Signal> for PrintItems {
fn from(value: Signal) -> Self {
let mut items = PrintItems::new();
items.push_signal(value);
items
}
}
impl From<PrintItemPath> for PrintItems {
fn from(value: PrintItemPath) -> Self {
let mut items = PrintItems::new();
items.push_path(value);
items
}
}
impl<T> From<Option<T>> for PrintItems
where
PrintItems: From<T>,
{
fn from(value: Option<T>) -> Self {
value.map(PrintItems::from).unwrap_or_default()
}
}
#[cfg(feature = "tracing")]
#[derive(serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Trace {
pub nanos: u128,
pub print_node_id: u32,
#[serde(skip_serializing_if = "Option::is_none")]
pub writer_node_id: Option<u32>,
}
#[cfg(feature = "tracing")]
#[derive(serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct TraceWriterNode {
pub writer_node_id: u32,
#[serde(skip_serializing_if = "Option::is_none")]
pub previous_node_id: Option<u32>,
pub text: String,
}
#[cfg(feature = "tracing")]
#[derive(serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct TracePrintNode {
pub print_node_id: u32,
#[serde(skip_serializing_if = "Option::is_none")]
pub next_print_node_id: Option<u32>,
pub print_item: TracePrintItem,
}
#[cfg(feature = "tracing")]
#[derive(serde::Serialize)]
#[serde(tag = "kind", content = "content", rename_all = "camelCase")]
pub enum TracePrintItem {
String(String),
Condition(TraceCondition),
Info(TraceInfo),
Signal(Signal),
RcPath(u32),
Anchor(TraceLineNumberAnchor),
ConditionReevaluation(TraceConditionReevaluation),
}
#[cfg(feature = "tracing")]
#[derive(serde::Serialize)]
#[serde(tag = "kind", content = "content", rename_all = "camelCase")]
pub enum TraceInfo {
LineNumber(TraceInfoInner),
ColumnNumber(TraceInfoInner),
IsStartOfLine(TraceInfoInner),
IndentLevel(TraceInfoInner),
LineStartColumnNumber(TraceInfoInner),
LineStartIndentLevel(TraceInfoInner),
}
#[cfg(feature = "tracing")]
#[derive(serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct TraceInfoInner {
pub info_id: u32,
pub name: String,
}
#[cfg(feature = "tracing")]
impl TraceInfoInner {
pub fn new(info_id: u32, name: &str) -> Self {
Self {
info_id,
name: name.to_string(),
}
}
}
#[cfg(feature = "tracing")]
#[derive(serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct TraceLineNumberAnchor {
pub anchor_id: u32,
pub name: String,
}
#[cfg(feature = "tracing")]
#[derive(serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct TraceConditionReevaluation {
pub condition_id: u32,
pub name: String,
}
#[cfg(feature = "tracing")]
#[derive(serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct TraceCondition {
pub condition_id: u32,
pub name: String,
pub is_stored: bool,
pub store_save_point: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub true_path: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub false_path: Option<u32>,
}
pub struct PrintNode {
pub(super) next: Option<PrintItemPath>,
pub(super) item: PrintItem,
#[cfg(feature = "tracing")]
pub print_node_id: u32,
}
impl PrintNode {
fn new(item: PrintItem) -> PrintNode {
PrintNode {
item,
next: None,
#[cfg(feature = "tracing")]
print_node_id: thread_state::next_print_node_id(),
}
}
fn set_next(&mut self, new_next: Option<PrintItemPath>) {
let past_next = mem::replace(&mut self.next, new_next);
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 }
}
#[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;
}
current
}
#[cfg(feature = "tracing")]
pub(super) fn get_node_id(&self) -> u32 {
unsafe { (*self.get_node()).print_node_id }
}
#[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 = UnsafePrintLifetime<PrintNodeCell>;
pub(super) type UnsafePrintLifetime<T> = &'static T;
#[derive(Clone)]
pub enum PrintItem {
String(UnsafePrintLifetime<StringContainer>),
Condition(UnsafePrintLifetime<Condition>),
Signal(Signal),
RcPath(PrintItemPath),
Anchor(Anchor),
Info(Info),
ConditionReevaluation(ConditionReevaluation),
}
#[derive(Clone, PartialEq, Eq, Copy, Debug, serde::Serialize)]
pub enum Signal {
NewLine,
Tab,
PossibleNewLine,
SpaceOrNewLine,
ExpectNewLine,
QueueStartIndent,
StartIndent,
FinishIndent,
StartNewLineGroup,
FinishNewLineGroup,
SingleIndent,
StartIgnoringIndent,
FinishIgnoringIndent,
StartForceNoNewLines,
FinishForceNoNewLines,
SpaceIfNotTrailing,
}
#[derive(Clone)]
pub enum Anchor {
LineNumber(LineNumberAnchor),
}
impl From<LineNumberAnchor> for Anchor {
fn from(anchor: LineNumberAnchor) -> Self {
Anchor::LineNumber(anchor)
}
}
#[derive(Clone)]
pub struct LineNumberAnchor {
id: u32,
line_number: LineNumber,
}
impl LineNumberAnchor {
pub fn new(line_number: LineNumber) -> Self {
Self {
id: thread_state::next_line_number_anchor_id(),
line_number,
}
}
#[inline]
pub fn unique_id(&self) -> u32 {
self.id
}
#[inline]
pub fn line_number_id(&self) -> u32 {
self.line_number.id
}
#[inline]
pub fn name(&self) -> &'static str {
self.line_number.name()
}
}
#[derive(Clone, PartialEq, Eq, Copy, Debug)]
pub enum Info {
LineNumber(LineNumber),
ColumnNumber(ColumnNumber),
IsStartOfLine(IsStartOfLine),
IndentLevel(IndentLevel),
LineStartColumnNumber(LineStartColumnNumber),
LineStartIndentLevel(LineStartIndentLevel),
}
impl From<LineNumber> for Info {
fn from(info: LineNumber) -> Self {
Info::LineNumber(info)
}
}
impl From<ColumnNumber> for Info {
fn from(info: ColumnNumber) -> Self {
Info::ColumnNumber(info)
}
}
impl From<IsStartOfLine> for Info {
fn from(info: IsStartOfLine) -> Self {
Info::IsStartOfLine(info)
}
}
impl From<IndentLevel> for Info {
fn from(info: IndentLevel) -> Self {
Info::IndentLevel(info)
}
}
impl From<LineStartColumnNumber> for Info {
fn from(info: LineStartColumnNumber) -> Self {
Info::LineStartColumnNumber(info)
}
}
impl From<LineStartIndentLevel> for Info {
fn from(info: LineStartIndentLevel) -> Self {
Info::LineStartIndentLevel(info)
}
}
#[derive(Clone, PartialEq, Eq, Copy, Debug)]
pub struct LineAndColumn {
pub line: LineNumber,
pub column: ColumnNumber,
}
impl LineAndColumn {
pub fn new(name: &'static str) -> Self {
Self {
line: LineNumber::new(name),
column: ColumnNumber::new(name),
}
}
}
#[derive(Clone, PartialEq, Eq, Copy, Debug)]
pub struct LineNumber {
id: u32,
#[cfg(debug_assertions)]
name: &'static str,
}
impl LineNumber {
pub fn new(_name: &'static str) -> Self {
Self {
id: thread_state::next_line_number_id(),
#[cfg(debug_assertions)]
name: _name,
}
}
#[inline]
pub fn unique_id(&self) -> u32 {
self.id
}
#[inline]
pub fn name(&self) -> &'static str {
#[cfg(debug_assertions)]
return self.name;
#[cfg(not(debug_assertions))]
return "line_number";
}
}
#[derive(Clone, PartialEq, Eq, Copy, Debug)]
pub struct ColumnNumber {
id: u32,
#[cfg(debug_assertions)]
name: &'static str,
}
impl ColumnNumber {
pub fn new(_name: &'static str) -> Self {
Self {
id: thread_state::next_column_number_id(),
#[cfg(debug_assertions)]
name: _name,
}
}
#[inline]
pub fn unique_id(&self) -> u32 {
self.id
}
#[inline]
pub fn name(&self) -> &'static str {
#[cfg(debug_assertions)]
return self.name;
#[cfg(not(debug_assertions))]
return "column_number";
}
}
#[derive(Clone, PartialEq, Eq, Copy, Debug)]
pub struct IsStartOfLine {
id: u32,
#[cfg(debug_assertions)]
name: &'static str,
}
impl IsStartOfLine {
pub fn new(_name: &'static str) -> Self {
Self {
id: thread_state::next_is_start_of_line_id(),
#[cfg(debug_assertions)]
name: _name,
}
}
#[inline]
pub fn unique_id(&self) -> u32 {
self.id
}
#[inline]
pub fn name(&self) -> &'static str {
#[cfg(debug_assertions)]
return self.name;
#[cfg(not(debug_assertions))]
return "is_start_of_line";
}
}
#[derive(Clone, PartialEq, Eq, Copy, Debug)]
pub struct LineStartColumnNumber {
id: u32,
#[cfg(debug_assertions)]
name: &'static str,
}
impl LineStartColumnNumber {
pub fn new(_name: &'static str) -> Self {
Self {
id: thread_state::next_line_start_column_number_id(),
#[cfg(debug_assertions)]
name: _name,
}
}
#[inline]
pub fn unique_id(&self) -> u32 {
self.id
}
#[inline]
pub fn name(&self) -> &'static str {
#[cfg(debug_assertions)]
return self.name;
#[cfg(not(debug_assertions))]
return "line_start_column_number";
}
}
#[derive(Clone, PartialEq, Eq, Copy, Debug)]
pub struct IndentLevel {
id: u32,
#[cfg(debug_assertions)]
name: &'static str,
}
impl IndentLevel {
pub fn new(_name: &'static str) -> Self {
Self {
id: thread_state::next_indent_level_id(),
#[cfg(debug_assertions)]
name: _name,
}
}
#[inline]
pub fn unique_id(&self) -> u32 {
self.id
}
#[inline]
pub fn name(&self) -> &'static str {
#[cfg(debug_assertions)]
return self.name;
#[cfg(not(debug_assertions))]
return "indent_level";
}
}
#[derive(Clone, PartialEq, Eq, Copy, Debug)]
pub struct LineStartIndentLevel {
id: u32,
#[cfg(debug_assertions)]
name: &'static str,
}
impl LineStartIndentLevel {
pub fn new(_name: &'static str) -> Self {
Self {
id: thread_state::next_line_start_indent_level_id(),
#[cfg(debug_assertions)]
name: _name,
}
}
#[inline]
pub fn unique_id(&self) -> u32 {
self.id
}
#[inline]
pub fn name(&self) -> &'static str {
#[cfg(debug_assertions)]
return self.name;
#[cfg(not(debug_assertions))]
return "line_start_indent_level";
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct ConditionReevaluation {
pub(crate) condition_reevaluation_id: u32,
pub(crate) condition_id: u32,
#[cfg(debug_assertions)]
name: &'static str,
}
impl ConditionReevaluation {
pub(crate) fn new(_name: &'static str, condition_id: u32) -> Self {
ConditionReevaluation {
condition_reevaluation_id: thread_state::next_condition_reevaluation_id(),
condition_id,
#[cfg(debug_assertions)]
name: _name,
}
}
pub fn name(&self) -> &'static str {
#[cfg(debug_assertions)]
return self.name;
#[cfg(not(debug_assertions))]
return "condition_reevaluation";
}
}
#[derive(Clone)]
pub struct Condition {
id: u32,
#[cfg(debug_assertions)]
name: &'static str,
pub(super) is_stored: bool,
pub(super) store_save_point: bool,
pub(super) condition: ConditionResolver,
pub(super) true_path: Option<PrintItemPath>,
pub(super) false_path: Option<PrintItemPath>,
}
impl Condition {
pub fn new(name: &'static str, properties: ConditionProperties) -> Self {
Self::new_internal(name, properties)
}
pub fn new_true() -> Self {
Self::new_internal(
"trueCondition",
ConditionProperties {
condition: condition_resolvers::true_resolver(),
true_path: None,
false_path: None,
},
)
}
pub fn new_false() -> Self {
Self::new_internal(
"falseCondition",
ConditionProperties {
condition: condition_resolvers::false_resolver(),
true_path: None,
false_path: None,
},
)
}
fn new_internal(_name: &'static str, properties: ConditionProperties) -> Self {
Self {
id: thread_state::next_condition_id(),
is_stored: false,
store_save_point: false,
#[cfg(debug_assertions)]
name: _name,
condition: properties.condition,
true_path: properties.true_path.and_then(|x| x.first_node),
false_path: properties.false_path.and_then(|x| x.first_node),
}
}
#[inline]
pub fn unique_id(&self) -> u32 {
self.id
}
#[inline]
pub fn name(&self) -> &'static str {
#[cfg(debug_assertions)]
return self.name;
#[cfg(not(debug_assertions))]
return "condition";
}
#[inline]
pub fn true_path(&self) -> &Option<PrintItemPath> {
&self.true_path
}
#[inline]
pub fn false_path(&self) -> &Option<PrintItemPath> {
&self.false_path
}
#[inline]
pub(super) fn resolve(&self, context: &mut ConditionResolverContext) -> Option<bool> {
(self.condition)(context)
}
pub fn create_reference(&mut self) -> ConditionReference {
self.is_stored = true;
ConditionReference::new(self.name(), self.id)
}
pub fn create_reevaluation(&mut self) -> ConditionReevaluation {
self.store_save_point = true;
self.is_stored = true;
ConditionReevaluation::new(self.name(), self.id)
}
}
#[derive(Clone, PartialEq, Eq, Copy, Debug)]
pub struct ConditionReference {
#[cfg(debug_assertions)]
pub(super) name: &'static str,
pub(super) id: u32,
}
impl ConditionReference {
pub(super) fn new(_name: &'static str, id: u32) -> ConditionReference {
ConditionReference {
#[cfg(debug_assertions)]
name: _name,
id,
}
}
#[inline]
pub(super) fn name(&self) -> &'static str {
#[cfg(debug_assertions)]
return self.name;
#[cfg(not(debug_assertions))]
return "conditionRef";
}
pub fn create_resolver(&self) -> ConditionResolver {
let captured_self = *self;
Rc::new(move |condition_context: &mut ConditionResolverContext| condition_context.resolved_condition(&captured_self))
}
}
pub struct ConditionProperties {
pub condition: ConditionResolver,
pub true_path: Option<PrintItems>,
pub false_path: Option<PrintItems>,
}
pub type ConditionResolver = Rc<dyn Fn(&mut ConditionResolverContext) -> Option<bool>>;
pub struct ConditionResolverContext<'a, 'b> {
printer: &'a mut Printer<'b>,
pub writer_info: WriterInfo,
}
impl<'a, 'b> ConditionResolverContext<'a, 'b> {
pub(super) fn new(printer: &'a mut Printer<'b>, writer_info: WriterInfo) -> Self {
ConditionResolverContext { printer, writer_info }
}
pub fn resolved_condition(&mut self, condition_reference: &ConditionReference) -> Option<bool> {
self.printer.resolved_condition(condition_reference)
}
pub fn resolved_line_and_column(&mut self, line_and_column: LineAndColumn) -> Option<(u32, u32)> {
let line = self.printer.resolved_line_number(line_and_column.line)?;
let column = self.printer.resolved_column_number(line_and_column.column)?;
Some((line, column))
}
pub fn resolved_line_number(&mut self, line_number: LineNumber) -> Option<u32> {
self.printer.resolved_line_number(line_number)
}
pub fn resolved_column_number(&mut self, column_number: ColumnNumber) -> Option<u32> {
self.printer.resolved_column_number(column_number)
}
pub fn resolved_is_start_of_line(&mut self, is_start_of_line: IsStartOfLine) -> Option<bool> {
self.printer.resolved_is_start_of_line(is_start_of_line)
}
pub fn resolved_indent_level(&mut self, indent_level: IndentLevel) -> Option<u8> {
self.printer.resolved_indent_level(indent_level)
}
pub fn resolved_line_start_column_number(&mut self, line_start_column_number: LineStartColumnNumber) -> Option<u32> {
self.printer.resolved_line_start_column_number(line_start_column_number)
}
pub fn resolved_line_start_indent_level(&mut self, line_start_indent_level: LineStartIndentLevel) -> Option<u8> {
self.printer.resolved_line_start_indent_level(line_start_indent_level)
}
pub fn clear_line_and_column(&mut self, lc: LineAndColumn) {
self.clear_info(lc.line);
self.clear_info(lc.column);
}
pub fn clear_info(&mut self, info: impl Into<Info>) {
self.printer.clear_info(info.into())
}
pub fn is_forcing_no_newlines(&self) -> bool {
self.printer.is_forcing_no_newlines()
}
}
#[derive(Clone)]
pub struct StringContainer {
pub text: UnsafePrintLifetime<str>,
pub(super) char_count: u32,
}
impl StringContainer {
pub fn new(text: UnsafePrintLifetime<str>) -> Self {
let char_count = unicode_width::UnicodeWidthStr::width(text) as u32;
Self { text, char_count }
}
pub const fn proc_macro_new_with_char_count(text: UnsafePrintLifetime<str>, char_count: u32) -> Self {
Self { 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 indent_width: u8,
pub expect_newline_next: bool,
}
impl WriterInfo {
pub fn is_start_of_line(&self) -> bool {
self.expect_newline_next || self.is_column_number_at_line_start()
}
pub fn is_start_of_line_indented(&self) -> bool {
self.line_start_indent_level > self.indent_level
}
pub fn is_column_number_at_line_start(&self) -> bool {
self.column_number == self.line_start_column_number()
}
pub fn line_start_column_number(&self) -> u32 {
(self.line_start_indent_level as u32) * (self.indent_width as u32)
}
pub fn line_and_column(&self) -> (u32, u32) {
(self.line_number, self.column_number)
}
}