gioser

tawasuyu/taffy

A high performance rust-powered UI layout library

Rust 709HTML 662Markdown 12TOML 62348 Sutichaykuna

⎇ 5e63f994cf121ecdad9e32f900afaeee8cabc651 src/debug.rs Rust · 131 siq'ikuna · 4.0 KB Ñawpa willay Pi imata llamkarqan ch'uya

Use `struct NodeId(u64)` instead of `slotmap::DefaultKey` in all public APIs (#426) e997fa3f4 · Nico Burns ·

1use core::fmt::{Debug, Display, Write};
2use slotmap::{DefaultKey, Key};
3use std::sync::Mutex;
4
5use crate::node::Taffy;
6use crate::style;
7use crate::tree::NodeId;
8
9/// Prints a debug representation of the computed layout for a tree of nodes, starting with the passed root node.
10pub fn print_tree(tree: &Taffy, root: NodeId) {
11    println!("TREE");
12    print_node(tree, root, false, String::new());
13}
14
15fn print_node(tree: &Taffy, node: NodeId, has_sibling: bool, lines_string: String) {
16    let key = DefaultKey::from(node);
17    let layout = &tree.nodes[key].layout;
18    let style = &tree.nodes[key].style;
19    let num_children = tree.children[key].len();
20
21    let display = match (num_children, style.display) {
22        (_, style::Display::None) => "NONE",
23        (0, _) => "LEAF",
24        #[cfg(feature = "flexbox")]
25        (_, style::Display::Flex) => "FLEX",
26        #[cfg(feature = "grid")]
27        (_, style::Display::Grid) => "GRID",
28    };
29
30    let fork_string = if has_sibling { "├── " } else { "└── " };
31    println!(
32        "{lines}{fork} {display} [x: {x:<4} y: {y:<4} width: {width:<4} height: {height:<4}] ({key:?})",
33        lines = lines_string,
34        fork = fork_string,
35        display = display,
36        x = layout.location.x,
37        y = layout.location.y,
38        width = layout.size.width,
39        height = layout.size.height,
40        key = key.data(),
41    );
42    let bar = if has_sibling { "│   " } else { "    " };
43    let new_string = lines_string + bar;
44
45    // Recurse into children
46    for (index, child) in tree.children[key].iter().enumerate() {
47        let has_sibling = index < num_children - 1;
48        print_node(tree, *child, has_sibling, new_string.clone());
49    }
50}
51
52#[doc(hidden)]
53pub struct DebugLogger {
54    stack: Mutex<Vec<String>>,
55}
56
57static EMPTY_STRING: String = String::new();
58impl DebugLogger {
59    pub const fn new() -> Self {
60        Self { stack: Mutex::new(Vec::new()) }
61    }
62
63    pub fn push_node(&self, new_key: impl Key) {
64        let mut stack = self.stack.lock().unwrap();
65        let mut key_string = String::new();
66        write!(&mut key_string, "{:?}", new_key.data()).unwrap();
67        stack.push(key_string);
68    }
69
70    pub fn pop_node(&self) {
71        let mut stack = self.stack.lock().unwrap();
72        stack.pop();
73    }
74
75    pub fn log(&self, message: impl Display) {
76        let stack = self.stack.lock().unwrap();
77        let key = stack.last().unwrap_or(&EMPTY_STRING);
78        let level = stack.len() * 4;
79        let space = " ";
80        println!("{space:level$}{key}: {message}");
81    }
82
83    pub fn labelled_log(&self, label: &str, message: impl Display) {
84        let stack = self.stack.lock().unwrap();
85        let key = stack.last().unwrap_or(&EMPTY_STRING);
86        let level = stack.len() * 4;
87        let space = " ";
88        println!("{space:level$}{key}: {label} {message}");
89    }
90
91    pub fn debug_log(&self, message: impl Debug) {
92        let stack = self.stack.lock().unwrap();
93        let key = stack.last().unwrap_or(&EMPTY_STRING);
94        let level = stack.len() * 4;
95        let space = " ";
96        println!("{space:level$}{key}: {message:?}");
97    }
98
99    pub fn labelled_debug_log(&self, label: &str, message: impl Debug) {
100        let stack = self.stack.lock().unwrap();
101        let key = stack.last().unwrap_or(&EMPTY_STRING);
102        let level = stack.len() * 4;
103        let space = " ";
104        println!("{space:level$}{key}: {label} {message:?}");
105    }
106}
107
108#[cfg(any(feature = "debug", feature = "profile"))]
109pub(crate) static NODE_LOGGER: DebugLogger = DebugLogger::new();
110
111#[cfg(feature = "profile")]
112#[allow(unused_macros)]
113macro_rules! time {
114    ($label:expr, $($code:tt)*) => {
115        let start = ::std::time::Instant::now();
116        $($code)*
117        let duration = ::std::time::Instant::now().duration_since(start);
118        crate::debug::NODE_LOGGER.log(format_args!("Performed {} in {}ms", $label, duration.as_millis()));
119    };
120}
121
122#[cfg(not(feature = "profile"))]
123#[allow(unused_macros)]
124macro_rules! time {
125    ($label:expr, $($code:tt)*) => {
126        $($code)*
127    };
128}
129
130#[allow(unused_imports)]
131pub(crate) use time;