use mecha10::prelude::*;
use serde_json::json;
use std::io::Write;
use tempfile::NamedTempFile;
pub fn basic_validation_example() -> Result<()> {
info!("Example 1: Basic project configuration validation");
let config = json!({
"name": "my-robot",
"version": "1.0.0",
"description": "Example robot project",
"author": "Mecha10 Team",
"robot_id": "robot-001",
"robot_platform": "differential-drive"
});
match validate_project_json(&config) {
Ok(_) => info!("✓ Valid configuration"),
Err(e) => error!("✗ Invalid: {}", e),
}
Ok(())
}
pub fn invalid_name_example() -> Result<()> {
info!("Example 2: Detecting invalid project names");
let config = json!({
"name": "My Robot Project",
"version": "1.0.0"
});
match validate_project_json(&config) {
Ok(_) => warn!("Unexpectedly passed validation"),
Err(e) => {
info!("✓ Correctly caught error:");
info!(" {}", e);
}
}
Ok(())
}
pub fn invalid_version_example() -> Result<()> {
info!("Example 3: Detecting version format errors");
let config = json!({
"name": "my-robot",
"version": "1.0"
});
match validate_project_json(&config) {
Ok(_) => warn!("Unexpectedly passed validation"),
Err(e) => {
info!("✓ Correctly caught error:");
info!(" {}", e);
}
}
Ok(())
}
pub fn circular_dependency_example() -> Result<()> {
info!("Example 4: Detecting circular dependencies");
let config = json!({
"name": "my-robot",
"version": "1.0.0",
"nodes": {
"drivers": [
{
"name": "camera",
"path": "./camera",
"depends_on": ["lidar"]
},
{
"name": "lidar",
"path": "./lidar",
"depends_on": ["imu"]
},
{
"name": "imu",
"path": "./imu",
"depends_on": ["camera"]
}
]
}
});
match validate_project_json(&config) {
Ok(_) => {
info!("Schema validation passed");
use mecha10::schema_validation;
if let Err(e) = schema_validation::validate_project_json(&config)
.and_then(|_| schema_validation::validate_project_json(&config))
{
info!("✓ Correctly caught circular dependency:");
info!(" {}", e);
}
}
Err(e) => {
info!("Caught during schema validation: {}", e);
}
}
Ok(())
}
pub fn undefined_run_target_example() -> Result<()> {
info!("Example 5: Detecting undefined run_target references");
let config = json!({
"name": "my-robot",
"version": "1.0.0",
"nodes": {
"drivers": [
{
"name": "camera",
"path": "./camera",
"run_target": "nonexistent"
}
]
},
"run_targets": {
"robot": {
"description": "On-robot execution",
"resources": {
"cpu_limit": "2.0",
"memory_limit": "512M"
}
},
"remote": {
"description": "Cloud execution",
"resources": {
"cpu_limit": "8.0",
"memory_limit": "16G"
}
}
}
});
info!("This configuration references 'nonexistent' run_target");
info!("Available targets: robot, remote");
Ok(())
}
pub fn duplicate_node_names_example() -> Result<()> {
info!("Example 6: Detecting duplicate node names");
let config = json!({
"name": "my-robot",
"version": "1.0.0",
"nodes": {
"drivers": [
{
"name": "camera",
"path": "./drivers/camera"
}
],
"custom": [
{
"name": "camera",
"path": "./custom/camera"
}
]
}
});
info!("This configuration has 'camera' defined in both drivers and custom");
info!("Node names must be unique across all categories");
Ok(())
}
pub fn file_validation_example() -> Result<()> {
info!("Example 7: Validating file-based configuration");
let mut temp_file = NamedTempFile::new().map_err(|e| Mecha10Error::IoError(e))?;
let config_content = json!({
"$schema": "https://mecha10.dev/schemas/project.schema.json",
"name": "test-robot",
"version": "1.0.0",
"description": "Test robot for validation",
"robot_id": "${ROBOT_ID}",
"nodes": {
"drivers": [
{
"name": "camera_fake",
"path": "./drivers/camera_fake",
"run_target": "robot",
"enabled": true
}
]
},
"run_targets": {
"robot": {
"description": "Robot",
"resources": {
"cpu_limit": "2.0",
"memory_limit": "512M"
}
}
}
});
writeln!(temp_file, "{}", serde_json::to_string_pretty(&config_content).unwrap())
.map_err(|e| Mecha10Error::IoError(e))?;
match validate_project_config(temp_file.path()) {
Ok(_) => info!("✓ File validation passed"),
Err(e) => error!("✗ File validation failed: {}", e),
}
Ok(())
}
pub fn load_and_validate_example() -> Result<()> {
info!("Example 8: Load and validate in one step");
let mut temp_file = NamedTempFile::new().map_err(|e| Mecha10Error::IoError(e))?;
let config_content = json!({
"name": "rover-robot",
"version": "1.0.0",
"description": "Autonomous delivery robot",
"robot_id": "rover-001",
"robot_platform": "differential-drive",
"nodes": {
"drivers": [
{
"name": "motor_controller",
"path": "./drivers/motor",
"run_target": "robot"
},
{
"name": "camera",
"path": "./drivers/camera",
"run_target": "robot"
}
],
"custom": [
{
"name": "navigation",
"path": "./nodes/navigation",
"run_target": "remote",
"depends_on": ["motor_controller", "camera"]
}
]
},
"run_targets": {
"robot": {
"description": "On-robot",
"resources": {
"cpu_limit": "2.0",
"memory_limit": "512M"
}
},
"remote": {
"description": "Cloud",
"resources": {
"cpu_limit": "8.0",
"memory_limit": "16G"
}
}
}
});
writeln!(temp_file, "{}", serde_json::to_string_pretty(&config_content).unwrap())
.map_err(|e| Mecha10Error::IoError(e))?;
match load_and_validate_project(temp_file.path()) {
Ok(config) => {
info!("✓ Configuration loaded and validated");
info!(" Project: {}", config["name"].as_str().unwrap_or("unknown"));
info!(" Version: {}", config["version"].as_str().unwrap_or("unknown"));
if let Some(nodes) = config.get("nodes") {
if let Some(drivers) = nodes.get("drivers").and_then(|d| d.as_array()) {
info!(" Drivers: {}", drivers.len());
}
}
}
Err(e) => error!("✗ Failed: {}", e),
}
Ok(())
}
pub fn node_config_validation_example() -> Result<()> {
info!("Example 9: Validating node configuration");
let config = json!({
"id": "camera_node",
"executable": "./target/release/camera_node",
"args": ["--fps", "30"],
"env": {
"CAMERA_DEVICE": "/dev/video0"
},
"mode": "local",
"auto_restart": true,
"health_check_interval_s": 5,
"publishes": [
"/sensor/camera/rgb",
"/sensor/camera/depth"
],
"subscribes": [],
"depends_on": []
});
match validate_node_config_json(&config) {
Ok(_) => info!("✓ Node configuration valid"),
Err(e) => error!("✗ Node configuration invalid: {}", e),
}
let invalid_config = json!({
"id": "bad_node",
"executable": "./bad_node",
"mode": "invalid_mode"
});
match validate_node_config_json(&invalid_config) {
Ok(_) => warn!("Unexpectedly passed validation"),
Err(e) => {
info!("✓ Correctly caught invalid mode:");
info!(" {}", e);
}
}
Ok(())
}
pub fn export_schema_example() -> Result<()> {
info!("Example 10: Exporting schema for IDE integration");
let temp_dir = std::env::temp_dir();
let schema_path = temp_dir.join("project.schema.json");
export_project_schema(&schema_path)?;
info!("✓ Schema exported to: {:?}", schema_path);
info!(" You can reference this in your mecha10.json:");
info!(" {{");
info!(" \"$schema\": \"file://{}\",", schema_path.display());
info!(" \"name\": \"my-robot\",");
info!(" ...");
info!(" }}");
if let Ok(schema_content) = std::fs::read_to_string(&schema_path) {
if let Ok(schema_json) = serde_json::from_str::<serde_json::Value>(&schema_content) {
info!(" Schema title: {}", schema_json["title"].as_str().unwrap_or(""));
info!(" Schema ID: {}", schema_json["$id"].as_str().unwrap_or(""));
}
}
Ok(())
}
pub fn complex_config_example() -> Result<()> {
info!("Example 11: Complex configuration with all features");
let config = json!({
"$schema": "https://mecha10.dev/schemas/project.schema.json",
"name": "warehouse-robot",
"version": "2.1.0-beta",
"description": "Autonomous warehouse navigation and picking robot",
"author": "Robotics Team",
"license": "Apache-2.0",
"robot_id": "${ROBOT_ID}",
"robot_platform": "mecanum",
"nodes": {
"drivers": [
{
"name": "lidar_sick",
"path": "./drivers/lidar_sick",
"config": "./config/lidar.yaml",
"description": "SICK LiDAR driver for 360° scanning",
"run_target": "robot",
"enabled": true,
"auto_restart": true
},
{
"name": "motor_odrive",
"path": "./drivers/motor_odrive",
"config": "./config/motors.yaml",
"description": "ODrive motor controller for mecanum drive",
"run_target": "robot",
"enabled": true,
"auto_restart": true
},
{
"name": "rgbd_camera",
"path": "./drivers/rgbd_camera",
"config": "./config/camera.yaml",
"description": "Intel RealSense D435i RGB-D camera",
"run_target": "robot",
"enabled": true
}
],
"custom": [
{
"name": "slam_node",
"path": "./nodes/slam",
"config": "./config/slam.yaml",
"description": "Real-time SLAM and mapping",
"run_target": "remote",
"enabled": true,
"depends_on": ["lidar_sick", "rgbd_camera"]
},
{
"name": "path_planner",
"path": "./nodes/planner",
"config": "./config/planner.yaml",
"description": "Global and local path planning",
"run_target": "remote",
"enabled": true,
"depends_on": ["slam_node"]
},
{
"name": "object_detector",
"path": "./nodes/detector",
"config": "./config/detector.yaml",
"description": "ML-based object detection",
"run_target": "remote",
"enabled": true,
"depends_on": ["rgbd_camera"]
}
]
},
"run_targets": {
"robot": {
"description": "On-robot execution (drivers + low-latency control)",
"includes": ["robot", "shared"],
"resources": {
"cpu_limit": "4.0",
"memory_limit": "2G",
"gpu": false,
"storage_type": "local",
"devices": ["/dev/video0", "/dev/ttyUSB0", "/dev/ttyACM0"]
}
},
"remote": {
"description": "Cloud/edge execution (compute-intensive tasks)",
"includes": ["remote", "shared"],
"resources": {
"cpu_limit": "16.0",
"memory_limit": "32G",
"gpu": {
"enabled": true,
"vendor": "nvidia",
"count": 2
},
"storage_type": "ssd",
"storage_size_gb": 500,
"model_cache": "/mnt/models"
}
},
"dev": {
"description": "Development all-in-one",
"includes": ["robot", "remote", "shared"],
"resources": {
"cpu_limit": "8.0",
"memory_limit": "16G",
"gpu": {
"enabled": false,
"optional": true
},
"storage_type": "any"
}
}
},
"behaviors": {
"default": "./config/behaviors/warehouse.xml",
"maintenance": "./config/behaviors/maintenance.xml"
},
"simulation": {
"enabled": true,
"environment": "./environments/warehouse.tscn"
},
"scripts": {
"dev": "cargo run",
"build": "cargo build --release",
"test": "cargo test --all",
"docker:build": "docker-compose build",
"docker:up": "docker-compose up -d",
"docker:down": "docker-compose down",
"deploy": "mecha10 deploy --target production"
}
});
match validate_project_json(&config) {
Ok(_) => {
info!("✓ Complex configuration validation passed");
info!(" Project: warehouse-robot");
info!(" Drivers: 3");
info!(" Custom nodes: 3");
info!(" Run targets: 3 (robot, remote, dev)");
info!(" All dependencies resolved");
info!(" No circular dependencies");
}
Err(e) => error!("✗ Validation failed: {}", e),
}
Ok(())
}
fn main() -> Result<()> {
tracing_subscriber::fmt().with_max_level(tracing::Level::INFO).init();
println!("JSON Schema Validation Usage Examples");
println!("======================================");
println!();
println!("Schema validation catches configuration errors early:");
println!("1. Invalid project names, versions, node names");
println!("2. Circular dependencies between nodes");
println!("3. Undefined run_target references");
println!("4. Duplicate node names");
println!("5. Invalid resource specifications");
println!("6. Missing required fields");
println!();
basic_validation_example()?;
println!();
invalid_name_example()?;
println!();
invalid_version_example()?;
println!();
circular_dependency_example()?;
println!();
undefined_run_target_example()?;
println!();
duplicate_node_names_example()?;
println!();
file_validation_example()?;
println!();
load_and_validate_example()?;
println!();
node_config_validation_example()?;
println!();
export_schema_example()?;
println!();
complex_config_example()?;
println!();
println!("All examples completed!");
println!();
println!("Usage in your code:");
println!(" use mecha10::prelude::*;");
println!();
println!(" // Validate project config");
println!(" validate_project_config(\"mecha10.json\")?;");
println!();
println!(" // Load and validate");
println!(" let config = load_and_validate_project(\"mecha10.json\")?;");
println!();
println!(" // Export schema for IDE");
println!(" export_project_schema(\"project.schema.json\")?;");
Ok(())
}