boxworks_knuthplass/
debug.rs1use std::{cell::RefCell, rc::Rc};
2
3use boxworks::ds;
4
5pub struct FeasibleBreakpoint {
6 pub elem_index: usize,
7 pub badness: i32,
8 pub penalty: i32,
9 pub demerits: i32,
10 pub artificial_demerits: bool,
11 pub previous_node_index: usize,
12}
13
14pub struct NewActiveNode {
15 pub node_index: usize,
16 pub line_number: usize,
17 pub fitness_class: u8,
18 pub hyphenated: bool,
19 pub total_demerits: i32,
20 pub artificial_demerits: bool,
21 pub previous_node_index: usize,
22}
23
24pub trait Logger {
25 fn log_attempt(&mut self, attempt: Attempt);
26 fn log_feasible_breakpoint(&mut self, list: &[ds::Horizontal], fb: FeasibleBreakpoint);
27 fn log_new_active_node(&mut self, an: NewActiveNode);
28 fn log_selected_node(&mut self, _node_index: usize) {}
34}
35
36pub struct TexLogger {
37 writer: Rc<RefCell<dyn std::fmt::Write>>,
38 next_elem_to_write: usize,
39}
40
41impl TexLogger {
42 pub fn new(writer: Rc<RefCell<dyn std::fmt::Write>>) -> Self {
43 Self {
44 writer,
45 next_elem_to_write: 0,
46 }
47 }
48}
49
50#[derive(Clone, Copy)]
52pub enum Attempt {
53 First,
54 Second,
55 Emergency,
56}
57
58impl Attempt {
59 pub fn number(self) -> u8 {
60 use Attempt::*;
61 match self {
62 First => 1,
63 Second => 2,
64 Emergency => 3,
65 }
66 }
67}
68
69impl std::fmt::Display for Attempt {
70 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
71 use Attempt::*;
72 let s = match self {
73 First => "firstpass",
74 Second => "secondpass",
75 Emergency => "emergencypass",
76 };
77 write!(f, "{}", s)
78 }
79}
80
81impl Logger for TexLogger {
82 fn log_attempt(&mut self, attempt: Attempt) {
83 self.next_elem_to_write = 0;
84 let _ = writeln!(self.writer.borrow_mut(), "@{}", attempt);
86 }
87 fn log_feasible_breakpoint(&mut self, list: &[ds::Horizontal], fb: FeasibleBreakpoint) {
88 if self.next_elem_to_write <= fb.elem_index {
89 let upper = if fb.elem_index >= list.len() {
90 list.len() - 1
91 } else {
92 fb.elem_index
93 };
94 _ = boxworks::ds::short_display_hlist(
95 &mut *self.writer.borrow_mut(),
96 &list[self.next_elem_to_write..=upper],
97 );
98 _ = writeln!(&mut *self.writer.borrow_mut());
99 }
100 self.next_elem_to_write = fb.elem_index + 1;
101 let b = if fb.badness > crate::INFINITE_BADNESS {
104 "*".into()
105 } else {
106 fb.badness.to_string()
107 };
108 let d = if fb.artificial_demerits {
109 "*".into()
110 } else {
111 fb.demerits.to_string()
112 };
113 _ = writeln!(
114 self.writer.borrow_mut(),
115 "@{} via @@{} b={} p={} d={}",
116 match list.get(fb.elem_index) {
117 None => r"\par",
118 Some(elem) => {
119 use ds::Horizontal::*;
120 match elem {
121 Discretionary(discretionary) => {
122 self.next_elem_to_write += discretionary.replace_count as usize;
123 r"\discretionary"
124 }
125 _ => "",
126 }
127 }
128 },
129 fb.previous_node_index,
130 b,
131 fb.penalty,
132 d,
133 );
134 }
135 fn log_new_active_node(&mut self, an: NewActiveNode) {
136 let _ = writeln!(
138 self.writer.borrow_mut(),
139 "@@{}: line {}.{}{} t={} -> @@{}",
140 an.node_index,
141 an.line_number,
142 an.fitness_class,
143 if an.hyphenated { "-" } else { "" },
144 an.total_demerits,
145 an.previous_node_index,
146 );
147 }
148}