use std::fmt::Debug;
pub struct Inspector {
enabled: bool,
prefix: String,
}
impl Inspector {
pub fn new() -> Self {
Self {
enabled: true,
prefix: String::from("[INSPECT]"),
}
}
pub fn with_prefix(prefix: impl Into<String>) -> Self {
Self {
enabled: true,
prefix: prefix.into(),
}
}
pub fn set_enabled(&mut self, enabled: bool) {
self.enabled = enabled;
}
pub fn inspect<T: Debug>(&self, label: &str, value: &T) {
if self.enabled {
eprintln!("{} {}: {:?}", self.prefix, label, value);
}
}
pub fn inspect_with<T, F>(&self, label: &str, value: &T, formatter: F)
where
F: FnOnce(&T) -> String,
{
if self.enabled {
eprintln!("{} {}: {}", self.prefix, label, formatter(value));
}
}
pub fn scope(&self, scope_name: &str) -> ScopedInspector<'_> {
ScopedInspector {
inspector: self,
scope_name: scope_name.to_string(),
depth: 0,
}
}
}
impl Default for Inspector {
fn default() -> Self {
Self::new()
}
}
pub struct ScopedInspector<'a> {
inspector: &'a Inspector,
scope_name: String,
depth: usize,
}
impl<'a> ScopedInspector<'a> {
pub fn inspect<T: Debug>(&self, label: &str, value: &T) {
if self.inspector.enabled {
let indent = " ".repeat(self.depth);
eprintln!(
"{} {}{}/{}: {:?}",
self.inspector.prefix, indent, self.scope_name, label, value
);
}
}
pub fn nested(&self, name: &str) -> ScopedInspector<'_> {
ScopedInspector {
inspector: self.inspector,
scope_name: format!("{}/{}", self.scope_name, name),
depth: self.depth + 1,
}
}
}
pub trait Inspectable: Sized {
fn inspect(self, label: &str) -> Self
where
Self: Debug,
{
eprintln!("[INSPECT] {}: {:?}", label, self);
self
}
fn inspect_if(self, condition: bool, label: &str) -> Self
where
Self: Debug,
{
if condition {
eprintln!("[INSPECT] {}: {:?}", label, self);
}
self
}
fn inspect_with<F>(self, label: &str, f: F) -> Self
where
F: FnOnce(&Self) -> String,
{
eprintln!("[INSPECT] {}: {}", label, f(&self));
self
}
fn tap<F>(self, f: F) -> Self
where
F: FnOnce(&Self),
{
f(&self);
self
}
fn tap_if<F>(self, condition: bool, f: F) -> Self
where
F: FnOnce(&Self),
{
if condition {
f(&self);
}
self
}
}
impl<T> Inspectable for T {}