use std::sync::{Arc, Mutex};
#[macro_use]
pub mod default;
mod internal;
pub mod scoped_branch;
pub mod defer;
mod test;
pub mod tree_config;
pub use default::default_tree;
use once_cell::sync::Lazy;
use scoped_branch::ScopedBranch;
use std::collections::BTreeMap;
use std::fs::File;
use std::io::Write;
pub use crate::tree_config::*;
#[derive(Debug, Clone)]
pub struct TreeBuilder(Arc<Mutex<internal::TreeBuilderBase>>);
impl TreeBuilder {
pub fn new() -> TreeBuilder {
TreeBuilder {
0: Arc::new(Mutex::new(internal::TreeBuilderBase::new())),
}
}
pub fn set_config_override(&self, config: TreeConfig) {
let mut lock = self.0.lock().unwrap();
lock.set_config_override(Some(config))
}
pub fn remove_config_override(&self) {
self.0.lock().unwrap().set_config_override(None);
}
pub fn update_config_override<F: Fn(&mut TreeConfig)>(&self, update: F) {
let mut lock = self.0.lock().unwrap();
match lock.config_override_mut() {
Some(x) => update(x),
None => {
let mut x = TreeConfig::default();
update(&mut x);
lock.set_config_override(Some(x));
}
}
}
pub fn get_config_override(&self) -> Option<TreeConfig> {
let lock = self.0.lock().unwrap();
lock.config_override().clone()
}
pub fn has_config_override(&self) -> bool {
let lock = self.0.lock().unwrap();
lock.config_override().is_some()
}
pub fn add_branch(&self, text: &str) -> ScopedBranch {
self.add_leaf(text);
ScopedBranch::new(self.clone())
}
pub fn enter_scoped(&self) -> ScopedBranch {
if self.is_enabled() {
ScopedBranch::new(self.clone())
} else {
ScopedBranch::none()
}
}
pub fn add_leaf(&self, text: &str) {
let mut x = self.0.lock().unwrap();
if x.is_enabled() {
x.add_leaf(&text);
}
}
pub fn enter(&self) {
let mut x = self.0.lock().unwrap();
if x.is_enabled() {
x.enter();
}
}
pub fn exit(&self) -> bool {
let mut x = self.0.lock().unwrap();
if x.is_enabled() {
x.exit()
} else {
false
}
}
pub fn depth(&self) -> usize {
self.0.lock().unwrap().depth()
}
pub fn peek_print(&self) {
self.0.lock().unwrap().peek_print();
}
pub fn print(&self) {
self.0.lock().unwrap().print();
}
pub fn peek_string(&self) -> String {
self.0.lock().unwrap().peek_string()
}
pub fn string(&self) -> String {
self.0.lock().unwrap().string()
}
pub fn peek_write(&self, path: &str) -> std::io::Result<()> {
let mut file = File::create(path)?;
file.write_all(self.peek_string().as_bytes())
}
pub fn write(&self, path: &str) -> std::io::Result<()> {
let mut file = File::create(path)?;
file.write_all(self.string().as_bytes())
}
pub fn clear(&self) {
self.0.lock().unwrap().clear()
}
pub fn set_enabled(&self, enabled: bool) {
self.0.lock().unwrap().set_enabled(enabled);
}
pub fn is_enabled(&self) -> bool {
self.0.lock().unwrap().is_enabled()
}
}
pub trait AsTree {
fn as_tree(&self) -> TreeBuilder;
fn is_tree_enabled(&self) -> bool {
self.as_tree().is_enabled()
}
}
impl AsTree for TreeBuilder {
fn as_tree(&self) -> TreeBuilder {
self.clone()
}
}
pub(crate) fn get_or_add_tree<T: AsRef<str>>(name: T) -> TreeBuilder {
let mut map = TREE_MAP.lock().unwrap();
match map.get(name.as_ref()) {
Some(x) => x.clone(),
_ => {
let val = TreeBuilder::new();
map.insert(name.as_ref().to_string(), val.clone());
val
}
}
}
pub(crate) fn get_tree<T: AsRef<str>>(name: T) -> Option<TreeBuilder> {
TREE_MAP.lock().unwrap().get(name.as_ref()).cloned()
}
type TreeMap = BTreeMap<String, TreeBuilder>;
static TREE_MAP: Lazy<Arc<Mutex<TreeMap>>> =
Lazy::new(|| -> Arc<Mutex<TreeMap>> { Arc::new(Mutex::new(TreeMap::new())) });
pub fn set_enabled<T: AsRef<str>>(name: T, enabled: bool) {
let mut map = TREE_MAP.lock().unwrap();
match map.get_mut(name.as_ref()) {
Some(x) => x.set_enabled(enabled),
_ => {
let tree = TreeBuilder::new();
tree.set_enabled(enabled);
map.insert(name.as_ref().to_string(), tree);
}
}
}
impl<T: AsRef<str>> AsTree for T {
fn as_tree(&self) -> TreeBuilder {
get_or_add_tree(self)
}
fn is_tree_enabled(&self) -> bool {
get_tree(self).map(|x| x.is_enabled()).unwrap_or(false)
}
}
pub fn tree<T: AsTree>(tree: T) -> TreeBuilder {
tree.as_tree()
}
pub fn is_tree_enabled<T: AsTree>(tree: &T) -> bool {
tree.is_tree_enabled()
}
pub fn clear<T: AsRef<str>>(name: T) {
name.as_tree().clear();
}
pub fn string<T: AsRef<str>>(name: T) -> String {
name.as_tree().string()
}
pub fn peek_string<T: AsRef<str>>(name: T) -> String {
name.as_tree().peek_string()
}
pub fn print<T: AsRef<str>>(name: T) {
name.as_tree().print();
}
pub fn peek_print<T: AsRef<str>>(name: T) {
name.as_tree().peek_print();
}
pub fn write<T: AsRef<str>, P: AsRef<str>>(name: T, path: P) -> std::io::Result<()> {
name.as_tree().write(path.as_ref())
}
pub fn peek_write<T: AsRef<str>, P: AsRef<str>>(name: T, path: P) -> std::io::Result<()> {
name.as_tree().peek_write(path.as_ref())
}
#[macro_export]
macro_rules! add_leaf_to {
($tree:expr, $($arg:tt)*) => (if $crate::is_tree_enabled(&$tree) {
use $crate::AsTree;
$tree.as_tree().add_leaf(&format!($($arg)*))
});
}
#[macro_export]
macro_rules! add_leaf_value_to {
($tree:expr, $value:expr) => {{
let v = $value;
if $crate::is_tree_enabled(&$tree) {
use $crate::AsTree;
$tree.as_tree().add_leaf(&format!("{}", &v));
}
v
}};
}
#[macro_export]
macro_rules! add_branch_to {
($tree:expr) => {
let _debug_tree_branch = if $crate::is_tree_enabled(&$tree) {
use $crate::AsTree;
$tree.as_tree().enter_scoped()
} else {
$crate::scoped_branch::ScopedBranch::none()
};
};
($tree:expr, $($arg:tt)*) => {
let _debug_tree_branch = if $crate::is_tree_enabled(&$tree) {
use $crate::AsTree;
$tree.as_tree().add_branch(&format!($($arg)*))
} else {
$crate::scoped_branch::ScopedBranch::none()
};
};
}
#[macro_export]
macro_rules! defer {
($function:expr) => {
let _debug_tree_defer = {
use $crate::AsTree;
if $crate::default::default_tree().is_enabled() {
use $crate::AsTree;
$crate::defer::DeferredFn::new($crate::default::default_tree(), $function)
} else {
$crate::defer::DeferredFn::none()
}
};
};
($tree:expr, $function:expr) => {
let _debug_tree_defer = {
use $crate::AsTree;
if $tree.as_tree().is_enabled() {
$crate::defer::DeferredFn::new($tree.as_tree(), $function)
} else {
$crate::defer::DeferredFn::none()
}
};
};
}
#[macro_export]
macro_rules! defer_print {
() => {
$crate::defer!(|x| {
x.print();
})
};
($tree:expr) => {
$crate::defer!($tree, |x| {
x.print();
})
};
}
#[macro_export]
macro_rules! defer_peek_print {
() => {
$crate::defer!(|x| {
x.peek_print();
})
};
($tree:expr) => {
$crate::defer!($tree, |x| {
x.peek_print();
})
};
}
#[macro_export]
macro_rules! defer_write {
($tree:expr, $path:expr) => {
$crate::defer!($tree, |x| {
if let Err(err) = x.write($path) {
eprintln!("error during `defer_write`: {}", err);
}
})
};
($path:expr) => {
$crate::defer!(|x| {
if let Err(err) = x.write($path) {
eprintln!("error during `defer_write`: {}", err);
}
})
};
}
#[macro_export]
macro_rules! defer_peek_write {
($tree:expr, $path:expr) => {
$crate::defer!($tree, |x| {
if let Err(err) = x.peek_write($path) {
eprintln!("error during `defer_peek_write`: {}", err);
}
})
};
($path:expr) => {
$crate::defer!(|x| {
if let Err(err) = x.peek_write($path) {
eprintln!("error during `defer_peek_write`: {}", err);
}
})
};
}