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