use mecha10::prelude::*;
use std::collections::HashSet;
pub fn simple_chain_example() -> Result<()> {
info!("Example 1: Simple dependency chain");
let graph = create_graph(&[
("camera", vec![]),
("vision", vec!["camera"]),
("planner", vec!["vision"]),
("controller", vec!["planner"]),
])?;
let startup = graph.topological_sort()?;
info!("Startup order: {:?}", startup);
let shutdown = graph.reverse_topological_sort()?;
info!("Shutdown order: {:?}", shutdown);
Ok(())
}
pub fn parallel_dependencies_example() -> Result<()> {
info!("Example 2: Parallel dependencies");
let graph = create_graph(&[
("camera", vec![]),
("lidar", vec![]),
("imu", vec![]),
("sensor_fusion", vec!["camera", "lidar", "imu"]),
("localization", vec!["sensor_fusion"]),
])?;
let plan = graph.startup_plan()?;
info!("Startup plan with {} levels", plan.level_count());
for (i, level) in plan.levels.iter().enumerate() {
info!(
" Level {}: {:?} ({} nodes can start in parallel)",
i,
level,
level.len()
);
}
info!("Maximum parallelism: {} nodes", plan.max_parallelism());
Ok(())
}
pub fn complex_system_example() -> Result<()> {
info!("Example 3: Complex robot system");
let graph = create_graph(&[
("camera_driver", vec![]),
("lidar_driver", vec![]),
("imu_driver", vec![]),
("motor_driver", vec![]),
("image_processor", vec!["camera_driver"]),
("point_cloud_processor", vec!["lidar_driver"]),
("odometry", vec!["imu_driver", "motor_driver"]),
("object_detector", vec!["image_processor"]),
("lane_detector", vec!["image_processor"]),
("obstacle_detector", vec!["point_cloud_processor"]),
("localization", vec!["odometry", "point_cloud_processor"]),
("path_planner", vec!["localization", "obstacle_detector"]),
("behavior_planner", vec!["object_detector", "lane_detector"]),
("motion_controller", vec!["path_planner", "behavior_planner"]),
])?;
let plan = graph.startup_plan()?;
info!("\nComplex system startup plan:");
info!("Total nodes: {}", plan.node_count());
info!("Total levels: {}", plan.level_count());
info!("Max parallelism: {}\n", plan.max_parallelism());
for (i, level) in plan.levels.iter().enumerate() {
info!("Level {}: {} nodes", i, level.len());
info!(" {:?}", level);
}
let shutdown = graph.shutdown_plan()?;
info!("\nShutdown plan (first 2 levels):");
for (i, level) in shutdown.levels.iter().take(2).enumerate() {
info!("Level {}: {:?}", i, level);
}
Ok(())
}
pub fn circular_dependency_example() -> Result<()> {
info!("Example 4: Detecting circular dependencies");
let result = create_graph(&[
("node_a", vec!["node_b"]),
("node_b", vec!["node_c"]),
("node_c", vec!["node_a"]),
]);
match result {
Ok(_) => warn!("Unexpectedly passed validation"),
Err(e) => {
info!("✓ Correctly detected circular dependency:");
info!(" {}", e);
}
}
Ok(())
}
pub fn can_start_stop_example() -> Result<()> {
info!("Example 5: Checking if nodes can start/stop");
let graph = create_graph(&[
("camera", vec![]),
("vision", vec!["camera"]),
("planner", vec!["vision"]),
])?;
let mut running = HashSet::new();
info!("\nInitial state (nothing running):");
info!(" camera can start: {}", graph.can_start("camera", &running));
info!(" vision can start: {}", graph.can_start("vision", &running));
info!(" planner can start: {}", graph.can_start("planner", &running));
running.insert("camera".to_string());
info!("\nAfter starting camera:");
info!(" vision can start: {}", graph.can_start("vision", &running));
info!(" planner can start: {}", graph.can_start("planner", &running));
running.insert("vision".to_string());
info!("\nAfter starting vision:");
info!(" planner can start: {}", graph.can_start("planner", &running));
running.insert("planner".to_string());
info!("\nAll nodes running - checking stop order:");
info!(" camera can stop: {}", graph.can_stop("camera", &running));
info!(" vision can stop: {}", graph.can_stop("vision", &running));
info!(" planner can stop: {}", graph.can_stop("planner", &running));
running.remove("planner");
info!("\nAfter stopping planner:");
info!(" vision can stop: {}", graph.can_stop("vision", &running));
info!(" camera can stop: {}", graph.can_stop("camera", &running));
Ok(())
}
pub fn transitive_dependencies_example() -> Result<()> {
info!("Example 6: Transitive dependencies");
let graph = create_graph(&[
("a", vec![]),
("b", vec!["a"]),
("c", vec!["b"]),
("d", vec!["c"]),
("e", vec!["c"]),
])?;
let deps = graph.get_all_dependencies("d");
info!("\nAll dependencies of 'd': {:?}", deps);
let dependents = graph.get_all_dependents("a");
info!("All dependents of 'a': {:?}", dependents);
let direct_deps = graph.get_direct_dependencies("d");
info!("\nDirect dependencies of 'd': {:?}", direct_deps);
let direct_dependents = graph.get_direct_dependents("a");
info!("Direct dependents of 'a': {:?}", direct_dependents);
Ok(())
}
pub fn from_node_configs_example() -> Result<()> {
info!("Example 7: Building graph from NodeConfig");
use std::collections::HashMap;
let configs = vec![
NodeConfig {
id: "camera".to_string(),
name: Some("RGB Camera".to_string()),
executable: "./camera".to_string(),
args: vec![],
env: HashMap::new(),
mode: NodeMode::Local,
auto_restart: true,
health_check_interval_s: 5,
publishes: vec!["/sensor/camera/rgb".to_string()],
subscribes: vec![],
depends_on: vec![],
},
NodeConfig {
id: "vision".to_string(),
name: Some("Vision Processing".to_string()),
executable: "./vision".to_string(),
args: vec![],
env: HashMap::new(),
mode: NodeMode::Remote,
auto_restart: true,
health_check_interval_s: 5,
publishes: vec!["/perception/detections".to_string()],
subscribes: vec!["/sensor/camera/rgb".to_string()],
depends_on: vec!["camera".to_string()],
},
NodeConfig {
id: "planner".to_string(),
name: Some("Path Planning".to_string()),
executable: "./planner".to_string(),
args: vec![],
env: HashMap::new(),
mode: NodeMode::Remote,
auto_restart: true,
health_check_interval_s: 5,
publishes: vec!["/planning/path".to_string()],
subscribes: vec!["/perception/detections".to_string()],
depends_on: vec!["vision".to_string()],
},
];
let graph = DependencyGraph::from_configs(&configs)?;
info!("\nBuilt graph from {} NodeConfig objects", configs.len());
let startup = graph.topological_sort()?;
info!("Startup order: {:?}", startup);
let plan = graph.startup_plan()?;
info!("\nStartup plan:");
for (i, level) in plan.levels.iter().enumerate() {
info!(" Level {}: {:?}", i, level);
}
Ok(())
}
pub fn warehouse_robot_example() -> Result<()> {
info!("Example 8: Warehouse robot system");
let graph = create_graph(&[
("sick_lidar", vec![]),
("realsense_camera", vec![]),
("imu_sensor", vec![]),
("odrive_motors", vec![]),
("gripper_controller", vec![]),
("lidar_processor", vec!["sick_lidar"]),
("rgb_processor", vec!["realsense_camera"]),
("depth_processor", vec!["realsense_camera"]),
("imu_filter", vec!["imu_sensor"]),
("wheel_odometry", vec!["odrive_motors", "imu_sensor"]),
("slam", vec!["lidar_processor", "wheel_odometry"]),
("object_detection", vec!["rgb_processor"]),
("shelf_detection", vec!["depth_processor"]),
("global_planner", vec!["slam"]),
("local_planner", vec!["global_planner", "object_detection"]),
("grasp_planner", vec!["shelf_detection", "object_detection"]),
("navigation_controller", vec!["local_planner"]),
("manipulation_controller", vec!["grasp_planner", "gripper_controller"]),
(
"task_coordinator",
vec!["navigation_controller", "manipulation_controller"],
),
])?;
let plan = graph.startup_plan()?;
info!("\nWarehouse robot startup plan:");
info!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
info!("Total nodes: {}", plan.node_count());
info!("Total levels: {}", plan.level_count());
info!("Max parallelism: {} nodes", plan.max_parallelism());
info!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
for (i, level) in plan.levels.iter().enumerate() {
let layer_name = match i {
0 => "Hardware",
1 => "Processing",
2 => "Perception",
3 => "Planning",
4 => "Control",
5 => "Coordination",
_ => "Advanced",
};
info!("Level {} - {} Layer ({} nodes):", i, layer_name, level.len());
for node in level {
info!(" • {}", node);
}
info!("");
}
Ok(())
}
fn main() -> Result<()> {
tracing_subscriber::fmt().with_max_level(tracing::Level::INFO).init();
println!("Dependency Ordering Usage Examples");
println!("===================================\n");
println!("Dependency ordering ensures nodes start and stop in the correct order.");
println!("Dependencies must start before dependents, and stop after them.\n");
simple_chain_example()?;
println!();
parallel_dependencies_example()?;
println!();
complex_system_example()?;
println!();
circular_dependency_example()?;
println!();
can_start_stop_example()?;
println!();
transitive_dependencies_example()?;
println!();
from_node_configs_example()?;
println!();
warehouse_robot_example()?;
println!();
println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
println!("All examples completed!");
println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
println!("Usage in your code:");
println!(" use mecha10::prelude::*;");
println!();
println!(" // Build graph from configs");
println!(" let graph = DependencyGraph::from_configs(&node_configs)?;");
println!();
println!(" // Get startup order");
println!(" let plan = graph.startup_plan()?;");
println!(" for level in &plan.levels {{");
println!(" // Start nodes in this level (can be parallel)");
println!(" for node_id in level {{");
println!(" runtime.start_node(node_id).await?;");
println!(" }}");
println!(" }}");
println!();
println!(" // Get shutdown order");
println!(" let shutdown = graph.shutdown_plan()?;");
println!(" for level in &shutdown.levels {{");
println!(" // Stop nodes in this level");
println!(" }}");
Ok(())
}