behaviortree-core 0.1.0

Core implementaion of behaviortree
Documentation
// Copyright © 2025 Stephan Kunz
//! [`SimpleBehavior`]  implementation for registering functions as behavior.
#![allow(unused)]

use alloc::boxed::Box;
use core::any::Any;

use dataport::{PortCollection, PortCollectionAccessors, PortCollectionProvider, PortList, PortVec};
use tinyscript::SharedRuntime;

use crate::{
	Arc, Behavior, BehaviorCreationFn, BehaviorResult, behavior_data::BehaviorData, behavior_kind::BehaviorKind,
	tree::BehaviorTreeElementList,
};

/// Signature of a simple registered behavior function called by `SimpleBehavior`'s tick
pub type SimpleBhvrTickFn = Arc<Box<dyn Fn() -> BehaviorResult + Send + Sync>>;

/// Signature of a registered behavior function called by `SimpleBehavior`'s tick
pub type ComplexBhvrTickFn = Arc<Box<dyn Fn(&mut BehaviorData, &mut PortVec) -> BehaviorResult + Send + Sync>>;

/// A simple behavior
pub struct SimpleBehavior {
	/// The function to be called on tick
	simple_tick_fn: Option<SimpleBhvrTickFn>,
	/// The function to be called on tick if ports exist
	complex_tick_fn: Option<ComplexBhvrTickFn>,
	// /// List of provided ports
	// provided_ports: PortList,
	/// Kind of the behavior, either [`BehaviorKind::Action`] or [`BehaviorKind::Condition`]
	kind: BehaviorKind,
	/// To hold any portlist
	portlist: PortVec,
}

impl crate::behavior_traits::BehaviorExecution for SimpleBehavior {
	fn as_any(&self) -> &dyn Any {
		self
	}

	fn as_any_mut(&mut self) -> &mut dyn Any {
		self
	}

	fn kind(&self) -> BehaviorKind {
		self.kind
	}

	fn portlist(&self) -> &dyn PortList {
		&self.portlist
	}

	fn portlist_mut(&mut self) -> &mut dyn PortList {
		&mut self.portlist
	}
}

#[async_trait::async_trait]
impl crate::behavior_traits::Behavior for SimpleBehavior {
	async fn tick(
		&mut self,
		behavior: &mut BehaviorData,
		_children: &mut BehaviorTreeElementList,
		_runtime: &SharedRuntime,
	) -> BehaviorResult {
		self.complex_tick_fn.as_ref().map_or_else(
			|| {
				self.simple_tick_fn.as_ref().map_or_else(
					|| {
						Err(crate::error::Error::Composition {
							txt: "SimpleBehavior without tick function".into(),
						})
					},
					|func| (func.as_ref())(),
				)
			},
			|func| (func.as_ref())(behavior, &mut self.portlist),
		)
	}
}

impl PortCollectionProvider for SimpleBehavior {
	fn provided_ports(&self) -> &impl PortCollectionAccessors {
		&self.portlist
	}

	fn provided_ports_mut(&mut self) -> &mut impl PortCollectionAccessors {
		&mut self.portlist
	}

	fn port_collection(&self) -> &impl PortCollection {
		&self.portlist
	}
}

/// Implementation resembles the macro generated impl code
impl SimpleBehavior {
	/// Create a `SimpleBehavior` with the given function
	pub fn create(tick_fn: SimpleBhvrTickFn, kind: BehaviorKind) -> Box<BehaviorCreationFn> {
		Box::new(move |_blackboard| {
			Box::new(Self {
				simple_tick_fn: Some(tick_fn.clone()),
				complex_tick_fn: None,
				kind,
				portlist: PortVec::default(),
			})
		})
	}

	/// Create a `SimpleBehavior` with the given function and list of ports
	pub fn create_with_ports(tick_fn: ComplexBhvrTickFn, kind: BehaviorKind, portlist: PortVec) -> Box<BehaviorCreationFn> {
		Box::new(move |_blackboard| {
			Box::new(Self {
				simple_tick_fn: None,
				complex_tick_fn: Some(tick_fn.clone()),
				kind,
				portlist: portlist.clone(),
			})
		})
	}
}

#[cfg(test)]
mod tests {
	use super::*;
	use crate::Mutex;
	use tinyscript::Runtime;

	#[tokio::test]
	async fn tick_without_any_fn_errors() {
		let mut behavior = SimpleBehavior {
			simple_tick_fn: None,
			complex_tick_fn: None,
			kind: BehaviorKind::Action,
			portlist: PortVec::default(),
		};
		let mut data = BehaviorData::default();
		let mut children = BehaviorTreeElementList::default();
		let runtime: SharedRuntime = Arc::new(Mutex::new(Runtime::default()));
		let result = behavior
			.tick(&mut data, &mut children, &runtime)
			.await;
		assert!(result.is_err());
	}
}