tawasuyu

tawasuyu/taffy

A high performance rust-powered UI layout library

HTML 231Rust 10TOML 3CSS 1348 Sutichaykuna

⎇ 2f5d0d1df229df22613a9cd7cd1bd74e3f192d47 src/util/debug.rs Rust · 129 siq'ikuna · 4.0 KB Ñawpa willay Pi imata llamkarqan ch'uya

Add `taffy_tree` feature to opt-out of default Taffy tree (#448) fda1f88ed · Martijn Arts ·

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