Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  lib.rs   Sprache: unbekannt

 
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::*;

/// Reference wrapper for `TreeBuilderBase`
#[derive(Debug, Clone)]
pub struct TreeBuilder(Arc<Mutex<internal::TreeBuilderBase>>);

impl TreeBuilder {
    /// Returns a new `TreeBuilder` with an empty `Tree`.
    ///
    /// # Example
    ///
    /// ```
    /// use debug_tree::TreeBuilder;
    /// let tree = TreeBuilder::new();
    /// ```
    pub fn new() -> TreeBuilder {
        TreeBuilder {
            0: Arc::new(Mutex::new(internal::TreeBuilderBase::new())),
        }
    }

    /// Set the configuration override for displaying trees
    ///
    /// # Example
    ///
    /// ```
    /// use debug_tree::{TreeBuilder, add_branch_to, add_leaf_to, TreeSymbols, TreeConfig};
    /// let tree = TreeBuilder::new();
    /// {
    ///     add_branch_to!(tree, "1");
    ///     {
    ///         add_branch_to!(tree, "1.1");
    ///         add_leaf_to!(tree, "1.1.1");
    ///         add_leaf_to!(tree, "1.1.2");
    ///     }
    ///     add_leaf_to!(tree, "1.2");
    /// }
    /// add_leaf_to!(tree, "2");
    /// tree.set_config_override(TreeConfig::new()
    ///     .show_first_level()
    ///     .symbols(TreeSymbols::with_rounded()));
    /// tree.peek_print();
    /// assert_eq!("\
    /// ├╼ 1
    /// │ ├╼ 1.1
    /// │ │ ├╼ 1.1.1
    /// │ │ ╰╼ 1.1.2
    /// │ ╰╼ 1.2
    /// ╰╼ 2" , &tree.string());
    /// ```
    pub fn set_config_override(&self, config: TreeConfig) {
        let mut lock = self.0.lock().unwrap();
        lock.set_config_override(Some(config))
    }

    /// Remove the configuration override
    /// The default configuration will be used instead
    pub fn remove_config_override(&self) {
        self.0.lock().unwrap().set_config_override(None);
    }

    /// Update the configuration override for displaying trees
    /// If an override doesn't yet exist, it is created.
    ///
    /// # Example
    ///
    /// ```
    /// use debug_tree::{TreeBuilder, add_branch_to, add_leaf_to, TreeSymbols};
    /// let tree = TreeBuilder::new();
    /// {
    ///     add_branch_to!(tree, "1");
    ///     {
    ///         add_branch_to!(tree, "1.1");
    ///         add_leaf_to!(tree, "1.1.1");
    ///         add_leaf_to!(tree, "1.1.2");
    ///     }
    ///     add_leaf_to!(tree, "1.2");
    /// }
    /// add_leaf_to!(tree, "2");
    /// tree.update_config_override(|x|{
    ///     x.indent = 3;
    ///     x.symbols = TreeSymbols::with_rounded();
    ///     x.show_first_level = true;
    /// });
    /// tree.peek_print();
    /// assert_eq!("\
    /// ├─╼ 1
    /// │  ├─╼ 1.1
    /// │  │  ├─╼ 1.1.1
    /// │  │  ╰─╼ 1.1.2
    /// │  ╰─╼ 1.2
    /// ╰─╼ 2" , &tree.string());
    /// ```
    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));
            }
        }
    }

    /// Returns the optional configuration override.
    pub fn get_config_override(&self) -> Option<TreeConfig> {
        let lock = self.0.lock().unwrap();
        lock.config_override().clone()
    }

    /// Returns whether a configuration override is set.
    pub fn has_config_override(&self) -> bool {
        let lock = self.0.lock().unwrap();
        lock.config_override().is_some()
    }

    /// Adds a new branch with text, `text` and returns a `ScopedBranch`.
    /// When the returned `ScopedBranch` goes out of scope, (likely the end of the current block),
    /// or if its `release()` method is called, the tree will step back out of the added branch.
    ///
    /// # Arguments
    /// * `text` - A string slice to use as the newly added branch's text.
    ///
    /// # Examples
    ///
    /// Exiting branch when end of scope is reached.
    /// ```
    /// use debug_tree::TreeBuilder;
    /// let tree = TreeBuilder::new();
    /// {
    ///     let _branch = tree.add_branch("Branch"); // _branch enters scope
    ///     // tree is now pointed inside new branch.
    ///     tree.add_leaf("Child of Branch");
    ///     // _branch leaves scope, tree moves up to parent branch.
    /// }
    /// tree.add_leaf("Sibling of Branch");
    /// assert_eq!("\
    /// Branch
    /// └╼ Child of Branch
    /// Sibling of Branch" , &tree.string());
    /// ```
    ///
    /// Using `release()` before out of scope.
    /// ```
    /// use debug_tree::TreeBuilder;
    /// let tree = TreeBuilder::new();
    /// {
    ///     let mut branch = tree.add_branch("Branch"); // branch enters scope
    ///     // tree is now pointed inside new branch.
    ///     tree.add_leaf("Child of Branch");
    ///     branch.release();
    ///     tree.add_leaf("Sibling of Branch");
    ///     // branch leaves scope, but no effect because its `release()` method has already been called
    /// }
    /// assert_eq!("\
    /// Branch
    /// └╼ Child of Branch
    /// Sibling of Branch", &tree.string());
    /// ```
    pub fn add_branch(&self, text: &str) -> ScopedBranch {
        self.add_leaf(text);
        ScopedBranch::new(self.clone())
    }

    /// Adds a new branch with text, `text` and returns a `ScopedBranch`.
    /// When the returned `ScopedBranch` goes out of scope, (likely the end of the current block),
    /// or if its `release()` method is called, the tree tree will step back out of the added branch.
    ///
    /// # Arguments
    /// * `text` - A string slice to use as the newly added branch's text.
    ///
    /// # Examples
    ///
    /// Stepping out of branch when end of scope is reached.
    /// ```
    /// use debug_tree::TreeBuilder;
    /// let tree = TreeBuilder::new();
    /// {
    ///     tree.add_leaf("Branch");
    ///     let _branch = tree.enter_scoped(); // _branch enters scope
    ///     // tree is now pointed inside new branch.
    ///     tree.add_leaf("Child of Branch");
    ///     // _branch leaves scope, tree moves up to parent branch.
    /// }
    /// tree.add_leaf("Sibling of Branch");
    /// assert_eq!("\
    /// Branch
    /// └╼ Child of Branch
    /// Sibling of Branch", &tree.string());
    /// ```
    ///
    /// Using `release()` before out of scope.
    /// ```
    /// use debug_tree::TreeBuilder;
    /// let tree = TreeBuilder::new();
    /// {
    ///     tree.add_leaf("Branch");
    ///     let mut branch = tree.enter_scoped(); // branch enters scope
    ///     // tree is now pointed inside new branch.
    ///     tree.add_leaf("Child of Branch");
    ///     branch.release();
    ///     tree.add_leaf("Sibling of Branch");
    ///     // branch leaves scope, but no effect because its `release()` method has already been called
    /// }
    /// assert_eq!("\
    /// Branch
    /// └╼ Child of Branch
    /// Sibling of Branch", &tree.string());
    /// ```
    pub fn enter_scoped(&self) -> ScopedBranch {
        if self.is_enabled() {
            ScopedBranch::new(self.clone())
        } else {
            ScopedBranch::none()
        }
    }

    /// Adds a leaf to current branch with the given text, `text`.
    ///
    /// # Arguments
    /// * `text` - A string slice to use as the newly added leaf's text.
    ///
    /// # Example
    ///
    /// ```
    /// use debug_tree::TreeBuilder;
    /// let tree = TreeBuilder::new();
    /// tree.add_leaf("New leaf");
    /// ```
    pub fn add_leaf(&self, text: &str) {
        let mut x = self.0.lock().unwrap();
        if x.is_enabled() {
            x.add_leaf(&text);
        }
    }

    /// Steps into a new child branch.
    /// Stepping out of the branch requires calling `exit()`.
    ///
    /// # Example
    /// ```
    /// use debug_tree::TreeBuilder;
    /// let tree = TreeBuilder::new();
    /// tree.add_leaf("Branch");
    /// tree.enter();
    /// tree.add_leaf("Child of Branch");
    /// assert_eq!("\
    /// Branch
    /// └╼ Child of Branch", &tree.string());
    /// ```
    pub fn enter(&self) {
        let mut x = self.0.lock().unwrap();
        if x.is_enabled() {
            x.enter();
        }
    }

    /// Exits the current branch, to the parent branch.
    /// If no parent branch exists, no action is taken
    ///
    /// # Example
    ///
    /// ```
    /// use debug_tree::TreeBuilder;
    /// let tree = TreeBuilder::new();
    /// tree.add_leaf("Branch");
    /// tree.enter();
    /// tree.add_leaf("Child of Branch");
    /// tree.exit();
    /// tree.add_leaf("Sibling of Branch");
    /// assert_eq!("\
    /// Branch
    /// └╼ Child of Branch
    /// Sibling of Branch", &tree.string());
    /// ```
    pub fn exit(&self) -> bool {
        let mut x = self.0.lock().unwrap();
        if x.is_enabled() {
            x.exit()
        } else {
            false
        }
    }

    /// Returns the depth of the current branch
    /// The initial depth when no branches have been adeed is 0.
    ///
    /// # Example
    ///
    /// ```
    /// use debug_tree::TreeBuilder;
    /// let tree = TreeBuilder::new();
    /// assert_eq!(0, tree.depth());
    /// let _b = tree.add_branch("Branch");
    /// assert_eq!(1, tree.depth());
    /// let _b = tree.add_branch("Child branch");
    /// assert_eq!(2, tree.depth());
    /// ```
    pub fn depth(&self) -> usize {
        self.0.lock().unwrap().depth()
    }

    /// Prints the tree without clearing.
    ///
    /// # Example
    ///
    /// ```
    /// use debug_tree::TreeBuilder;
    /// let tree = TreeBuilder::new();
    /// tree.add_leaf("Leaf");
    /// tree.peek_print();
    /// // Leaf
    /// tree.peek_print();
    /// // Leaf
    /// // Leaf 2
    /// ```
    pub fn peek_print(&self) {
        self.0.lock().unwrap().peek_print();
    }

    /// Prints the tree and then clears it.
    ///
    /// # Example
    ///
    /// ```
    /// use debug_tree::TreeBuilder;
    /// let tree = TreeBuilder::new();
    /// tree.add_leaf("Leaf");
    /// tree.print();
    /// // Leaf
    /// tree.add_leaf("Leaf 2");
    /// tree.print();
    /// // Leaf 2
    /// ```
    pub fn print(&self) {
        self.0.lock().unwrap().print();
    }

    /// Returns the tree as a string without clearing the tree.
    ///
    /// # Example
    ///
    /// ```
    /// use debug_tree::TreeBuilder;
    /// let tree = TreeBuilder::new();
    /// tree.add_leaf("Leaf");
    /// assert_eq!("Leaf", tree.peek_string());
    /// tree.add_leaf("Leaf 2");
    /// assert_eq!("Leaf\nLeaf 2", tree.peek_string());
    /// ```
    pub fn peek_string(&self) -> String {
        self.0.lock().unwrap().peek_string()
    }

    /// Returns the tree as a string and clears the tree.
    ///
    /// # Example
    ///
    /// ```
    /// use debug_tree::TreeBuilder;
    /// let tree = TreeBuilder::new();
    /// tree.add_leaf("Leaf");
    /// assert_eq!("Leaf", tree.string());
    /// tree.add_leaf("Leaf 2");
    /// assert_eq!("Leaf 2", tree.string());
    /// ```
    pub fn string(&self) -> String {
        self.0.lock().unwrap().string()
    }

    /// Writes the tree to file without clearing.
    ///
    /// # Example
    ///
    /// ```
    /// use debug_tree::TreeBuilder;
    /// use std::fs::{read_to_string, create_dir};
    /// use std::io::Read;
    /// let tree = TreeBuilder::new();
    /// create_dir("test_out").ok();
    /// tree.add_leaf("Leaf");
    /// assert_eq!(tree.peek_string(), "Leaf");
    /// tree.peek_write("test_out/peek_write.txt");
    /// assert_eq!(read_to_string("test_out/peek_write.txt").unwrap(), "Leaf");
    /// assert_eq!(tree.peek_string(), "Leaf");
    /// ```
    pub fn peek_write(&self, path: &str) -> std::io::Result<()> {
        let mut file = File::create(path)?;
        file.write_all(self.peek_string().as_bytes())
    }

    /// Writes the tree to file without clearing.
    ///
    /// # Example
    ///
    /// ```
    /// use debug_tree::TreeBuilder;
    /// use std::io::Read;
    /// use std::fs::{read_to_string, create_dir};
    /// let tree = TreeBuilder::new();
    /// create_dir("test_out").ok();
    /// tree.add_leaf("Leaf");
    /// assert_eq!(tree.peek_string(), "Leaf");
    /// tree.write("test_out/write.txt");
    /// assert_eq!(read_to_string("test_out/write.txt").unwrap(), "Leaf");
    /// assert_eq!(tree.peek_string(), "");
    /// ```
    pub fn write(&self, path: &str) -> std::io::Result<()> {
        let mut file = File::create(path)?;
        file.write_all(self.string().as_bytes())
    }

    /// Clears the tree.
    ///
    /// # Example
    ///
    /// ```
    /// use debug_tree::TreeBuilder;
    /// let tree = TreeBuilder::new();
    /// tree.add_leaf("Leaf");
    /// assert_eq!("Leaf", tree.peek_string());
    /// tree.clear();
    /// assert_eq!("", tree.peek_string());
    /// ```
    pub fn clear(&self) {
        self.0.lock().unwrap().clear()
    }

    /// Sets the enabled state of the tree.
    ///
    /// If not enabled, the tree will not be modified by adding leaves or branches.
    /// Additionally, if called using the `add_`... macros, arguments will not be processed.
    /// This is particularly useful for suppressing output in production, with very little overhead.
    ///
    /// # Example
    /// ```
    /// #[macro_use]
    /// use debug_tree::{TreeBuilder, add_leaf_to};
    /// let mut tree = TreeBuilder::new();
    /// tree.add_leaf("Leaf 1");
    /// tree.set_enabled(false);
    /// add_leaf_to!(tree, "Leaf 2");
    /// tree.set_enabled(true);
    /// add_leaf_to!(tree, "Leaf 3");
    /// assert_eq!("Leaf 1\nLeaf 3", tree.peek_string());
    /// ```
    pub fn set_enabled(&self, enabled: bool) {
        self.0.lock().unwrap().set_enabled(enabled);
    }

    /// Returns the enabled state of the tree.
    ///
    /// # Example
    /// ```
    /// use debug_tree::TreeBuilder;
    /// let mut tree = TreeBuilder::new();
    /// assert_eq!(true, tree.is_enabled());
    /// tree.set_enabled(false);
    /// assert_eq!(false, tree.is_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())) });

/// Sets the enabled state of the tree.
///
/// # Arguments
/// * `name` - The tree name
/// * `enabled` - The enabled state
///
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)
    }
    /// Check if the named tree is enabled and exists
    /// This does not create a new tree if non-existent
    ///
    /// # Arguments
    /// * `tree_name` - The tree name
    ///
    fn is_tree_enabled(&self) -> bool {
        get_tree(self).map(|x| x.is_enabled()).unwrap_or(false)
    }
}

/// Returns the tree
/// If there is no tree then one is created and then returned.
pub fn tree<T: AsTree>(tree: T) -> TreeBuilder {
    tree.as_tree()
}

/// Returns the tree named `name`
/// If there is no tree named `name` then one is created and then returned.
pub fn is_tree_enabled<T: AsTree>(tree: &T) -> bool {
    tree.is_tree_enabled()
}

/// Calls [clear](TreeBuilder::clear) for the tree named `name`
/// If there is no tree named `name` then one is created
pub fn clear<T: AsRef<str>>(name: T) {
    name.as_tree().clear();
}

/// Returns [string](TreeBuilder::string) for the tree named `name`
/// If there is no tree named `name` then one is created
pub fn string<T: AsRef<str>>(name: T) -> String {
    name.as_tree().string()
}

/// Returns [peek_string](TreeBuilder::peek_string) for the tree named `name`
/// If there is no tree named `name` then one is created
pub fn peek_string<T: AsRef<str>>(name: T) -> String {
    name.as_tree().peek_string()
}

/// Calls [print](TreeBuilder::print) for the tree named `name`
/// If there is no tree named `name` then one is created
pub fn print<T: AsRef<str>>(name: T) {
    name.as_tree().print();
}

/// Calls [peek_print](TreeBuilder::peek_print)  for the tree named `name`
/// If there is no tree named `name` then one is created
pub fn peek_print<T: AsRef<str>>(name: T) {
    name.as_tree().peek_print();
}

/// Calls [write](TreeBuilder::write) for the tree named `name`
/// If there is no tree named `name` then one is created
pub fn write<T: AsRef<str>, P: AsRef<str>>(name: T, path: P) -> std::io::Result<()> {
    name.as_tree().write(path.as_ref())
}

/// Calls [peek_print](TreeBuilder::peek_print)  for the tree named `name`
/// If there is no tree named `name` then one is created
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())
}

/// Adds a leaf to given tree with the given text and formatting arguments
///
/// # Arguments
/// * `tree` - The tree that the leaf should be added to
/// * `text...` - Formatted text arguments, as per `format!(...)`.
///
/// # Example
///
/// ```
/// #[macro_use]
/// use debug_tree::{TreeBuilder, add_leaf_to};
/// fn main() {
///     let tree = TreeBuilder::new();
///     add_leaf_to!(tree, "A {} leaf", "new");
///     assert_eq!("A new leaf", &tree.peek_string());
/// }
/// ```
#[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)*))
    });
}

/// Adds a leaf to given tree with the given `value` argument
///
/// # Arguments
/// * `tree` - The tree that the leaf should be added to
/// * `value` - An expression that implements the `Display` trait.
///
/// # Example
///
/// ```
/// #[macro_use]
/// use debug_tree::{TreeBuilder, add_leaf_value_to};
/// fn main() {
///     let tree = TreeBuilder::new();
///     let value = add_leaf_value_to!(tree, 5 * 4 * 3 * 2);
///     assert_eq!(120, value);
///     assert_eq!("120", &tree.peek_string());
/// }
/// ```
#[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
    }};
}

/// Adds a scoped branch to given tree with the given text and formatting arguments
/// The branch will be exited at the end of the current block.
///
/// # Arguments
/// * `tree` - The tree that the leaf should be added to
/// * `text...` - Formatted text arguments, as per `format!(...)`.
///
/// # Example
///
/// ```
/// #[macro_use]
/// use debug_tree::{TreeBuilder, add_branch_to, add_leaf_to};
/// fn main() {
///     let tree = TreeBuilder::new();
///     {
///         add_branch_to!(tree, "New {}", "Branch"); // _branch enters scope
///         // tree is now pointed inside new branch.
///         add_leaf_to!(tree, "Child of {}", "Branch");
///         // Block ends, so tree exits the current branch.
///     }
///     add_leaf_to!(tree, "Sibling of {}", "Branch");
///     assert_eq!("\
/// New Branch
/// └╼ Child of Branch
/// Sibling of Branch" , &tree.string());
/// }
/// ```
#[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()
        };
    };
}

/// Calls `function` with argument, `tree`, at the end of the current scope
/// The function will only be executed if the tree is enabled when this macro is called
#[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()
            }
        };
    };
}

/// Calls [print](TreeBuilder::print) on `tree` at the end of the current scope.
/// The function will only be executed if the tree is enabled when this macro is called
#[macro_export]
macro_rules! defer_print {
    () => {
        $crate::defer!(|x| {
            x.print();
        })
    };
    ($tree:expr) => {
        $crate::defer!($tree, |x| {
            x.print();
        })
    };
}

/// Calls [peek_print](TreeBuilder::peek_print) on `tree` at the end of the current scope.
/// The function will only be executed if the tree is enabled when this macro is called
#[macro_export]
macro_rules! defer_peek_print {
    () => {
        $crate::defer!(|x| {
            x.peek_print();
        })
    };
    ($tree:expr) => {
        $crate::defer!($tree, |x| {
            x.peek_print();
        })
    };
}

/// Calls [write](TreeBuilder::write) on `tree` at the end of the current scope.
/// The function will only be executed if the tree is enabled when this macro is called
#[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);
            }
        })
    };
}

/// Calls [peek_write](TreeBuilder::peek_write) on `tree` at the end of the current scope.
/// The function will only be executed if the tree is enabled when this macro is called
#[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);
            }
        })
    };
}

[ Dauer der Verarbeitung: 0.30 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge