cornerstone 0.1.1

A behavior tree library
Documentation
use std::{any::Any, collections::HashMap, sync::Arc};

#[derive(Default)]
pub struct Context {
    storage: HashMap<String, Arc<dyn Any>>,
}

impl Context {
    pub fn set<T: 'static>(&mut self, key: String, val: T) {
        self.storage.insert(key, Arc::new(val));
    }

    fn get<T: 'static>(&self, key: &str) -> Option<&T> {
        self.storage.get(key).and_then(|val| val.downcast_ref())
    }
}

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

pub trait TreeNode {
    fn tick(&mut self, ctx: &mut Context) -> NodeStatus;
}

pub trait ControlNode {
    fn add_child(&mut self, node: Box<dyn TreeNode>);
}

pub trait DecoratorNode {
    fn new(node: Box<dyn TreeNode>) -> Self
    where
        Self: Sized;
}

#[derive(Debug, Clone)]
pub struct DataProxy {
    ports_mapping: HashMap<String, String>,
}

impl DataProxy {
    pub fn new(map: HashMap<String, String>) -> Self {
        Self { ports_mapping: map }
    }

    fn ports_mapping_key(&self, key: &str) -> Option<&str> {
        self.ports_mapping.get(key).map(|a| a.as_str())
    }

    pub fn get<'a, T: 'static>(&'a self, ctx: &'a Context, key: &str) -> Option<&T> {
        let key = self.ports_mapping_key(key).unwrap_or(key);

        ctx.get(key)
    }
}

#[derive(Default)]
pub struct SequenceNode {
    current_child_idx: usize,
    handle: ControlNodeHandle,
}

impl ControlNode for SequenceNode {
    fn add_child(&mut self, node: Box<dyn TreeNode>) {
        self.handle.add_child(node);
    }
}

impl TreeNode for SequenceNode {
    fn tick(&mut self, ctx: &mut Context) -> NodeStatus {
        let from = self.current_child_idx;

        for node in self.handle.child_nodes.iter_mut().skip(from) {
            match node.tick(ctx) {
                NodeStatus::Failure => {
                    return NodeStatus::Failure;
                }
                NodeStatus::Running => {
                    return NodeStatus::Running;
                }
                NodeStatus::Success => (),
            }
        }

        NodeStatus::Success
    }
}

#[derive(Default)]
pub struct ControlNodeHandle {
    child_nodes: Vec<Box<dyn TreeNode>>,
}

impl ControlNode for ControlNodeHandle {
    fn add_child(&mut self, node: Box<dyn TreeNode>) {
        self.child_nodes.push(node);
    }
}

pub struct DecoratorNodeHandle {
    node: Box<dyn TreeNode>,
}

impl DecoratorNode for DecoratorNodeHandle {
    fn new(node: Box<dyn TreeNode>) -> Self
    where
        Self: Sized,
    {
        Self { node }
    }
}

pub struct ForceSuccessNode {
    handle: DecoratorNodeHandle,
}

impl TreeNode for ForceSuccessNode {
    fn tick(&mut self, ctx: &mut Context) -> NodeStatus {
        match self.handle.node.tick(ctx) {
            NodeStatus::Running => NodeStatus::Running,
            _ => NodeStatus::Success,
        }
    }
}

impl DecoratorNode for ForceSuccessNode {
    fn new(node: Box<dyn TreeNode>) -> Self
    where
        Self: Sized,
    {
        Self {
            handle: DecoratorNodeHandle::new(node),
        }
    }
}

pub struct RepeatNode {
    count: usize,
    handle: DecoratorNodeHandle,
}

impl RepeatNode {
    pub fn new(count: usize, node: Box<dyn TreeNode>) -> Self {
        Self {
            count,
            handle: DecoratorNodeHandle::new(node)
        }
    }
}

impl TreeNode for RepeatNode {
    fn tick(&mut self, ctx: &mut Context) -> NodeStatus {
        if self.count == 0 {
            return NodeStatus::Success;
        }

        match self.handle.node.tick(ctx) {
            NodeStatus::Success => {
                self.count -= 1;
                return NodeStatus::Running;
            }
            res => return res,
        }
    }
}