behaviortree-core 0.1.0

Core implementaion of behaviortree
Documentation
// Copyright © 2026 Stephan Kunz
//! BehaviorState

use nanoserde::DeJson;

use crate::error::Error;

/// Behavior state.
///
/// Implementation is as in BehaviorTree.CPP to be able to
/// cooperate with Groot2.
/// IMPORTANT: Behaviors should NEVER return IDLE from a tick.
#[derive(Clone, Copy, Debug, Default, DeJson, PartialEq, Eq)]
#[repr(u8)]
pub enum BehaviorState {
	/// Behavior is not executing.
	#[default]
	Idle = 0,
	/// Behavior is still executing.
	Running = 1,
	/// Behavior finished with success.
	Success = 2,
	/// Behavior execution failed.
	Failure = 3,
	/// Behavior has been skipped.
	Skipped = 4,
}

impl BehaviorState {
	/// Check if state is signaling that the behavior is active
	#[must_use]
	pub const fn is_active(&self) -> bool {
		matches!(self, Self::Idle | Self::Skipped)
	}

	/// Check if state is signaling that the behavior is completed
	#[must_use]
	pub const fn is_completed(&self) -> bool {
		matches!(self, Self::Success | Self::Failure)
	}

	/// Provide kind as a static str reference.
	#[must_use]
	pub const fn as_str(&self) -> &'static str {
		match self {
			Self::Idle => crate::IDLE,
			Self::Running => crate::RUNNING,
			Self::Success => crate::SUCCESS,
			Self::Failure => crate::FAILURE,
			Self::Skipped => crate::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 = Error;

	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(Error::ParseError {
					value: s.into(),
					src: "BehaviorState::from_str()".into(),
				});
			}
		};
		Ok(res)
	}
}