1use std::collections::HashMap;
2use std::sync::Arc;
3
4use async_trait::async_trait;
5use parking_lot::RwLock;
6
7use mabi_core::device::{DeviceHandle, DeviceInfo, DeviceState};
8use mabi_core::types::{DataPoint, DataPointDef};
9use mabi_core::value::Value;
10use mabi_core::Result as CoreResult;
11
12#[async_trait]
14pub trait DevicePort: Send + Sync {
15 fn info(&self) -> DeviceInfo;
17
18 fn id(&self) -> String {
20 self.info().id
21 }
22
23 fn state(&self) -> DeviceState {
25 self.info().state
26 }
27
28 async fn start(&self) -> CoreResult<()>;
30
31 async fn stop(&self) -> CoreResult<()>;
33
34 async fn read(&self, point_id: &str) -> CoreResult<DataPoint>;
36
37 async fn write(&self, point_id: &str, value: Value) -> CoreResult<()>;
39
40 fn point_definitions(&self) -> Vec<DataPointDef> {
42 Vec::new()
43 }
44}
45
46pub type DynDevicePort = Arc<dyn DevicePort>;
48
49#[derive(Clone)]
51pub struct CoreDevicePort {
52 handle: DeviceHandle,
53}
54
55impl CoreDevicePort {
56 pub fn new(handle: DeviceHandle) -> Self {
58 Self { handle }
59 }
60
61 pub fn handle(&self) -> &DeviceHandle {
63 &self.handle
64 }
65
66 pub fn into_shared(self) -> DynDevicePort {
68 Arc::new(self)
69 }
70}
71
72impl From<DeviceHandle> for CoreDevicePort {
73 fn from(handle: DeviceHandle) -> Self {
74 Self::new(handle)
75 }
76}
77
78#[async_trait]
79impl DevicePort for CoreDevicePort {
80 fn info(&self) -> DeviceInfo {
81 self.handle.info()
82 }
83
84 async fn start(&self) -> CoreResult<()> {
85 self.handle.start().await
86 }
87
88 async fn stop(&self) -> CoreResult<()> {
89 self.handle.stop().await
90 }
91
92 async fn read(&self, point_id: &str) -> CoreResult<DataPoint> {
93 self.handle.read(point_id).await
94 }
95
96 async fn write(&self, point_id: &str, value: Value) -> CoreResult<()> {
97 self.handle.write(point_id, value).await
98 }
99}
100
101#[derive(Clone, Default)]
103pub struct DeviceRegistry {
104 inner: Arc<RwLock<HashMap<String, DynDevicePort>>>,
105}
106
107impl DeviceRegistry {
108 pub fn new() -> Self {
110 Self::default()
111 }
112
113 pub fn register(&self, device_id: impl Into<String>, port: DynDevicePort) {
115 self.inner.write().insert(device_id.into(), port);
116 }
117
118 pub fn register_handle(&self, device_id: impl Into<String>, handle: DeviceHandle) {
120 self.register(device_id, CoreDevicePort::new(handle).into_shared());
121 }
122
123 pub fn get(&self, device_id: &str) -> Option<DynDevicePort> {
125 self.inner.read().get(device_id).cloned()
126 }
127
128 pub fn contains(&self, device_id: &str) -> bool {
130 self.inner.read().contains_key(device_id)
131 }
132
133 pub fn device_ids(&self) -> Vec<String> {
135 self.inner.read().keys().cloned().collect()
136 }
137
138 pub fn entries(&self) -> Vec<(String, DynDevicePort)> {
140 self.inner
141 .read()
142 .iter()
143 .map(|(device_id, port)| (device_id.clone(), Arc::clone(port)))
144 .collect()
145 }
146
147 pub fn len(&self) -> usize {
149 self.inner.read().len()
150 }
151
152 pub fn is_empty(&self) -> bool {
154 self.inner.read().is_empty()
155 }
156
157 pub fn remove(&self, device_id: &str) -> Option<DynDevicePort> {
159 self.inner.write().remove(device_id)
160 }
161
162 pub fn clear(&self) {
164 self.inner.write().clear();
165 }
166}
167
168#[cfg(test)]
169mod tests {
170 use super::DeviceRegistry;
171
172 #[test]
173 fn registry_starts_empty() {
174 let registry = DeviceRegistry::new();
175 assert!(registry.is_empty());
176 assert_eq!(registry.len(), 0);
177 }
178}