use canlink_hal::{BackendConfig, BackendRegistry, CanBackend, CanMessage};
use canlink_mock::{MockBackendFactory, MockConfig};
use std::sync::Arc;
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("=== CANLink HAL - Backend Switching Example ===\n");
println!("1. Getting global backend registry...");
let registry = BackendRegistry::global();
println!(" ✓ Registry obtained\n");
println!("2. Registering Mock backend...");
let mock_factory = Arc::new(MockBackendFactory::new());
registry.register(mock_factory)?;
println!(" ✓ Mock backend registered\n");
println!("3. Registering Mock CAN 2.0 backend...");
let _mock_can20_factory = Arc::new(MockBackendFactory::with_config(MockConfig::can20_only()));
println!(" ℹ Skipping (same name as first backend)\n");
println!("4. Listing available backends...");
let backends = registry.list_backends();
println!(" ✓ Available backends: {:?}", backends);
println!(" ✓ Total: {} backend(s)\n", backends.len());
println!("5. Querying backend information...");
for backend_name in &backends {
let info = registry.get_backend_info(backend_name)?;
println!(" ✓ Backend: {}", info.name);
println!(" - Version: {}", info.version);
}
println!();
println!("6. Creating backend from registry...");
let config = BackendConfig::new("mock");
let mut backend = registry.create("mock", &config)?;
println!(" ✓ Backend created: {}", backend.name());
println!(" ✓ Version: {}\n", backend.version());
println!("7. Using the backend...");
use_backend(&mut *backend)?;
println!();
println!("8. Demonstrating backend switching...");
println!(" ℹ In a real application, you would:");
println!(" - Load backend name from config file (canlink.toml)");
println!(" - Create backend using registry.create(name, config)");
println!(" - Application code remains unchanged");
println!();
println!("9. Simulating backend switch...");
backend.close()?;
println!(" ✓ Closed first backend");
let mut backend2 = registry.create("mock", &config)?;
println!(" ✓ Created second backend: {}", backend2.name());
use_backend(&mut *backend2)?;
backend2.close()?;
println!(" ✓ Closed second backend\n");
println!("10. Checking backend registration...");
if registry.is_registered("mock") {
println!(" ✓ 'mock' backend is registered");
}
if !registry.is_registered("nonexistent") {
println!(" ✓ 'nonexistent' backend is not registered");
}
println!();
println!("=== Example completed successfully! ===");
println!("\nKey Takeaways:");
println!("- Application code is independent of backend implementation");
println!("- Backends can be switched by changing configuration");
println!("- Registry provides runtime backend discovery");
println!("- Same CanBackend trait works for all hardware types");
Ok(())
}
fn use_backend(backend: &mut dyn CanBackend) -> Result<(), Box<dyn std::error::Error>> {
let config = BackendConfig::new(backend.name());
backend.initialize(&config)?;
println!(" ✓ Initialized backend: {}", backend.name());
let capability = backend.get_capability()?;
println!(
" ✓ Capabilities: {} channels, CAN-FD: {}",
capability.channel_count, capability.supports_canfd
);
backend.open_channel(0)?;
println!(" ✓ Opened channel 0");
let msg = CanMessage::new_standard(0x123, &[0x01, 0x02, 0x03, 0x04])?;
backend.send_message(&msg)?;
println!(" ✓ Sent message: ID={:?}", msg.id());
if let Some(received) = backend.receive_message()? {
println!(" ✓ Received message: ID={:?}", received.id());
} else {
println!(" ℹ No messages available to receive");
}
backend.close_channel(0)?;
println!(" ✓ Closed channel 0");
Ok(())
}