chalk_macros/
lib.rs

1use std::cell::RefCell;
2
3#[macro_use]
4extern crate lazy_static;
5
6#[macro_use]
7mod index;
8
9lazy_static! {
10    pub static ref DEBUG_ENABLED: bool = {
11        use std::env;
12        env::var("CHALK_DEBUG")
13            .ok()
14            .and_then(|s| s.parse::<u32>().ok())
15            .map(|x| x >= 2)
16            .unwrap_or(false)
17    };
18    pub static ref INFO_ENABLED: bool = {
19        use std::env;
20        env::var("CHALK_DEBUG")
21            .ok()
22            .and_then(|s| s.parse::<u32>().ok())
23            .map(|x| x >= 1)
24            .unwrap_or(false)
25    };
26}
27
28thread_local! {
29    pub(crate) static INDENT: RefCell<Vec<String>> = RefCell::new(vec![]);
30}
31
32// When CHALK_DEBUG is enabled, we only allow this many frames of
33// nested processing, at which point we assume something has gone
34// away.
35const OVERFLOW_DEPTH: usize = 100;
36
37#[macro_export]
38macro_rules! debug {
39    ($($t:tt)*) => {
40        if *$crate::DEBUG_ENABLED {
41            $crate::dump(&format!($($t)*), "");
42        }
43    }
44}
45
46#[macro_export]
47macro_rules! debug_heading {
48    ($($t:tt)*) => {
49        let _ = &if *$crate::DEBUG_ENABLED {
50            let string = format!($($t)*);
51            $crate::dump(&string, " {");
52            $crate::Indent::new(true, string)
53        } else {
54            $crate::Indent::new(false, String::new())
55        };
56    }
57}
58
59#[macro_export]
60macro_rules! info {
61    ($($t:tt)*) => {
62        if *$crate::INFO_ENABLED {
63            $crate::dump(&format!($($t)*), "");
64        }
65    }
66}
67
68#[macro_export]
69macro_rules! info_heading {
70    ($($t:tt)*) => {
71        let _ = &if *$crate::INFO_ENABLED {
72            let string = format!($($t)*);
73            $crate::dump(&string, " {");
74            $crate::Indent::new(true, string)
75        } else {
76            $crate::Indent::new(false, String::new())
77        };
78    }
79}
80
81pub fn dump(string: &str, suffix: &str) {
82    let indent = INDENT.with(|i| i.borrow().len());
83    let mut first = true;
84    for line in string.lines() {
85        if first {
86            for _ in 0..indent {
87                eprint!(": ");
88            }
89            eprint!("| ");
90        } else {
91            eprintln!();
92            for _ in 0..indent {
93                eprint!(": ");
94            }
95            eprint!(": ");
96        }
97        eprint!("{}", line);
98        first = false;
99    }
100
101    eprintln!("{}", suffix);
102}
103
104pub struct Indent {
105    enabled: bool,
106}
107
108impl Indent {
109    pub fn new(enabled: bool, value: String) -> Self {
110        if enabled {
111            INDENT.with(|i| {
112                i.borrow_mut().push(value);
113                if i.borrow().len() > OVERFLOW_DEPTH {
114                    eprintln!("CHALK_DEBUG OVERFLOW:");
115                    for v in i.borrow().iter().rev() {
116                        eprintln!("- {}", v);
117                    }
118                    panic!("CHALK_DEBUG OVERFLOW")
119                }
120            });
121        }
122        Indent { enabled }
123    }
124}
125
126impl Drop for Indent {
127    fn drop(&mut self) {
128        if self.enabled {
129            INDENT.with(|i| i.borrow_mut().pop().unwrap());
130            dump("}", "");
131        }
132    }
133}