1use std::borrow::Cow;
2use std::cell::UnsafeCell;
3use std::mem;
4use std::rc::Rc;
5
6use super::condition_resolvers;
7use super::printer::Printer;
8use super::thread_state;
9
10#[derive(Default)]
11pub struct PrintItems {
12 pub(super) first_node: Option<PrintItemPath>,
13 last_node: Option<PrintItemPath>,
14}
15
16impl PrintItems {
17 pub fn new() -> Self {
18 Self {
19 first_node: None,
20 last_node: None,
21 }
22 }
23
24 pub fn into_rc_path(self) -> Option<PrintItemPath> {
25 self.first_node
26 }
27
28 pub fn push_item(&mut self, item: PrintItem) {
29 self.push_item_internal(item);
30 }
31
32 #[inline]
33 fn push_item_internal(&mut self, item: PrintItem) {
34 let node = thread_state::with_bump_allocator(|bump| bump.alloc_print_node_cell(PrintNodeCell::new(item)));
35 if let Some(first_node) = &self.first_node {
36 let new_last_node = node.get_last_next().unwrap_or(node);
37 self.last_node.as_ref().unwrap_or(first_node).set_next(Some(node));
38 self.last_node = Some(new_last_node);
39 } else {
40 self.last_node = node.get_last_next();
41 self.first_node = Some(node);
42 }
43 }
44}
45
46impl PrintItems {
47 pub fn extend(&mut self, items: PrintItems) {
48 if let Some(first_node) = items.first_node {
49 if let Some(current_first_node) = &self.first_node {
50 self.last_node.as_ref().unwrap_or(current_first_node).set_next(Some(first_node));
51
52 if items.last_node.is_some() {
53 self.last_node = items.last_node;
54 } else if items.first_node.is_some() {
55 self.last_node = items.first_node;
56 }
57 } else {
58 self.first_node = items.first_node;
59 self.last_node = items.last_node;
60 }
61 }
62 }
63
64 pub fn push_str_runtime_width_computed(&mut self, item: &'static str) {
69 self.push_cow_string(Cow::Borrowed(item))
70 }
71
72 pub fn push_force_current_line_indentation(&mut self) {
73 const STR_EMPTY: StringContainer = StringContainer { text: "", char_count: 0 };
74 self.push_item_internal(PrintItem::String(&STR_EMPTY))
75 }
76
77 pub fn push_space(&mut self) {
78 const STR_SPACE: StringContainer = StringContainer { text: " ", char_count: 1 };
79 self.push_item_internal(PrintItem::String(&STR_SPACE))
80 }
81
82 pub fn push_sc(&mut self, item: &'static StringContainer) {
84 self.push_item_internal(PrintItem::String(item))
85 }
86
87 pub fn push_string(&mut self, item: String) {
88 self.push_cow_string(Cow::Owned(item))
89 }
90
91 fn push_cow_string(&mut self, item: Cow<'static, str>) {
92 let string_container = thread_state::with_bump_allocator(|bump| bump.alloc_string(item));
93 self.push_item_internal(PrintItem::String(string_container));
94 }
95
96 pub fn push_condition(&mut self, condition: Condition) {
97 let condition = thread_state::with_bump_allocator(|bump| bump.alloc_condition(condition));
98 self.push_item_internal(PrintItem::Condition(condition));
99 }
100
101 pub fn push_info(&mut self, info: impl Into<Info>) {
102 self.push_item_internal(PrintItem::Info(info.into()));
103 }
104
105 pub fn push_line_and_column(&mut self, line_and_col: LineAndColumn) {
106 self.push_info(line_and_col.line);
107 self.push_info(line_and_col.column);
108 }
109
110 pub fn push_anchor(&mut self, anchor: impl Into<Anchor>) {
111 self.push_item_internal(PrintItem::Anchor(anchor.into()));
112 }
113
114 pub fn push_reevaluation(&mut self, condition_reevaluation: ConditionReevaluation) {
115 self.push_item_internal(PrintItem::ConditionReevaluation(condition_reevaluation));
116 }
117
118 pub fn push_signal(&mut self, signal: Signal) {
119 self.push_item_internal(PrintItem::Signal(signal));
120 }
121
122 pub fn push_path(&mut self, path: PrintItemPath) {
123 self.push_item_internal(PrintItem::RcPath(path))
124 }
125
126 pub fn push_optional_path(&mut self, path: Option<PrintItemPath>) {
127 if let Some(path) = path {
128 self.push_path(path);
129 }
130 }
131
132 pub fn is_empty(&self) -> bool {
133 self.first_node.is_none()
134 }
135
136 #[cfg(debug_assertions)]
138 pub fn get_as_text(&self) -> String {
139 return if let Some(first_node) = &self.first_node {
140 get_items_as_text(first_node, String::from(""))
141 } else {
142 String::new()
143 };
144
145 fn get_items_as_text(items: PrintItemPath, indent_text: String) -> String {
146 let mut text = String::new();
147 for item in PrintItemsIterator::new(items) {
148 match item {
149 PrintItem::Signal(signal) => text.push_str(&get_line(format!("Signal::{:?}", signal), &indent_text)),
150 PrintItem::Condition(condition) => {
151 text.push_str(&get_line(format!("Condition: {}", condition.name), &indent_text));
152 if let Some(true_path) = &condition.true_path {
153 text.push_str(&get_line(String::from(" true:"), &indent_text));
154 text.push_str(&get_items_as_text(true_path, format!("{} ", &indent_text)));
155 }
156 if let Some(false_path) = &condition.false_path {
157 text.push_str(&get_line(String::from(" false:"), &indent_text));
158 text.push_str(&get_items_as_text(false_path, format!("{} ", &indent_text)));
159 }
160 }
161 PrintItem::String(str_text) => text.push_str(&get_line(format!("`{}`", str_text.text), &indent_text)),
162 PrintItem::RcPath(path) => text.push_str(&get_items_as_text(path, indent_text.clone())),
163 PrintItem::Anchor(Anchor::LineNumber(line_number_anchor)) => {
164 text.push_str(&get_line(format!("Line number anchor: {}", line_number_anchor.name()), &indent_text))
165 }
166 PrintItem::Info(info) => {
167 let (desc, name) = match info {
168 Info::LineNumber(info) => ("Line number", info.name()),
169 Info::ColumnNumber(info) => ("Column number", info.name()),
170 Info::IsStartOfLine(info) => ("Is start of line", info.name()),
171 Info::IndentLevel(info) => ("Indent level", info.name()),
172 Info::LineStartColumnNumber(info) => ("Line start column number", info.name()),
173 Info::LineStartIndentLevel(info) => ("Line start indent level", info.name()),
174 };
175 text.push_str(&get_line(format!("{}: {}", desc, name), &indent_text))
176 }
177 PrintItem::ConditionReevaluation(reevaluation) => text.push_str(&get_line(format!("Condition reevaluation: {}", reevaluation.name()), &indent_text)),
178 }
179 }
180
181 return text;
182
183 fn get_line(text: String, indent_text: &str) -> String {
184 format!("{}{}\n", indent_text, text)
185 }
186 }
187 }
188
189 pub fn iter(&self) -> PrintItemsIterator {
190 PrintItemsIterator { node: self.first_node }
191 }
192}
193
194pub struct PrintItemsIterator {
195 node: Option<PrintItemPath>,
196}
197
198impl PrintItemsIterator {
199 pub fn new(path: PrintItemPath) -> Self {
200 Self { node: Some(path) }
201 }
202}
203
204impl Iterator for PrintItemsIterator {
205 type Item = PrintItem;
206
207 fn next(&mut self) -> Option<PrintItem> {
208 let node = self.node.take();
209
210 match node {
211 Some(node) => {
212 self.node = node.get_next();
213 Some(node.get_item())
214 }
215 None => None,
216 }
217 }
218}
219
220impl From<&'static str> for PrintItems {
221 fn from(value: &'static str) -> Self {
222 let mut items = PrintItems::new();
223 items.push_str_runtime_width_computed(value);
224 items
225 }
226}
227
228impl From<String> for PrintItems {
229 fn from(value: String) -> Self {
230 let mut items = PrintItems::new();
231 items.push_string(value);
232 items
233 }
234}
235
236impl From<Condition> for PrintItems {
237 fn from(value: Condition) -> Self {
238 let mut items = PrintItems::new();
239 items.push_condition(value);
240 items
241 }
242}
243
244impl From<Signal> for PrintItems {
245 fn from(value: Signal) -> Self {
246 let mut items = PrintItems::new();
247 items.push_signal(value);
248 items
249 }
250}
251
252impl From<PrintItemPath> for PrintItems {
253 fn from(value: PrintItemPath) -> Self {
254 let mut items = PrintItems::new();
255 items.push_path(value);
256 items
257 }
258}
259
260impl<T> From<Option<T>> for PrintItems
261where
262 PrintItems: From<T>,
263{
264 fn from(value: Option<T>) -> Self {
265 value.map(PrintItems::from).unwrap_or_default()
266 }
267}
268
269#[cfg(feature = "tracing")]
272#[derive(serde::Serialize)]
273#[serde(rename_all = "camelCase")]
274pub struct Trace {
275 pub nanos: u128,
277 pub print_node_id: u32,
278 #[serde(skip_serializing_if = "Option::is_none")]
279 pub writer_node_id: Option<u32>,
280}
281
282#[cfg(feature = "tracing")]
283#[derive(serde::Serialize)]
284#[serde(rename_all = "camelCase")]
285pub struct TraceWriterNode {
286 pub writer_node_id: u32,
287 #[serde(skip_serializing_if = "Option::is_none")]
288 pub previous_node_id: Option<u32>,
289 pub text: String,
290}
291
292#[cfg(feature = "tracing")]
293#[derive(serde::Serialize)]
294#[serde(rename_all = "camelCase")]
295pub struct TracePrintNode {
296 pub print_node_id: u32,
297 #[serde(skip_serializing_if = "Option::is_none")]
298 pub next_print_node_id: Option<u32>,
299 pub print_item: TracePrintItem,
300}
301
302#[cfg(feature = "tracing")]
303#[derive(serde::Serialize)]
304#[serde(tag = "kind", content = "content", rename_all = "camelCase")]
305pub enum TracePrintItem {
306 String(String),
307 Condition(TraceCondition),
308 Info(TraceInfo),
309 Signal(Signal),
310 RcPath(u32),
312 Anchor(TraceLineNumberAnchor),
313 ConditionReevaluation(TraceConditionReevaluation),
314}
315
316#[cfg(feature = "tracing")]
317#[derive(serde::Serialize)]
318#[serde(tag = "kind", content = "content", rename_all = "camelCase")]
319pub enum TraceInfo {
320 LineNumber(TraceInfoInner),
321 ColumnNumber(TraceInfoInner),
322 IsStartOfLine(TraceInfoInner),
323 IndentLevel(TraceInfoInner),
324 LineStartColumnNumber(TraceInfoInner),
325 LineStartIndentLevel(TraceInfoInner),
326}
327
328#[cfg(feature = "tracing")]
329#[derive(serde::Serialize)]
330#[serde(rename_all = "camelCase")]
331pub struct TraceInfoInner {
332 pub info_id: u32,
333 pub name: String,
334}
335
336#[cfg(feature = "tracing")]
337impl TraceInfoInner {
338 pub fn new(info_id: u32, name: &str) -> Self {
339 Self {
340 info_id,
341 name: name.to_string(),
342 }
343 }
344}
345
346#[cfg(feature = "tracing")]
347#[derive(serde::Serialize)]
348#[serde(rename_all = "camelCase")]
349pub struct TraceLineNumberAnchor {
350 pub anchor_id: u32,
351 pub name: String,
352}
353
354#[cfg(feature = "tracing")]
355#[derive(serde::Serialize)]
356#[serde(rename_all = "camelCase")]
357pub struct TraceConditionReevaluation {
358 pub condition_id: u32,
359 pub name: String,
360}
361
362#[cfg(feature = "tracing")]
363#[derive(serde::Serialize)]
364#[serde(rename_all = "camelCase")]
365pub struct TraceCondition {
366 pub condition_id: u32,
367 pub name: String,
368 pub is_stored: bool,
369 pub store_save_point: bool,
370 #[serde(skip_serializing_if = "Option::is_none")]
371 pub true_path: Option<u32>,
373 #[serde(skip_serializing_if = "Option::is_none")]
374 pub false_path: Option<u32>,
376}
377
378pub struct PrintNode {
379 pub(super) next: Option<PrintItemPath>,
380 pub(super) item: PrintItem,
381 #[cfg(feature = "tracing")]
382 pub print_node_id: u32,
383}
384
385impl PrintNode {
386 fn new(item: PrintItem) -> PrintNode {
387 PrintNode {
388 item,
389 next: None,
390 #[cfg(feature = "tracing")]
391 print_node_id: thread_state::next_print_node_id(),
392 }
393 }
394
395 fn set_next(&mut self, new_next: Option<PrintItemPath>) {
396 let past_next = mem::replace(&mut self.next, new_next);
397
398 if let Some(past_next) = past_next {
399 if let Some(new_next) = new_next {
400 new_next.get_last_next().unwrap_or(new_next).set_next(Some(past_next));
401 }
402 }
403 }
404}
405
406pub struct PrintNodeCell {
408 value: UnsafeCell<PrintNode>,
409}
410
411impl PrintNodeCell {
412 pub(super) fn new(item: PrintItem) -> PrintNodeCell {
413 PrintNodeCell {
414 value: UnsafeCell::new(PrintNode::new(item)),
415 }
416 }
417
418 #[inline]
419 pub(super) fn get_item(&self) -> PrintItem {
420 unsafe { (*self.value.get()).item.clone() }
421 }
422
423 #[inline]
424 pub(super) fn get_next(&self) -> Option<PrintItemPath> {
425 unsafe { (*self.value.get()).next }
426 }
427
428 #[inline]
429 pub(super) fn set_next(&self, new_next: Option<PrintItemPath>) {
430 unsafe {
431 (*self.value.get()).set_next(new_next);
432 }
433 }
434
435 #[inline]
436 pub(super) fn get_last_next(&self) -> Option<PrintItemPath> {
437 let mut current = self.get_next();
438 loop {
439 if let Some(last) = ¤t {
440 if let Some(next) = last.get_next() {
441 current.replace(next);
442 continue;
443 }
444 }
445 break;
446 }
447
448 current
449 }
450
451 #[cfg(feature = "tracing")]
452 pub(super) fn get_node_id(&self) -> u32 {
453 unsafe { (*self.get_node()).print_node_id }
454 }
455
456 #[inline]
459 pub(super) unsafe fn get_node(&self) -> *mut PrintNode {
460 self.value.get()
461 }
462
463 #[inline]
464 pub fn take_next(self) -> Option<PrintItemPath> {
465 self.value.into_inner().next.take()
466 }
467}
468
469pub type PrintItemPath = UnsafePrintLifetime<PrintNodeCell>;
470
471pub(super) type UnsafePrintLifetime<T> = &'static T;
480
481#[derive(Clone)]
485pub enum PrintItem {
486 String(UnsafePrintLifetime<StringContainer>),
487 Condition(UnsafePrintLifetime<Condition>),
488 Signal(Signal),
489 RcPath(PrintItemPath),
490 Anchor(Anchor),
491 Info(Info),
492 ConditionReevaluation(ConditionReevaluation),
493}
494
495#[derive(Clone, PartialEq, Eq, Copy, Debug, serde::Serialize)]
496pub enum Signal {
497 NewLine,
499 Tab,
501 PossibleNewLine,
504 SpaceOrNewLine,
507 ExpectNewLine,
509 QueueStartIndent,
511 StartIndent,
513 FinishIndent,
515 StartNewLineGroup,
518 FinishNewLineGroup,
520 SingleIndent,
522 StartIgnoringIndent,
524 FinishIgnoringIndent,
526 StartForceNoNewLines,
528 FinishForceNoNewLines,
530 SpaceIfNotTrailing,
532}
533
534#[derive(Clone)]
535pub enum Anchor {
536 LineNumber(LineNumberAnchor),
537}
538
539impl From<LineNumberAnchor> for Anchor {
540 fn from(anchor: LineNumberAnchor) -> Self {
541 Anchor::LineNumber(anchor)
542 }
543}
544
545#[derive(Clone)]
548pub struct LineNumberAnchor {
549 id: u32,
550 line_number: LineNumber,
551}
552
553impl LineNumberAnchor {
554 pub fn new(line_number: LineNumber) -> Self {
555 Self {
556 id: thread_state::next_line_number_anchor_id(),
557 line_number,
558 }
559 }
560
561 #[inline]
562 pub fn unique_id(&self) -> u32 {
563 self.id
564 }
565
566 #[inline]
567 pub fn line_number_id(&self) -> u32 {
568 self.line_number.id
569 }
570
571 #[inline]
572 pub fn name(&self) -> &'static str {
573 self.line_number.name()
574 }
575}
576
577#[derive(Clone, PartialEq, Eq, Copy, Debug)]
578pub enum Info {
579 LineNumber(LineNumber),
580 ColumnNumber(ColumnNumber),
581 IsStartOfLine(IsStartOfLine),
582 IndentLevel(IndentLevel),
583 LineStartColumnNumber(LineStartColumnNumber),
584 LineStartIndentLevel(LineStartIndentLevel),
585}
586
587impl From<LineNumber> for Info {
588 fn from(info: LineNumber) -> Self {
589 Info::LineNumber(info)
590 }
591}
592
593impl From<ColumnNumber> for Info {
594 fn from(info: ColumnNumber) -> Self {
595 Info::ColumnNumber(info)
596 }
597}
598
599impl From<IsStartOfLine> for Info {
600 fn from(info: IsStartOfLine) -> Self {
601 Info::IsStartOfLine(info)
602 }
603}
604
605impl From<IndentLevel> for Info {
606 fn from(info: IndentLevel) -> Self {
607 Info::IndentLevel(info)
608 }
609}
610
611impl From<LineStartColumnNumber> for Info {
612 fn from(info: LineStartColumnNumber) -> Self {
613 Info::LineStartColumnNumber(info)
614 }
615}
616
617impl From<LineStartIndentLevel> for Info {
618 fn from(info: LineStartIndentLevel) -> Self {
619 Info::LineStartIndentLevel(info)
620 }
621}
622
623#[derive(Clone, PartialEq, Eq, Copy, Debug)]
625pub struct LineAndColumn {
626 pub line: LineNumber,
627 pub column: ColumnNumber,
628}
629
630impl LineAndColumn {
631 pub fn new(name: &'static str) -> Self {
632 Self {
633 line: LineNumber::new(name),
634 column: ColumnNumber::new(name),
635 }
636 }
637}
638
639#[derive(Clone, PartialEq, Eq, Copy, Debug)]
640pub struct LineNumber {
641 id: u32,
642 #[cfg(debug_assertions)]
644 name: &'static str,
645}
646
647impl LineNumber {
648 pub fn new(_name: &'static str) -> Self {
649 Self {
650 id: thread_state::next_line_number_id(),
651 #[cfg(debug_assertions)]
652 name: _name,
653 }
654 }
655
656 #[inline]
657 pub fn unique_id(&self) -> u32 {
658 self.id
659 }
660
661 #[inline]
662 pub fn name(&self) -> &'static str {
663 #[cfg(debug_assertions)]
664 return self.name;
665 #[cfg(not(debug_assertions))]
666 return "line_number";
667 }
668}
669
670#[derive(Clone, PartialEq, Eq, Copy, Debug)]
671pub struct ColumnNumber {
672 id: u32,
673 #[cfg(debug_assertions)]
675 name: &'static str,
676}
677
678impl ColumnNumber {
679 pub fn new(_name: &'static str) -> Self {
680 Self {
681 id: thread_state::next_column_number_id(),
682 #[cfg(debug_assertions)]
683 name: _name,
684 }
685 }
686
687 #[inline]
688 pub fn unique_id(&self) -> u32 {
689 self.id
690 }
691
692 #[inline]
693 pub fn name(&self) -> &'static str {
694 #[cfg(debug_assertions)]
695 return self.name;
696 #[cfg(not(debug_assertions))]
697 return "column_number";
698 }
699}
700
701#[derive(Clone, PartialEq, Eq, Copy, Debug)]
702pub struct IsStartOfLine {
703 id: u32,
704 #[cfg(debug_assertions)]
706 name: &'static str,
707}
708
709impl IsStartOfLine {
710 pub fn new(_name: &'static str) -> Self {
711 Self {
712 id: thread_state::next_is_start_of_line_id(),
713 #[cfg(debug_assertions)]
714 name: _name,
715 }
716 }
717
718 #[inline]
719 pub fn unique_id(&self) -> u32 {
720 self.id
721 }
722
723 #[inline]
724 pub fn name(&self) -> &'static str {
725 #[cfg(debug_assertions)]
726 return self.name;
727 #[cfg(not(debug_assertions))]
728 return "is_start_of_line";
729 }
730}
731
732#[derive(Clone, PartialEq, Eq, Copy, Debug)]
733pub struct LineStartColumnNumber {
734 id: u32,
735 #[cfg(debug_assertions)]
737 name: &'static str,
738}
739
740impl LineStartColumnNumber {
741 pub fn new(_name: &'static str) -> Self {
742 Self {
743 id: thread_state::next_line_start_column_number_id(),
744 #[cfg(debug_assertions)]
745 name: _name,
746 }
747 }
748
749 #[inline]
750 pub fn unique_id(&self) -> u32 {
751 self.id
752 }
753
754 #[inline]
755 pub fn name(&self) -> &'static str {
756 #[cfg(debug_assertions)]
757 return self.name;
758 #[cfg(not(debug_assertions))]
759 return "line_start_column_number";
760 }
761}
762
763#[derive(Clone, PartialEq, Eq, Copy, Debug)]
764pub struct IndentLevel {
765 id: u32,
766 #[cfg(debug_assertions)]
768 name: &'static str,
769}
770
771impl IndentLevel {
772 pub fn new(_name: &'static str) -> Self {
773 Self {
774 id: thread_state::next_indent_level_id(),
775 #[cfg(debug_assertions)]
776 name: _name,
777 }
778 }
779
780 #[inline]
781 pub fn unique_id(&self) -> u32 {
782 self.id
783 }
784
785 #[inline]
786 pub fn name(&self) -> &'static str {
787 #[cfg(debug_assertions)]
788 return self.name;
789 #[cfg(not(debug_assertions))]
790 return "indent_level";
791 }
792}
793
794#[derive(Clone, PartialEq, Eq, Copy, Debug)]
795pub struct LineStartIndentLevel {
796 id: u32,
797 #[cfg(debug_assertions)]
799 name: &'static str,
800}
801
802impl LineStartIndentLevel {
803 pub fn new(_name: &'static str) -> Self {
804 Self {
805 id: thread_state::next_line_start_indent_level_id(),
806 #[cfg(debug_assertions)]
807 name: _name,
808 }
809 }
810
811 #[inline]
812 pub fn unique_id(&self) -> u32 {
813 self.id
814 }
815
816 #[inline]
817 pub fn name(&self) -> &'static str {
818 #[cfg(debug_assertions)]
819 return self.name;
820 #[cfg(not(debug_assertions))]
821 return "line_start_indent_level";
822 }
823}
824
825#[derive(Clone, Copy, PartialEq, Eq, Debug)]
827pub struct ConditionReevaluation {
828 pub(crate) condition_reevaluation_id: u32,
829 pub(crate) condition_id: u32,
830 #[cfg(debug_assertions)]
832 name: &'static str,
833}
834
835impl ConditionReevaluation {
836 pub(crate) fn new(_name: &'static str, condition_id: u32) -> Self {
837 ConditionReevaluation {
838 condition_reevaluation_id: thread_state::next_condition_reevaluation_id(),
839 condition_id,
840 #[cfg(debug_assertions)]
841 name: _name,
842 }
843 }
844
845 pub fn name(&self) -> &'static str {
846 #[cfg(debug_assertions)]
847 return self.name;
848 #[cfg(not(debug_assertions))]
849 return "condition_reevaluation";
850 }
851}
852
853#[derive(Clone)]
858pub struct Condition {
859 id: u32,
861 #[cfg(debug_assertions)]
863 name: &'static str,
864 pub(super) is_stored: bool,
867 pub(super) store_save_point: bool,
868 pub(super) condition: ConditionResolver,
870 pub(super) true_path: Option<PrintItemPath>,
872 pub(super) false_path: Option<PrintItemPath>,
874}
875
876impl Condition {
877 pub fn new(name: &'static str, properties: ConditionProperties) -> Self {
878 Self::new_internal(name, properties)
879 }
880
881 pub fn new_true() -> Self {
882 Self::new_internal(
883 "trueCondition",
884 ConditionProperties {
885 condition: condition_resolvers::true_resolver(),
886 true_path: None,
887 false_path: None,
888 },
889 )
890 }
891
892 pub fn new_false() -> Self {
893 Self::new_internal(
894 "falseCondition",
895 ConditionProperties {
896 condition: condition_resolvers::false_resolver(),
897 true_path: None,
898 false_path: None,
899 },
900 )
901 }
902
903 fn new_internal(_name: &'static str, properties: ConditionProperties) -> Self {
904 Self {
905 id: thread_state::next_condition_id(),
906 is_stored: false,
907 store_save_point: false,
908 #[cfg(debug_assertions)]
909 name: _name,
910 condition: properties.condition,
911 true_path: properties.true_path.and_then(|x| x.first_node),
912 false_path: properties.false_path.and_then(|x| x.first_node),
913 }
914 }
915
916 #[inline]
917 pub fn unique_id(&self) -> u32 {
918 self.id
919 }
920
921 #[inline]
922 pub fn name(&self) -> &'static str {
923 #[cfg(debug_assertions)]
924 return self.name;
925 #[cfg(not(debug_assertions))]
926 return "condition";
927 }
928
929 #[inline]
930 pub fn true_path(&self) -> &Option<PrintItemPath> {
931 &self.true_path
932 }
933
934 #[inline]
935 pub fn false_path(&self) -> &Option<PrintItemPath> {
936 &self.false_path
937 }
938
939 #[inline]
940 pub(super) fn resolve(&self, context: &mut ConditionResolverContext) -> Option<bool> {
941 (self.condition)(context)
942 }
943
944 pub fn create_reference(&mut self) -> ConditionReference {
945 self.is_stored = true;
946 ConditionReference::new(self.name(), self.id)
947 }
948
949 pub fn create_reevaluation(&mut self) -> ConditionReevaluation {
950 self.store_save_point = true;
951 self.is_stored = true;
952 ConditionReevaluation::new(self.name(), self.id)
953 }
954}
955
956#[derive(Clone, PartialEq, Eq, Copy, Debug)]
957pub struct ConditionReference {
958 #[cfg(debug_assertions)]
959 pub(super) name: &'static str,
960 pub(super) id: u32,
961}
962
963impl ConditionReference {
964 pub(super) fn new(_name: &'static str, id: u32) -> ConditionReference {
965 ConditionReference {
966 #[cfg(debug_assertions)]
967 name: _name,
968 id,
969 }
970 }
971
972 #[inline]
973 pub(super) fn name(&self) -> &'static str {
974 #[cfg(debug_assertions)]
975 return self.name;
976 #[cfg(not(debug_assertions))]
977 return "conditionRef";
978 }
979
980 pub fn create_resolver(&self) -> ConditionResolver {
982 let captured_self = *self;
983 Rc::new(move |condition_context: &mut ConditionResolverContext| condition_context.resolved_condition(&captured_self))
984 }
985}
986
987pub struct ConditionProperties {
989 pub condition: ConditionResolver,
991 pub true_path: Option<PrintItems>,
993 pub false_path: Option<PrintItems>,
995}
996
997pub type ConditionResolver = Rc<dyn Fn(&mut ConditionResolverContext) -> Option<bool>>;
999
1000pub struct ConditionResolverContext<'a, 'b> {
1002 printer: &'a mut Printer<'b>,
1003 pub writer_info: WriterInfo,
1005}
1006
1007impl<'a, 'b> ConditionResolverContext<'a, 'b> {
1008 pub(super) fn new(printer: &'a mut Printer<'b>, writer_info: WriterInfo) -> Self {
1009 ConditionResolverContext { printer, writer_info }
1010 }
1011
1012 pub fn resolved_condition(&mut self, condition_reference: &ConditionReference) -> Option<bool> {
1015 self.printer.resolved_condition(condition_reference)
1016 }
1017
1018 pub fn resolved_line_and_column(&mut self, line_and_column: LineAndColumn) -> Option<(u32, u32)> {
1020 let line = self.printer.resolved_line_number(line_and_column.line)?;
1021 let column = self.printer.resolved_column_number(line_and_column.column)?;
1022 Some((line, column))
1023 }
1024
1025 pub fn resolved_line_number(&mut self, line_number: LineNumber) -> Option<u32> {
1027 self.printer.resolved_line_number(line_number)
1028 }
1029
1030 pub fn resolved_column_number(&mut self, column_number: ColumnNumber) -> Option<u32> {
1032 self.printer.resolved_column_number(column_number)
1033 }
1034
1035 pub fn resolved_is_start_of_line(&mut self, is_start_of_line: IsStartOfLine) -> Option<bool> {
1037 self.printer.resolved_is_start_of_line(is_start_of_line)
1038 }
1039
1040 pub fn resolved_indent_level(&mut self, indent_level: IndentLevel) -> Option<u8> {
1042 self.printer.resolved_indent_level(indent_level)
1043 }
1044
1045 pub fn resolved_line_start_column_number(&mut self, line_start_column_number: LineStartColumnNumber) -> Option<u32> {
1047 self.printer.resolved_line_start_column_number(line_start_column_number)
1048 }
1049
1050 pub fn resolved_line_start_indent_level(&mut self, line_start_indent_level: LineStartIndentLevel) -> Option<u8> {
1052 self.printer.resolved_line_start_indent_level(line_start_indent_level)
1053 }
1054
1055 pub fn clear_line_and_column(&mut self, lc: LineAndColumn) {
1057 self.clear_info(lc.line);
1058 self.clear_info(lc.column);
1059 }
1060
1061 pub fn clear_info(&mut self, info: impl Into<Info>) {
1063 self.printer.clear_info(info.into())
1064 }
1065
1066 pub fn is_forcing_no_newlines(&self) -> bool {
1068 self.printer.is_forcing_no_newlines()
1069 }
1070}
1071
1072#[derive(Clone)]
1074pub struct StringContainer {
1075 pub text: UnsafePrintLifetime<str>,
1077 pub(super) char_count: u32,
1080}
1081
1082impl StringContainer {
1083 pub fn new(text: UnsafePrintLifetime<str>) -> Self {
1085 let char_count = unicode_width::UnicodeWidthStr::width(text) as u32;
1086 Self { text, char_count }
1087 }
1088
1089 pub const fn proc_macro_new_with_char_count(text: UnsafePrintLifetime<str>, char_count: u32) -> Self {
1092 Self { text, char_count }
1093 }
1094}
1095
1096#[derive(Clone, Debug)]
1098pub struct WriterInfo {
1099 pub line_number: u32,
1100 pub column_number: u32,
1101 pub indent_level: u8,
1102 pub line_start_indent_level: u8,
1103 pub indent_width: u8,
1104 pub expect_newline_next: bool,
1105}
1106
1107impl WriterInfo {
1108 pub fn is_start_of_line(&self) -> bool {
1111 self.expect_newline_next || self.is_column_number_at_line_start()
1112 }
1113
1114 pub fn is_start_of_line_indented(&self) -> bool {
1116 self.line_start_indent_level > self.indent_level
1117 }
1118
1119 pub fn is_column_number_at_line_start(&self) -> bool {
1121 self.column_number == self.line_start_column_number()
1122 }
1123
1124 pub fn line_start_column_number(&self) -> u32 {
1125 (self.line_start_indent_level as u32) * (self.indent_width as u32)
1126 }
1127
1128 pub fn line_and_column(&self) -> (u32, u32) {
1130 (self.line_number, self.column_number)
1131 }
1132}