behaviortree-core 0.1.0

Core implementaion of behaviortree
Documentation
// Copyright © 2026 Stephan Kunz
//! [`behaviortree`](crate) groot2 dispatch function.

use alloc::string::ToString;

use bytes::{Bytes, BytesMut};
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, channel::Sender};

use crate::{
	Arc, BehaviorTreeMessage, Mutex,
	tree::{
		CHANNEL_SIZE,
		observer::groot2::{
			TRANSITION_SIZE, connector_data::Groot2ConnectorData, message::Groot2Message, protocol::Groot2RequestType,
			timestamp,
		},
	},
};

/// Common request → reply mapping shared between std and no_std.
pub async fn dispatch(
	rq_type: Groot2RequestType,
	request: &Groot2Message,
	reply: &mut Groot2Message,
	shared: &Arc<Mutex<Groot2ConnectorData>>,
	sender: &Sender<'static, CriticalSectionRawMutex, BehaviorTreeMessage, CHANNEL_SIZE>,
	xml: &Bytes,
) {
	let _ = rq_type;
	match rq_type {
		// most requests will be "State"
		Groot2RequestType::State => {
			reply.push_back(shared.lock().state_buffer.clone().into());
		}
		Groot2RequestType::FullTree => {
			shared.lock().connected = true;
			let _ = sender
				.send(BehaviorTreeMessage::AddGrootCallback(shared.clone()))
				.await;
			reply.push_back(xml.clone());
		}
		Groot2RequestType::RemoveAllHooks => {
			shared.lock().connected = false;
			let _ = sender
				.send(BehaviorTreeMessage::RemoveAllGrootHooks)
				.await;
		}
		Groot2RequestType::ToggleRecording => {
			if let Some(command) = request.get(1) {
				let cmd = command.as_ref();
				match cmd {
					b"start" => {
						// activate transition recording
						let mut shared_guard = shared.lock();
						shared_guard.recording = true;
						// clear transition buffer
						shared_guard.transitions_buffer.clear();
						// ensure that we can store at least TRANSITION_SIZE elements
						shared_guard
							.transitions_buffer
							.reserve(TRANSITION_SIZE as usize);
						drop(shared_guard);
						reply.push_back(Bytes::from(timestamp().to_string()));
					}
					b"stop" => {
						// de-activate transition recording
						shared.lock().recording = false;
					}
					_ => {
						// new/unsupported recording sub-command — silently ignore
					}
				}
			}
		}
		Groot2RequestType::GetTransitions => {
			// send transition buffer
			let mut bytes = BytesMut::with_capacity((TRANSITION_SIZE * 9) as usize);
			let mut shared_guard = shared.lock();
			for info in &shared_guard.transitions_buffer {
				bytes.extend(Bytes::from(info));
			}
			reply.push_back(Bytes::from(bytes));
			shared_guard.transitions_buffer.clear();
		}
		// not yet implemented — silently ignore so the connection stays alive
		Groot2RequestType::BlackBoard
		| Groot2RequestType::HookInsert
		| Groot2RequestType::HookRemove
		| Groot2RequestType::HooksDump
		| Groot2RequestType::DisableAllHooks
		| Groot2RequestType::BreakpointReached
		| Groot2RequestType::BreakpointUnlock
		| Groot2RequestType::Undefined => {
			#[cfg(feature = "std")]
			std::dbg!(request);
			#[cfg(not(feature = "std"))]
			let _ = request;
		}
	}
}