Skip to main content

BehaviorNode

Trait BehaviorNode 

Source
pub trait BehaviorNode:
    Send
    + Sync
    + Debug {
    // Required method
    fn tick<'life0, 'life1, 'async_trait>(
        &'life0 mut self,
        ctx: &'life1 Context,
    ) -> Pin<Box<dyn Future<Output = Result<NodeStatus>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait;

    // Provided methods
    fn name(&self) -> &str { ... }
    fn children_mut(&mut self) -> Vec<&mut dyn BehaviorNode> { ... }
    fn reset_self(&mut self) { ... }
    fn reset<'life0, 'async_trait>(
        &'life0 mut self,
    ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait { ... }
    fn on_init<'life0, 'life1, 'async_trait>(
        &'life0 mut self,
        ctx: &'life1 Context,
    ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait { ... }
    fn on_terminate<'life0, 'life1, 'async_trait>(
        &'life0 mut self,
        ctx: &'life1 Context,
    ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait { ... }
}
Expand description

Core trait that all behavior nodes must implement.

This is the fundamental building block of the behavior system. Everything - from simple actions to complex AI models to composition primitives - implements this trait.

§Design Principles

  1. Simplicity - One method: tick()
  2. Async-first - All behaviors are async by default
  3. Composable - Nodes can be freely combined
  4. Type-safe - Rust’s type system ensures correctness

§Example

use mecha10_behavior_runtime::prelude::*;

#[derive(Debug)]
struct PrintMessage {
    message: String,
}

#[async_trait]
impl BehaviorNode for PrintMessage {
    async fn tick(&mut self, ctx: &Context) -> anyhow::Result<NodeStatus> {
        println!("{}", self.message);
        Ok(NodeStatus::Success)
    }

    fn name(&self) -> &str {
        "print_message"
    }
}

Required Methods§

Source

fn tick<'life0, 'life1, 'async_trait>( &'life0 mut self, ctx: &'life1 Context, ) -> Pin<Box<dyn Future<Output = Result<NodeStatus>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Execute one tick of the behavior.

This method is called repeatedly by the execution engine. It should:

  • Perform one unit of work
  • Return quickly (non-blocking)
  • Return NodeStatus to indicate progress
§Arguments
  • ctx - Execution context with access to messaging, sensors, etc.
§Returns
  • NodeStatus::Success - Behavior completed successfully
  • NodeStatus::Failure - Behavior failed (irrecoverable error)
  • NodeStatus::Running - Behavior is still executing (call again)
§Errors

Return an error for exceptional conditions that should halt execution. For recoverable failures, return Ok(NodeStatus::Failure) instead.

Provided Methods§

Source

fn name(&self) -> &str

Get the name of this behavior node.

Used for debugging, logging, and monitoring. The default implementation returns the type name.

Source

fn children_mut(&mut self) -> Vec<&mut dyn BehaviorNode>

Return mutable references to this node’s child behaviors, in the order they should receive lifecycle events.

Leaf nodes have no children and should not override this - the default implementation returns an empty list. Composite nodes (e.g. SequenceNode, SelectOrNode, ParallelNode, SubsumptionNode, EnsembleNode) override this to expose their children, which drives the default on_init/ on_terminate/reset propagation below without each composite having to hand-roll the same loop.

Source

fn reset_self(&mut self)

Reset this node’s own local state, ignoring children.

Called by the default reset() implementation before it propagates to children. Composite nodes with local progress to rewind (e.g. SequenceNode’s current child index, ParallelNode’s per-child statuses) override this instead of reset() itself, so they don’t have to hand-roll the child-propagation loop below.

Source

fn reset<'life0, 'async_trait>( &'life0 mut self, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Reset the behavior to its initial state.

Called when the behavior needs to be restarted (e.g., in a loop or after a failure). The default implementation resets local state via reset_self, then propagates the reset to every child returned by children_mut.

Source

fn on_init<'life0, 'life1, 'async_trait>( &'life0 mut self, ctx: &'life1 Context, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Called when the behavior is first initialized.

Use this for one-time setup like loading models, establishing connections, etc. The default implementation propagates on_init to every child returned by children_mut.

Source

fn on_terminate<'life0, 'life1, 'async_trait>( &'life0 mut self, ctx: &'life1 Context, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Called when the behavior is being terminated.

Use this for cleanup like closing connections, saving state, etc. The default implementation propagates on_terminate to every child returned by children_mut.

Dyn Compatibility§

This trait is dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§