cornerstone 0.3.1

A behavior tree library
Documentation
use std::{any::Any, collections::HashMap, future::Future, str::FromStr};

use node::{
    action::ActionWrapper, composite::CompositeWrapper, decorator::DecoratorWrapper, is_ref_key,
    DataProxy,
};
use parking_lot::RwLock;
use serde::Serialize;
use serde_json::{json, Value};
use thiserror::Error;

pub mod factory;
pub mod node;
pub mod parser;

type Result<T> = std::result::Result<T, BtError>;

#[derive(Error, Debug)]
pub enum BtError {
    #[error("xml parse meet failure")]
    QuickXml(#[from] quick_xml::Error),
    #[error("xml parse meet attr failure")]
    XmlAttr(#[from] quick_xml::events::attributes::AttrError),
    #[error("str parse error")]
    Str(#[from] std::str::Utf8Error),
    #[error("raw error {0}")]
    Raw(String),
}

#[derive(Default, PartialEq, Eq, Debug, Clone, Copy)]
pub enum NodeStatus {
    #[default]
    Idle,
    Success,
    Failure,
    Running,
}

impl NodeStatus {
    pub fn is_completed(&self) -> bool {
        self == &NodeStatus::Success || self == &NodeStatus::Failure
    }
}

#[derive(PartialEq, Eq, Debug, Clone, Copy)]
pub enum NodeType {
    Composite,
    Decorator,
    Action,
}

pub enum NodeWrapper {
    Composite(CompositeWrapper),
    Decorator(DecoratorWrapper),
    Action(ActionWrapper),
}

pub struct TreeNodeWrapper {
    pub node_wrapper: NodeWrapper,
}

impl TreeNodeWrapper {
    pub fn status(&self) -> NodeStatus {
        self.data_proxy_ref().status()
    }

    pub fn reset_status(&mut self) {
        self.data_proxy_ref_mut().reset_status();
    }

    pub fn new(node_wrapper: NodeWrapper) -> Self {
        Self { node_wrapper }
    }

    pub fn node_type(&self) -> NodeType {
        match self.node_wrapper {
            NodeWrapper::Composite(_) => NodeType::Composite,
            NodeWrapper::Decorator(_) => NodeType::Decorator,
            NodeWrapper::Action(_) => NodeType::Action,
        }
    }

    pub fn data_proxy_ref(&self) -> &DataProxy {
        match &self.node_wrapper {
            NodeWrapper::Composite(cp) => &cp.data_proxy,
            NodeWrapper::Decorator(dr) => &dr.data_proxy,
            NodeWrapper::Action(at) => &at.data_proxy,
        }
    }

    pub fn data_proxy_ref_mut(&mut self) -> &mut DataProxy {
        match &mut self.node_wrapper {
            NodeWrapper::Composite(cp) => &mut cp.data_proxy,
            NodeWrapper::Decorator(dr) => &mut dr.data_proxy,
            NodeWrapper::Action(at) => &mut at.data_proxy,
        }
    }

    pub fn uid(&self) -> u16 {
        self.data_proxy_ref().uid()
    }

    pub fn set_uid(&mut self, uid: u16) {
        self.data_proxy_ref_mut().set_uid(uid);
    }

    pub fn path(&self) -> &str {
        self.data_proxy_ref().path()
    }

    pub fn node_info(&self) -> String {
        let mut info = String::new();

        self.apply_recursive_visitor(&mut |node, layer| {
            info.push_str("\n");

            for _ in 0..layer {
                info.push_str("\t");
            }

            info.push_str(&format!(
                "uid= {} path= {}",
                node.uid(),
                node.data_proxy_ref().full_path()
            ));
        });

        info
    }

    pub fn dot_info(&self) -> String {
        let mut dot_s = String::new();

        dot_s.push_str("digraph G {");

        Self::dot_info_construct(&mut dot_s, self, self);

        dot_s.push_str("}");

        dot_s
    }

    fn dot_info_construct(content: &mut String, node: &TreeNodeWrapper, parent: &TreeNodeWrapper) {
        let p = format!("\"{}_{}\"", parent.uid(), parent.path());

        let node_s = format!("\"{}_{}\"", node.uid(), node.path());

        if p != node_s {
            content.push_str(&format!("{} -> {};\n", p, node_s));
        }

        match &node.node_wrapper {
            NodeWrapper::Action(at) => {}
            NodeWrapper::Composite(cp) => {
                for child_node in &cp.child_nodes {
                    Self::dot_info_construct(content, child_node, node);
                }
            }
            NodeWrapper::Decorator(dr) => {
                Self::dot_info_construct(content, &dr.inner_node, node);
            }
        }
    }

    fn apply_recursive_visitor_impl(&self, layer: u16, visitor: &mut impl FnMut(&Self, u16)) {
        visitor(self, layer);

        match &self.node_wrapper {
            NodeWrapper::Composite(cp) => {
                for child in &cp.child_nodes {
                    child.apply_recursive_visitor_impl(layer + 1, visitor);
                }
            }
            NodeWrapper::Decorator(dn) => {
                dn.inner_node
                    .apply_recursive_visitor_impl(layer + 1, visitor);
            }
            _ => {}
        }
    }

    pub fn apply_recursive_visitor(&self, visitor: &mut impl FnMut(&Self, u16)) {
        self.apply_recursive_visitor_impl(0, visitor);
    }
}

impl TreeNode for TreeNodeWrapper {
    fn tick(&mut self) -> NodeStatus {
        let uid = self.uid();

        match &mut self.node_wrapper {
            NodeWrapper::Composite(cp) => cp.tick(),
            NodeWrapper::Decorator(dn) => dn.tick(),
            NodeWrapper::Action(tn) => {
                tracing::trace!("action tick: uid= {uid}");
                tn.tick()
            }
        }
    }

    fn halt(&mut self) {
        match &mut self.node_wrapper {
            NodeWrapper::Composite(cp) => cp.halt(),
            NodeWrapper::Decorator(dn) => dn.halt(),
            NodeWrapper::Action(tn) => {
                tn.halt();
            }
        }
    }
}

pub trait TreeNode: Any + Send {
    fn tick(&mut self) -> NodeStatus;
    fn halt(&mut self) {}
}