taffy/util/
debug.rs

1#![allow(dead_code)]
2
3#[cfg(any(feature = "debug", feature = "profile"))]
4use core::fmt::{Debug, Display, Write};
5#[cfg(any(feature = "debug", feature = "profile"))]
6use std::sync::Mutex;
7
8#[doc(hidden)]
9#[cfg(any(feature = "debug", feature = "profile"))]
10pub struct DebugLogger {
11    stack: Mutex<Vec<String>>,
12}
13
14#[cfg(any(feature = "debug", feature = "profile"))]
15static EMPTY_STRING: String = String::new();
16#[cfg(any(feature = "debug", feature = "profile"))]
17impl DebugLogger {
18    pub const fn new() -> Self {
19        Self { stack: Mutex::new(Vec::new()) }
20    }
21
22    pub fn push_node(&self, new_key: crate::NodeId) {
23        let mut stack = self.stack.lock().unwrap();
24        let mut key_string = String::new();
25        write!(&mut key_string, "{:?}", new_key).unwrap();
26        stack.push(key_string);
27    }
28
29    pub fn pop_node(&self) {
30        let mut stack = self.stack.lock().unwrap();
31        stack.pop();
32    }
33
34    pub fn log(&self, message: impl Display) {
35        let stack = self.stack.lock().unwrap();
36        let key = stack.last().unwrap_or(&EMPTY_STRING);
37        let level = stack.len() * 4;
38        let space = " ";
39        println!("{space:level$}{key}: {message}");
40    }
41
42    pub fn labelled_log(&self, label: &str, message: impl Display) {
43        let stack = self.stack.lock().unwrap();
44        let key = stack.last().unwrap_or(&EMPTY_STRING);
45        let level = stack.len() * 4;
46        let space = " ";
47        println!("{space:level$}{key}: {label} {message}");
48    }
49
50    pub fn debug_log(&self, message: impl Debug) {
51        let stack = self.stack.lock().unwrap();
52        let key = stack.last().unwrap_or(&EMPTY_STRING);
53        let level = stack.len() * 4;
54        let space = " ";
55        println!("{space:level$}{key}: {message:?}");
56    }
57
58    pub fn labelled_debug_log(&self, label: &str, message: impl Debug) {
59        let stack = self.stack.lock().unwrap();
60        let key = stack.last().unwrap_or(&EMPTY_STRING);
61        let level = stack.len() * 4;
62        let space = " ";
63        println!("{space:level$}{key}: {label} {message:?}");
64    }
65}
66
67#[cfg(any(feature = "debug", feature = "profile"))]
68pub(crate) static NODE_LOGGER: DebugLogger = DebugLogger::new();
69
70macro_rules! debug_log {
71    // String literal label with debug printing
72    ($label:literal, dbg:$item:expr) => {{
73        #[cfg(feature = "debug")]
74        $crate::util::debug::NODE_LOGGER.labelled_debug_log($label, $item);
75    }};
76    // String literal label with display printing
77    ($label:literal, $item:expr) => {{
78        #[cfg(feature = "debug")]
79        $crate::util::debug::NODE_LOGGER.labelled_log($label, $item);
80    }};
81    // Debug printing
82    (dbg:$item:expr) => {{
83        #[cfg(feature = "debug")]
84        $crate::util::debug::NODE_LOGGER.debug_log($item);
85    }};
86    // Display printing
87    ($item:expr) => {{
88        #[cfg(feature = "debug")]
89        $crate::util::debug::NODE_LOGGER.log($item);
90    }};
91    // Blank newline
92    () => {{
93        #[cfg(feature = "debug")]
94        println!();
95    }};
96}
97
98macro_rules! debug_log_node {
99    ($known_dimensions: expr, $parent_size: expr, $available_space: expr, $run_mode: expr, $sizing_mode: expr) => {
100        debug_log!(dbg:$run_mode);
101        debug_log!("sizing_mode", dbg:$sizing_mode);
102        debug_log!("known_dimensions", dbg:$known_dimensions);
103        debug_log!("parent_size", dbg:$parent_size);
104        debug_log!("available_space", dbg:$available_space);
105    };
106}
107
108macro_rules! debug_push_node {
109    ($node_id:expr) => {
110        #[cfg(any(feature = "debug", feature = "profile"))]
111        $crate::util::debug::NODE_LOGGER.push_node($node_id);
112        debug_log!("");
113    };
114}
115
116macro_rules! debug_pop_node {
117    () => {
118        #[cfg(any(feature = "debug", feature = "profile"))]
119        $crate::util::debug::NODE_LOGGER.pop_node();
120    };
121}
122
123#[cfg(feature = "profile")]
124#[allow(unused_macros)]
125macro_rules! time {
126    ($label:expr, $($code:tt)*) => {
127        let start = ::std::time::Instant::now();
128        $($code)*
129        let duration = ::std::time::Instant::now().duration_since(start);
130        crate::util::debug::NODE_LOGGER.log(format_args!("Performed {} in {}ms", $label, duration.as_millis()));
131    };
132}
133
134#[cfg(not(feature = "profile"))]
135#[allow(unused_macros)]
136macro_rules! time {
137    ($label:expr, $($code:tt)*) => {
138        $($code)*
139    };
140}
141
142#[allow(unused_imports)]
143pub(crate) use {debug_log, debug_log_node, debug_pop_node, debug_push_node, time};