use mecha10::prelude::*;
pub async fn basic_example() -> Result<()> {
info!("Example 1: Basic registration and querying");
let registry = TopicRegistry::new();
registry
.register_publisher("/sensor/camera/rgb", "camera_node", "Image")
.await;
registry
.register_publisher("/sensor/lidar/scan", "lidar_node", "LaserScan")
.await;
registry
.register_subscriber("/sensor/camera/rgb", "vision_node", "Image")
.await;
registry
.register_subscriber("/sensor/camera/rgb", "recorder_node", "Image")
.await;
registry
.register_subscriber("/sensor/lidar/scan", "slam_node", "LaserScan")
.await;
if let Some(info) = registry.get_topic("/sensor/camera/rgb").await {
info!("\nTopic: {}", info.topic);
info!(" Message type: {}", info.message_type);
info!(" Publishers: {:?}", info.publishers);
info!(" Subscribers: {:?}", info.subscribers);
info!(" Publisher count: {}", info.publisher_count());
info!(" Subscriber count: {}", info.subscriber_count());
}
info!("\nAll registered topics:");
for topic in registry.list_topics().await {
info!(" - {}", topic);
}
Ok(())
}
pub async fn validation_example() -> Result<()> {
info!("Example 2: Topology validation");
let registry = TopicRegistry::new();
registry
.register_publisher("/sensor/camera", "camera_node", "Image")
.await;
registry
.register_subscriber("/sensor/camera", "vision_node", "Image")
.await;
registry
.register_publisher("/debug/raw_data", "debug_node", "RawData")
.await;
registry
.register_subscriber("/config/updates", "config_node", "Config")
.await;
info!("\nValidating topology...");
let issues = registry.validate().await;
if issues.is_empty() {
info!("✓ No topology issues found");
} else {
warn!("Found {} issues:", issues.len());
for issue in issues {
warn!(" • {}", issue);
}
}
Ok(())
}
pub async fn find_by_type_example() -> Result<()> {
info!("Example 3: Finding topics by message type");
let registry = TopicRegistry::new();
registry
.register_publisher("/sensor/camera/rgb", "camera1", "Image")
.await;
registry
.register_publisher("/sensor/camera/depth", "camera1", "Image")
.await;
registry
.register_publisher("/sensor/camera2/rgb", "camera2", "Image")
.await;
registry
.register_publisher("/sensor/lidar/scan", "lidar", "LaserScan")
.await;
registry.register_publisher("/sensor/imu", "imu", "IMU").await;
info!("\nFinding all 'Image' topics:");
let image_topics = registry.find_by_message_type("Image").await;
for topic in image_topics {
info!(" - {} (publishers: {:?})", topic.topic, topic.publishers);
}
info!("\nFinding all 'LaserScan' topics:");
let laser_topics = registry.find_by_message_type("LaserScan").await;
for topic in laser_topics {
info!(" - {} (publishers: {:?})", topic.topic, topic.publishers);
}
Ok(())
}
pub async fn node_queries_example() -> Result<()> {
info!("Example 4: Node-centric queries");
let registry = TopicRegistry::new();
registry
.register_publisher("/sensor/camera/rgb", "perception_node", "Image")
.await;
registry
.register_publisher("/perception/detections", "perception_node", "Detections")
.await;
registry
.register_subscriber("/sensor/lidar/scan", "perception_node", "LaserScan")
.await;
registry
.register_subscriber("/sensor/imu", "perception_node", "IMU")
.await;
info!("\nTopics published by 'perception_node':");
for topic in registry.topics_published_by("perception_node").await {
info!(" - {}", topic);
}
info!("\nTopics subscribed by 'perception_node':");
for topic in registry.topics_subscribed_by("perception_node").await {
info!(" - {}", topic);
}
Ok(())
}
pub async fn lifecycle_example() -> Result<()> {
info!("Example 5: Node lifecycle handling");
let registry = TopicRegistry::new();
info!("\nNode 'sensor_fusion' starting...");
registry
.register_publisher("/fusion/pose", "sensor_fusion", "Pose")
.await;
registry
.register_subscriber("/sensor/camera/rgb", "sensor_fusion", "Image")
.await;
registry
.register_subscriber("/sensor/lidar/scan", "sensor_fusion", "LaserScan")
.await;
registry
.register_subscriber("/sensor/imu", "sensor_fusion", "IMU")
.await;
info!("Topics after node start:");
info!(" Total topics: {}", registry.topic_count().await);
info!("\nNode 'sensor_fusion' stopping...");
registry.unregister_node("sensor_fusion").await;
info!("Topics after node stop:");
info!(" Total topics: {}", registry.topic_count().await);
Ok(())
}
pub async fn statistics_example() -> Result<()> {
info!("Example 6: Topology statistics");
let registry = TopicRegistry::new();
registry
.register_publisher("/sensor/camera/rgb", "camera", "Image")
.await;
registry
.register_subscriber("/sensor/camera/rgb", "vision", "Image")
.await;
registry
.register_subscriber("/sensor/camera/rgb", "recorder", "Image")
.await;
registry
.register_publisher("/sensor/lidar/scan", "lidar", "LaserScan")
.await;
registry
.register_subscriber("/sensor/lidar/scan", "slam", "LaserScan")
.await;
registry
.register_publisher("/perception/detections", "vision", "Detections")
.await;
registry
.register_subscriber("/perception/detections", "planner", "Detections")
.await;
registry.register_publisher("/planning/path", "planner", "Path").await;
registry
.register_subscriber("/planning/path", "controller", "Path")
.await;
registry.register_publisher("/debug/markers", "debug", "Markers").await;
let stats = registry.stats().await;
info!("\nTopology Statistics:");
info!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
info!("Total topics: {}", stats.total_topics);
info!("Total publisher connections: {}", stats.total_publishers);
info!("Total subscriber connections: {}", stats.total_subscribers);
info!("Orphaned topics: {}", stats.orphaned_topics);
info!("Topics without publishers: {}", stats.topics_without_publishers);
info!("Topics without subscribers: {}", stats.topics_without_subscribers);
info!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
Ok(())
}
pub async fn export_dot_example() -> Result<()> {
info!("Example 7: Export topology visualization");
let registry = TopicRegistry::new();
registry
.register_publisher("/sensor/camera", "camera_node", "Image")
.await;
registry
.register_publisher("/sensor/lidar", "lidar_node", "LaserScan")
.await;
registry
.register_subscriber("/sensor/camera", "vision_node", "Image")
.await;
registry
.register_subscriber("/sensor/lidar", "slam_node", "LaserScan")
.await;
registry
.register_publisher("/perception/detections", "vision_node", "Detections")
.await;
registry.register_publisher("/slam/pose", "slam_node", "Pose").await;
registry
.register_subscriber("/perception/detections", "planner_node", "Detections")
.await;
registry.register_subscriber("/slam/pose", "planner_node", "Pose").await;
registry
.register_publisher("/planning/path", "planner_node", "Path")
.await;
registry
.register_subscriber("/planning/path", "controller_node", "Path")
.await;
let dot = registry.export_dot().await;
info!("\nGenerated DOT graph:");
info!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
info!("{}", dot);
info!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
info!("\nTo visualize:");
info!(" Save to file: topology.dot");
info!(" Generate PNG: dot -Tpng topology.dot -o topology.png");
info!(" Or use online: https://dreampuf.github.io/GraphvizOnline/");
Ok(())
}
pub async fn complex_system_example() -> Result<()> {
info!("Example 8: Complex robot system topology");
let registry = TopicRegistry::new();
registry
.register_publisher("/sensor/camera/rgb", "camera_driver", "Image")
.await;
registry
.register_publisher("/sensor/camera/depth", "camera_driver", "Image")
.await;
registry
.register_publisher("/sensor/lidar/scan", "lidar_driver", "LaserScan")
.await;
registry.register_publisher("/sensor/imu", "imu_driver", "IMU").await;
registry
.register_publisher("/sensor/odometry", "motor_driver", "Odometry")
.await;
registry
.register_subscriber("/sensor/camera/rgb", "image_processor", "Image")
.await;
registry
.register_publisher("/processed/image", "image_processor", "ProcessedImage")
.await;
registry
.register_subscriber("/sensor/lidar/scan", "cloud_processor", "LaserScan")
.await;
registry
.register_publisher("/processed/cloud", "cloud_processor", "PointCloud")
.await;
registry
.register_subscriber("/processed/image", "object_detector", "ProcessedImage")
.await;
registry
.register_publisher("/perception/objects", "object_detector", "Objects")
.await;
registry
.register_subscriber("/processed/cloud", "obstacle_detector", "PointCloud")
.await;
registry
.register_publisher("/perception/obstacles", "obstacle_detector", "Obstacles")
.await;
registry
.register_subscriber("/sensor/lidar/scan", "slam_node", "LaserScan")
.await;
registry
.register_subscriber("/sensor/odometry", "slam_node", "Odometry")
.await;
registry.register_publisher("/slam/pose", "slam_node", "Pose").await;
registry.register_publisher("/slam/map", "slam_node", "Map").await;
registry.register_subscriber("/slam/pose", "planner", "Pose").await;
registry.register_subscriber("/slam/map", "planner", "Map").await;
registry
.register_subscriber("/perception/obstacles", "planner", "Obstacles")
.await;
registry.register_publisher("/planning/path", "planner", "Path").await;
registry
.register_subscriber("/planning/path", "controller", "Path")
.await;
registry
.register_subscriber("/sensor/odometry", "controller", "Odometry")
.await;
registry
.register_publisher("/actuator/cmd_vel", "controller", "Twist")
.await;
info!("\nComplex System Topology:");
info!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
let topics = registry.get_all_topics().await;
for topic_info in topics {
info!("\n{} ({})", topic_info.topic, topic_info.message_type);
info!(" Publishers ({}):", topic_info.publishers.len());
for pub_node in &topic_info.publishers {
info!(" • {}", pub_node);
}
info!(" Subscribers ({}):", topic_info.subscribers.len());
for sub_node in &topic_info.subscribers {
info!(" • {}", sub_node);
}
}
info!("\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
let stats = registry.stats().await;
info!("\nSystem Statistics:");
info!(" Topics: {}", stats.total_topics);
info!(" Publisher connections: {}", stats.total_publishers);
info!(" Subscriber connections: {}", stats.total_subscribers);
info!(" Nodes involved: {}", count_unique_nodes(®istry).await);
Ok(())
}
async fn count_unique_nodes(registry: &TopicRegistry) -> usize {
use std::collections::HashSet;
let mut nodes = HashSet::new();
let topics = registry.get_all_topics().await;
for topic in topics {
nodes.extend(topic.publishers.into_iter());
nodes.extend(topic.subscribers.into_iter());
}
nodes.len()
}
fn main() -> Result<()> {
tracing_subscriber::fmt().with_max_level(tracing::Level::INFO).init();
println!("Topic Registry Usage Examples");
println!("==============================\n");
println!("The Topic Registry provides runtime introspection and validation");
println!("of the pub/sub topology, enabling debugging and monitoring.\n");
let runtime = tokio::runtime::Runtime::new().unwrap();
runtime.block_on(async {
basic_example().await?;
println!();
validation_example().await?;
println!();
find_by_type_example().await?;
println!();
node_queries_example().await?;
println!();
lifecycle_example().await?;
println!();
statistics_example().await?;
println!();
export_dot_example().await?;
println!();
complex_system_example().await?;
println!();
Ok::<(), Mecha10Error>(())
})?;
println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
println!("All examples completed!");
println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
println!("Usage in your code:");
println!(" use mecha10::prelude::*;");
println!();
println!(" // Create global registry");
println!(" let registry = TopicRegistry::new();");
println!();
println!(" // Register when nodes start");
println!(" registry.register_publisher(topic, node_id, type_name).await;");
println!(" registry.register_subscriber(topic, node_id, type_name).await;");
println!();
println!(" // Query topology");
println!(" let info = registry.get_topic(topic).await;");
println!(" let topics = registry.list_topics().await;");
println!();
println!(" // Validate");
println!(" let issues = registry.validate().await;");
println!();
println!(" // Clean up when nodes stop");
println!(" registry.unregister_node(node_id).await;");
Ok(())
}