1 #![allow(dead_code)] 2 3 #[cfg(any(feature = "debug", feature = "profile"))] 4 use core::fmt::{Debug, Display, Write}; 5 #[cfg(any(feature = "debug", feature = "profile"))] 6 use std::sync::Mutex; 7 8 #[doc(hidden)] 9 #[cfg(any(feature = "debug", feature = "profile"))] 10 pub struct DebugLogger { 11 stack: Mutex<Vec<String>>, 12 } 13 14 #[cfg(any(feature = "debug", feature = "profile"))] 15 static EMPTY_STRING: String = String::new(); 16 #[cfg(any(feature = "debug", feature = "profile"))] 17 impl DebugLogger { new() -> Self18 pub const fn new() -> Self { 19 Self { stack: Mutex::new(Vec::new()) } 20 } 21 push_node(&self, new_key: crate::NodeId)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 pop_node(&self)29 pub fn pop_node(&self) { 30 let mut stack = self.stack.lock().unwrap(); 31 stack.pop(); 32 } 33 log(&self, message: impl Display)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 labelled_log(&self, label: &str, message: impl Display)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 debug_log(&self, message: impl Debug)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 labelled_debug_log(&self, label: &str, message: impl Debug)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"))] 68 pub(crate) static NODE_LOGGER: DebugLogger = DebugLogger::new(); 69 70 macro_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 98 macro_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 108 macro_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 116 macro_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)] 125 macro_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)] 136 macro_rules! time { 137 ($label:expr, $($code:tt)*) => { 138 $($code)* 139 }; 140 } 141 142 #[allow(unused_imports)] 143 pub(crate) use {debug_log, debug_log_node, debug_pop_node, debug_push_node, time}; 144