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 ($label:literal, dbg:$item:expr) => {{
73 #[cfg(feature = "debug")]
74 $crate::util::debug::NODE_LOGGER.labelled_debug_log($label, $item);
75 }};
76 ($label:literal, $item:expr) => {{
78 #[cfg(feature = "debug")]
79 $crate::util::debug::NODE_LOGGER.labelled_log($label, $item);
80 }};
81 (dbg:$item:expr) => {{
83 #[cfg(feature = "debug")]
84 $crate::util::debug::NODE_LOGGER.debug_log($item);
85 }};
86 ($item:expr) => {{
88 #[cfg(feature = "debug")]
89 $crate::util::debug::NODE_LOGGER.log($item);
90 }};
91 () => {{
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};