use crate::types::{device, Error};
use std::future::Future;
use std::{convert::Infallible, pin::Pin, sync::Arc};
use tokio::sync::{mpsc, oneshot, Mutex};
use toml::value;
use super::Result;
pub type Name = Arc<str>;
pub type DriverConfig = value::Table;
mod ro_device;
mod rw_device;
pub use ro_device::{ReadOnlyDevice, ReportReading};
pub use rw_device::{
ReadWriteDevice, RxDeviceSetting, SettingReply, SettingRequest,
TxDeviceSetting,
};
pub enum Request {
AddReadonlyDevice {
driver_name: Name,
dev_name: device::Name,
dev_units: Option<String>,
max_history: Option<usize>,
rpy_chan: oneshot::Sender<Result<ReportReading>>,
},
AddReadWriteDevice {
driver_name: Name,
dev_name: device::Name,
dev_units: Option<String>,
max_history: Option<usize>,
rpy_chan: oneshot::Sender<
Result<(ReportReading, RxDeviceSetting, Option<device::Value>)>,
>,
},
}
#[derive(Clone)]
pub struct RequestChan {
driver_name: Name,
prefix: device::Path,
req_chan: mpsc::Sender<Request>,
}
impl RequestChan {
pub fn new(
driver_name: Name,
prefix: &device::Path,
req_chan: &mpsc::Sender<Request>,
) -> Self {
RequestChan {
driver_name,
prefix: prefix.clone(),
req_chan: req_chan.clone(),
}
}
pub async fn add_ro_device<
T: Into<device::Value> + TryFrom<device::Value> + Clone,
>(
&self,
name: device::Base,
units: Option<&str>,
max_history: Option<usize>,
) -> super::Result<ReadOnlyDevice<T>> {
let (tx, rx) = oneshot::channel();
let result = self
.req_chan
.send(Request::AddReadonlyDevice {
driver_name: self.driver_name.clone(),
dev_name: device::Name::build(self.prefix.clone(), name),
dev_units: units.map(String::from),
max_history,
rpy_chan: tx,
})
.await;
if result.is_ok() {
if let Ok(v) = rx.await {
return v.map(ReadOnlyDevice::new);
}
}
Err(Error::MissingPeer(String::from(
"can't communicate with core",
)))
}
pub async fn add_rw_device<T>(
&self,
name: device::Base,
units: Option<&str>,
max_history: Option<usize>,
) -> Result<ReadWriteDevice<T>>
where
T: Into<device::Value> + TryFrom<device::Value> + Clone,
{
let (tx, rx) = oneshot::channel();
let result = self
.req_chan
.send(Request::AddReadWriteDevice {
driver_name: self.driver_name.clone(),
dev_name: device::Name::build(self.prefix.clone(), name),
dev_units: units.map(String::from),
max_history,
rpy_chan: tx,
})
.await;
if result.is_ok() {
if let Ok(v) = rx.await {
return v.map(|(rr, rs, prev)| {
ReadWriteDevice::new(
rr,
rs,
prev.and_then(|v| T::try_from(v).ok()),
)
});
}
}
Err(Error::MissingPeer(String::from(
"can't communicate with core",
)))
}
}
pub type DriverType<T> = Box<dyn API<DeviceSet = <T as API>::DeviceSet>>;
pub trait API: Send {
type DeviceSet: Send + Sync;
fn register_devices(
drc: RequestChan,
cfg: &DriverConfig,
max_history: Option<usize>,
) -> Pin<Box<dyn Future<Output = Result<Self::DeviceSet>> + Send>>;
fn create_instance(
cfg: &DriverConfig,
) -> Pin<Box<dyn Future<Output = Result<Box<Self>>> + Send>>
where
Self: Sized;
fn run<'a>(
&'a mut self,
devices: Arc<Mutex<Self::DeviceSet>>,
) -> Pin<Box<dyn Future<Output = Infallible> + Send + 'a>>;
}