use std::collections::HashMap;
use std::sync::Arc;
use once_cell::sync::Lazy;
use parking_lot::RwLock;
use snafu::ResultExt;
use svod_device::Result as DeviceResult;
use svod_device::device::Device;
use svod_device::registry::DeviceRegistry;
use svod_dtype::DeviceSpec;
use crate::error::{DeviceSnafu, Result, UnsupportedDeviceSnafu};
pub type DeviceFactory = Arc<dyn Fn(&DeviceSpec, &DeviceRegistry) -> DeviceResult<Device> + Send + Sync>;
pub struct DeviceFactoryRegistry {
devices: RwLock<HashMap<DeviceSpec, Arc<Device>>>,
factories: RwLock<HashMap<String, DeviceFactory>>,
}
impl DeviceFactoryRegistry {
pub fn new() -> Self {
let registry = Self { devices: RwLock::new(HashMap::new()), factories: RwLock::new(HashMap::new()) };
registry
.register_factory("CPU", Arc::new(|_spec, alloc_reg| crate::devices::cpu::create_cpu_device(alloc_reg)));
registry
}
pub fn register_factory(&self, device_type: &str, factory: DeviceFactory) {
self.factories.write().insert(device_type.to_uppercase(), factory);
}
pub fn device(&self, spec: &DeviceSpec, alloc_registry: &DeviceRegistry) -> Result<Arc<Device>> {
if let Some(dev) = self.devices.read().get(spec) {
return Ok(Arc::clone(dev));
}
let mut devices = self.devices.write();
if let Some(dev) = devices.get(spec) {
return Ok(Arc::clone(dev));
}
let device_type = spec.base_type();
let factory = self
.factories
.read()
.get(device_type)
.cloned()
.ok_or_else(|| UnsupportedDeviceSnafu { device: device_type.to_string() }.build())?;
let device = factory(spec, alloc_registry).context(DeviceSnafu)?;
let arc = Arc::new(device);
devices.insert(spec.clone(), Arc::clone(&arc));
Ok(arc)
}
}
impl Default for DeviceFactoryRegistry {
fn default() -> Self {
Self::new()
}
}
pub static DEVICE_FACTORIES: Lazy<DeviceFactoryRegistry> = Lazy::new(DeviceFactoryRegistry::new);