hojicha_core/debug/
inspector.rs1use std::fmt::Debug;
4
5pub struct Inspector {
7 enabled: bool,
8 prefix: String,
9}
10
11impl Inspector {
12 pub fn new() -> Self {
14 Self {
15 enabled: true,
16 prefix: String::from("[INSPECT]"),
17 }
18 }
19
20 pub fn with_prefix(prefix: impl Into<String>) -> Self {
22 Self {
23 enabled: true,
24 prefix: prefix.into(),
25 }
26 }
27
28 pub fn set_enabled(&mut self, enabled: bool) {
30 self.enabled = enabled;
31 }
32
33 pub fn inspect<T: Debug>(&self, label: &str, value: &T) {
35 if self.enabled {
36 eprintln!("{} {}: {:?}", self.prefix, label, value);
37 }
38 }
39
40 pub fn inspect_with<T, F>(&self, label: &str, value: &T, formatter: F)
42 where
43 F: FnOnce(&T) -> String,
44 {
45 if self.enabled {
46 eprintln!("{} {}: {}", self.prefix, label, formatter(value));
47 }
48 }
49
50 pub fn scope(&self, scope_name: &str) -> ScopedInspector {
52 ScopedInspector {
53 inspector: self,
54 scope_name: scope_name.to_string(),
55 depth: 0,
56 }
57 }
58}
59
60impl Default for Inspector {
61 fn default() -> Self {
62 Self::new()
63 }
64}
65
66pub struct ScopedInspector<'a> {
68 inspector: &'a Inspector,
69 scope_name: String,
70 depth: usize,
71}
72
73impl<'a> ScopedInspector<'a> {
74 pub fn inspect<T: Debug>(&self, label: &str, value: &T) {
76 if self.inspector.enabled {
77 let indent = " ".repeat(self.depth);
78 eprintln!(
79 "{} {}{}/{}: {:?}",
80 self.inspector.prefix, indent, self.scope_name, label, value
81 );
82 }
83 }
84
85 pub fn nested(&self, name: &str) -> ScopedInspector {
87 ScopedInspector {
88 inspector: self.inspector,
89 scope_name: format!("{}/{}", self.scope_name, name),
90 depth: self.depth + 1,
91 }
92 }
93}
94
95pub trait Inspectable: Sized {
97 fn inspect(self, label: &str) -> Self
99 where
100 Self: Debug,
101 {
102 eprintln!("[INSPECT] {}: {:?}", label, self);
103 self
104 }
105
106 fn inspect_if(self, condition: bool, label: &str) -> Self
108 where
109 Self: Debug,
110 {
111 if condition {
112 eprintln!("[INSPECT] {}: {:?}", label, self);
113 }
114 self
115 }
116
117 fn inspect_with<F>(self, label: &str, f: F) -> Self
119 where
120 F: FnOnce(&Self) -> String,
121 {
122 eprintln!("[INSPECT] {}: {}", label, f(&self));
123 self
124 }
125
126 fn tap<F>(self, f: F) -> Self
128 where
129 F: FnOnce(&Self),
130 {
131 f(&self);
132 self
133 }
134
135 fn tap_if<F>(self, condition: bool, f: F) -> Self
137 where
138 F: FnOnce(&Self),
139 {
140 if condition {
141 f(&self);
142 }
143 self
144 }
145}
146
147impl<T> Inspectable for T {}