pub trait NodeImpl:
Send
+ Sync
+ Debug
+ 'static {
type Config: DeserializeOwned + Send + Sync + Debug;
const NODE_TYPE: Option<NodeType> = None;
const NODE_TAGS: &'static [NodeTag] = _;
// Required methods
fn init<'async_trait>(
config: Self::Config,
) -> Pin<Box<dyn Future<Output = Result<Self>> + Send + 'async_trait>>
where Self: Sized + 'async_trait;
fn run<'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;
// Provided methods
fn shutdown<'life0, 'async_trait>(
&'life0 mut self,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait { ... }
fn health_check<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = HealthStatus> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait { ... }
fn preflight(&self) -> Result<()> { ... }
}Expand description
Core trait that all Mecha10 nodes must implement.
This trait defines the lifecycle of a node:
init()- Initialize the node with configurationrun()- Main execution loopshutdown()- Graceful shutdownhealth_check()- Report health status
§Example
use mecha10_core::prelude::*;
#[derive(Debug)]
struct MyNode {
config: MyConfig,
}
#[derive(Debug, Deserialize)]
struct MyConfig {
rate: f32,
}
#[async_trait]
impl NodeImpl for MyNode {
type Config = MyConfig;
async fn init(config: Self::Config) -> Result<Self> {
info!("Initializing node with rate: {}", config.rate);
Ok(Self { config })
}
async fn run(&mut self, ctx: &Context) -> Result<()> {
let mut images = ctx.subscribe(sensor::CAMERA_RGB).await?;
while let Some(image) = images.recv().await {
// Process image
info!("Received image: {}x{}", image.width, image.height);
}
Ok(())
}
}Provided Associated Constants§
Sourceconst NODE_TYPE: Option<NodeType> = None
const NODE_TYPE: Option<NodeType> = None
Built-in node type, if this is one of the framework-provided node
kinds. None for custom/project-local nodes – NodeType is
deliberately closed (it drives 1:1 config-schema resolution in
mecha10-schema-registry), so a custom node correctly stays None
here rather than being forced to misrepresent itself as one of the
built-in variants. This matches
mecha10-schema-registry::resolve_node_type’s existing None ->
generic-schema-fallback behavior for anything unrecognized.
Sourceconst NODE_TAGS: &'static [NodeTag] = _
const NODE_TAGS: &'static [NodeTag] = _
Capability tags. Empty by default. Unlike NODE_TYPE,
custom/project-local nodes are encouraged to set this – tagging e.g.
a custom lidar node NodeTag::Sensor lets it be picked up by any
dashboard widget that requires that tag, without needing an entry in
mecha10-schema-registry at all.
Required Associated Types§
Required Methods§
Sourcefn init<'async_trait>(
config: Self::Config,
) -> Pin<Box<dyn Future<Output = Result<Self>> + Send + 'async_trait>>where
Self: Sized + 'async_trait,
fn init<'async_trait>(
config: Self::Config,
) -> Pin<Box<dyn Future<Output = Result<Self>> + Send + 'async_trait>>where
Self: Sized + 'async_trait,
Initialize the node with the given configuration.
This is called once when the node starts. Use this to:
- Load configuration
- Initialize resources (models, connections, etc.)
- Validate prerequisites
§Errors
Return an error if initialization fails. The node will not start.
Sourcefn run<'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 run<'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,
Main execution loop for the node.
This is where your node’s business logic lives. Typical patterns:
- Subscribe to topics and process messages
- Run periodic tasks
- Publish results
This method should run indefinitely until:
- The context is cancelled (shutdown requested)
- An unrecoverable error occurs
§Errors
Return an error if the node encounters an unrecoverable error. The node will transition to Error state and shutdown.
Provided Methods§
Sourcefn shutdown<'life0, 'async_trait>(
&'life0 mut self,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn shutdown<'life0, 'async_trait>(
&'life0 mut self,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Graceful shutdown hook.
Called when the node is shutting down. Use this to:
- Close connections
- Flush buffers
- Save state
- Release resources
The default implementation does nothing.
§Errors
Errors during shutdown are logged but don’t prevent shutdown.
Sourcefn health_check<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = HealthStatus> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn health_check<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = HealthStatus> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Health check for monitoring.
Called periodically to check node health. Use this to:
- Report current state
- Check resource usage
- Validate connections
The default implementation returns healthy status.
Sourcefn preflight(&self) -> Result<()>
fn preflight(&self) -> Result<()>
Node-specific pre-run content check.
This is the “prerun” layer that catches a bad node config before the
node’s main loop starts, rather than crashing deep inside run() – e.g.
a camera device path that doesn’t exist, a model file that was never
downloaded, or two GPIO pins wired to the same physical pin.
Called once, after init() has already produced a fully-typed (and, per
crate::config::Validate, schema/shape-validated) Self, and before
run() starts. Unlike Validate::validate() – which only sees the raw
deserialized config and runs during config loading – preflight() runs
on the initialized node, so it can also check state derived during
init() (e.g. a resolved file path) rather than just raw config fields.
The default implementation does nothing, so opting in is non-breaking for
every existing NodeImpl.
§Errors
Return an error with an actionable message (see node-runner’s
preflight.rs for the established convention: a ❌ header naming what
failed, followed by numbered remediation steps) if the node should not
start. The node will not run.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".