use super::*;
use crate::units::Raw;
use derive_where::derive_where;
use std::{
error::Error as StdError, fmt::Debug, io::ErrorKind as IOErrorKind, path::PathBuf,
result::Result as StdResult,
};
pub trait VirtualSensor<T: Raw> {
fn read(&self) -> Result<T>;
}
#[derive(Debug, Clone)]
pub(crate) struct VirtualSensorStruct {
path: PathBuf,
}
impl<T: Raw> VirtualSensor<T> for VirtualSensorStruct {
fn read(&self) -> Result<T> {
match std::fs::read_to_string(&self.path) {
Ok(value) => T::from_raw(&value).map_err(Error::from),
Err(e) => match e.kind() {
IOErrorKind::PermissionDenied => Err(Error::insufficient_rights(&self.path)),
_ => Err(Error::read(e, &self.path)),
},
}
}
}
#[derive_where(Clone; RF)]
#[derive_where(Debug)]
#[derive_where(skip_inner(Debug))]
pub(crate) struct CustomReadVirtualSensorStruct<T, RF, E>
where
RF: Fn() -> StdResult<T, E>,
E: StdError + 'static,
{
read_fn: RF,
}
impl<T, FR, E> VirtualSensor<T> for CustomReadVirtualSensorStruct<T, FR, E>
where
T: Raw,
FR: Fn() -> StdResult<T, E>,
E: StdError + Send + 'static,
{
fn read(&self) -> Result<T> {
(self.read_fn)().map_err(Error::custom_virtual)
}
}
#[cfg(feature = "writeable")]
#[derive_where(Clone; RF, WF)]
#[derive_where(Debug)]
#[derive_where(skip_inner(Debug))]
pub(crate) struct CustomReadWriteVirtualSensorStruct<T, RF, WF, E>
where
RF: Fn() -> StdResult<T, E>,
WF: Fn(&T) -> StdResult<(), E>,
E: StdError + 'static,
{
read_fn: RF,
write_fn: WF,
}
#[cfg(feature = "writeable")]
impl<T, RF, WF, E> VirtualSensor<T> for CustomReadWriteVirtualSensorStruct<T, RF, WF, E>
where
T: Raw,
RF: Fn() -> StdResult<T, E>,
WF: Fn(&T) -> StdResult<(), E>,
E: StdError + Send + 'static,
{
fn read(&self) -> Result<T> {
(self.read_fn)().map_err(Error::custom_virtual)
}
}
#[cfg(feature = "writeable")]
pub trait WriteableVirtualSensor<T: Raw>: VirtualSensor<T> {
fn write(&self, value: &T) -> Result<()>;
}
#[cfg(feature = "writeable")]
impl<T> WriteableVirtualSensor<T> for VirtualSensorStruct
where
T: Raw,
{
fn write(&self, value: &T) -> Result<()> {
std::fs::write(&self.path, value.to_raw().as_bytes()).map_err(|e| match e.kind() {
std::io::ErrorKind::PermissionDenied => Error::insufficient_rights(&self.path),
_ => Error::write(e, &self.path),
})
}
}
#[cfg(feature = "writeable")]
impl<T, RF, WF, E> WriteableVirtualSensor<T> for CustomReadWriteVirtualSensorStruct<T, RF, WF, E>
where
T: Raw,
RF: Fn() -> StdResult<T, E>,
WF: Fn(&T) -> StdResult<(), E>,
E: StdError + Send + 'static,
{
fn write(&self, value: &T) -> Result<()> {
(self.write_fn)(value).map_err(Error::custom_virtual)
}
}
pub fn virtual_sensor_from_path<T: Raw>(
path: impl Into<PathBuf>,
) -> Result<impl VirtualSensor<T> + Clone + Send + Sync + Debug + 'static> {
let path = path.into();
if !path.is_file() {
return Err(Error::read(
std::io::Error::from(std::io::ErrorKind::NotFound),
path,
));
}
Ok(VirtualSensorStruct { path })
}
pub fn custom_virtual_sensor<T, RF, E>(read_fn: RF) -> impl VirtualSensor<T> + Debug
where
T: Raw,
RF: Fn() -> StdResult<T, E>,
E: StdError + Send + 'static,
{
CustomReadVirtualSensorStruct { read_fn }
}
pub fn custom_virtual_sensor_sync<T, RF, E>(
read_fn: RF,
) -> impl VirtualSensor<T> + Send + Sync + Debug
where
T: Raw,
RF: Fn() -> StdResult<T, E> + Send + Sync,
E: StdError + Send + 'static,
{
CustomReadVirtualSensorStruct { read_fn }
}
pub fn custom_virtual_sensor_clone<T, RF, E>(read_fn: RF) -> impl VirtualSensor<T> + Clone + Debug
where
T: Raw,
RF: Fn() -> StdResult<T, E> + Clone,
E: StdError + Send + 'static,
{
CustomReadVirtualSensorStruct { read_fn }
}
#[cfg(feature = "writeable")]
pub fn writeable_virtual_sensor_from_path<T: Raw>(
path: impl Into<PathBuf>,
) -> Result<impl WriteableVirtualSensor<T> + Send + Sync + Debug + 'static> {
let path = path.into();
if !path.is_file() {
return Err(Error::read(
std::io::Error::from(std::io::ErrorKind::NotFound),
path,
));
}
Ok(VirtualSensorStruct { path })
}
#[cfg(feature = "writeable")]
pub fn custom_writeable_virtual_sensor<T, RF, WF, E>(
read_fn: RF,
write_fn: WF,
) -> impl WriteableVirtualSensor<T> + Debug
where
T: Raw,
RF: Fn() -> StdResult<T, E>,
WF: Fn(&T) -> StdResult<(), E>,
E: StdError + Send + 'static,
{
CustomReadWriteVirtualSensorStruct { read_fn, write_fn }
}
#[cfg(feature = "writeable")]
pub fn custom_writeable_virtual_sensor_sync<T, RF, WF, E>(
read_fn: RF,
write_fn: WF,
) -> impl WriteableVirtualSensor<T> + Send + Sync + Debug
where
T: Raw,
RF: Fn() -> StdResult<T, E> + Send + Sync,
WF: Fn(&T) -> StdResult<(), E> + Send + Sync,
E: StdError + Send + 'static,
{
CustomReadWriteVirtualSensorStruct { read_fn, write_fn }
}
#[cfg(feature = "writeable")]
pub fn custom_writeable_virtual_sensor_clone<T, RF, WF, E>(
read_fn: RF,
write_fn: WF,
) -> impl WriteableVirtualSensor<T> + Clone + Debug
where
T: Raw,
RF: Fn() -> StdResult<T, E> + Clone,
WF: Fn(&T) -> StdResult<(), E> + Clone,
E: StdError + Send + 'static,
{
CustomReadWriteVirtualSensorStruct { read_fn, write_fn }
}