pub mod action;
pub mod behavior_data;
pub mod behavior_description;
pub mod condition;
pub mod control;
pub mod decorator;
pub mod error;
pub mod mock_behavior;
pub mod pre_post_conditions;
mod shared_queue;
mod simple_behavior;
mod sub_tree;
pub use error::Error as BehaviorError;
pub use mock_behavior::{MockBehavior, MockBehaviorConfig};
use nanoserde::DeJson;
pub use shared_queue::SharedQueue;
pub use simple_behavior::{ComplexBhvrTickFn, SimpleBehavior, SimpleBhvrTickFn};
pub use sub_tree::SubTree;
use crate::{
ACTION, CONDITION, CONTROL, DECORATOR, FAILURE, IDLE, RUNNING, SKIPPED, SUBTREE, SUCCESS,
behavior::{behavior_data::BehaviorData, behavior_description::BehaviorDescription, pre_post_conditions::Conditions},
factory::BehaviorRegistry,
port::PortList,
tree::BehaviorTreeElementList,
};
use alloc::{boxed::Box, string::String};
use core::any::Any;
use databoard::{Databoard, RemappingList};
use tinyscript::SharedRuntime;
pub type BehaviorPtr = Box<dyn BehaviorExecution>;
pub type BehaviorResult<Output = BehaviorState> = Result<Output, BehaviorError>;
pub type BehaviorCreationFn = dyn Fn() -> BehaviorPtr + Send + Sync;
pub type BehaviorTickCallback = dyn Fn(&BehaviorData, &mut BehaviorState) + Send + Sync;
pub(crate) struct BehaviorDataCollection<'a> {
pub behavior_name: String,
pub path: String,
pub bhvr_desc: BehaviorDescription,
pub blackboard: Databoard,
pub bhvr: Box<dyn BehaviorExecution>,
pub remappings: RemappingList,
pub conditions: Conditions,
pub uid: u16,
pub registry: &'a BehaviorRegistry,
}
pub trait BehaviorExecution: Any + Behavior {
fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
#[deprecated(since = "0.7.3", note = "use <T>::create(...)")]
fn creation_fn() -> Box<BehaviorCreationFn>
where
Self: Sized;
#[deprecated(since = "0.7.3")]
fn kind() -> BehaviorKind
where
Self: Sized;
fn static_provided_ports(&self) -> PortList;
}
#[async_trait::async_trait]
pub trait Behavior: Send + Sync {
#[inline]
fn on_halt(&mut self) -> Result<(), BehaviorError> {
Ok(())
}
#[inline]
fn on_start(
&mut self,
_behavior: &mut BehaviorData,
_children: &mut BehaviorTreeElementList,
_runtime: &SharedRuntime,
) -> Result<(), BehaviorError> {
Ok(())
}
#[inline]
async fn start(
&mut self,
behavior: &mut BehaviorData,
children: &mut BehaviorTreeElementList,
runtime: &SharedRuntime,
) -> BehaviorResult {
self.on_start(behavior, children, runtime)?;
self.tick(behavior, children, runtime).await
}
async fn tick(
&mut self,
behavior: &mut BehaviorData,
children: &mut BehaviorTreeElementList,
runtime: &SharedRuntime,
) -> BehaviorResult;
#[inline]
fn halt(
&mut self,
_behavior: &mut BehaviorData,
children: &mut BehaviorTreeElementList,
runtime: &SharedRuntime,
) -> BehaviorResult {
children.halt(runtime)?;
self.on_halt()?;
Ok(BehaviorState::Idle)
}
#[must_use]
#[inline]
fn provided_ports() -> PortList
where
Self: Sized,
{
PortList::default()
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
#[repr(u8)]
pub enum BehaviorKind {
#[default]
Action,
Condition,
Control,
Decorator,
SubTree,
}
impl core::fmt::Display for BehaviorKind {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", self.as_str())
}
}
impl BehaviorKind {
#[must_use]
pub const fn as_str(&self) -> &'static str {
match self {
Self::Action => ACTION,
Self::Condition => CONDITION,
Self::Control => CONTROL,
Self::Decorator => DECORATOR,
Self::SubTree => SUBTREE,
}
}
}
#[derive(Clone, Copy, Debug, Default, DeJson, PartialEq, Eq)]
#[repr(u8)]
pub enum BehaviorState {
#[default]
Idle = 0,
Running = 1,
Success = 2,
Failure = 3,
Skipped = 4,
}
impl BehaviorState {
#[must_use]
pub const fn is_active(&self) -> bool {
matches!(self, Self::Idle | Self::Skipped)
}
#[must_use]
pub const fn is_completed(&self) -> bool {
matches!(self, Self::Success | Self::Failure)
}
#[must_use]
pub const fn as_str(&self) -> &'static str {
match self {
Self::Idle => IDLE,
Self::Running => RUNNING,
Self::Success => SUCCESS,
Self::Failure => FAILURE,
Self::Skipped => SKIPPED,
}
}
}
impl core::fmt::Display for BehaviorState {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", self.as_str())
}
}
impl core::str::FromStr for BehaviorState {
type Err = BehaviorError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let s = s.to_ascii_lowercase();
let res = match s.as_ref() {
"idle" => Self::Idle,
"running" => Self::Running,
"success" => Self::Success,
"failure" => Self::Failure,
"skipped" => Self::Skipped,
_ => {
return Err(BehaviorError::ParseError {
value: s.into(),
src: "BehaviorState::from_str()".into(),
});
}
};
Ok(res)
}
}
#[cfg(test)]
mod tests {
use super::*;
const fn is_normal<T: Sized + Send + Sync>() {}
#[test]
const fn normal_types() {
is_normal::<error::Error>();
is_normal::<BehaviorData>();
is_normal::<BehaviorDataCollection>();
is_normal::<BehaviorDescription>();
}
}