libmedium 0.13.4

Library to interface with lm_sensors
Documentation
//! Module containing the virtual sensors and their related functionality.

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,
};

/// Helper trait that sums up all functionality of a read-only virtual sensor.
pub trait VirtualSensor<T: Raw> {
    /// Reads the virtual sensor.
    fn read(&self) -> Result<T>;
}

/// Struct that represents a virtual sensor.
#[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)),
            },
        }
    }
}

/// Struct that represents a virtual sensor with a custom read function.
#[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)
    }
}

/// Struct that represents a virtual sensor with custom read and write function.
#[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")]
/// Helper trait that sums up all functionality of a read-write virtual sensor.
pub trait WriteableVirtualSensor<T: Raw>: VirtualSensor<T> {
    /// Writes to the virtual sensor.
    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)
    }
}

/// Creates a virtual sensor from the given file at `path`.
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 })
}

/// Creates a virtual sensor from a custom read function.
/// Virtual sensors with custom read and write functions are neither `Send` nor `Sync`.
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 }
}

/// Creates a virtual sensor from a custom read function that is `Send` and `Sync`.
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 }
}

/// Creates a virtual sensor from a custom read function that is `Clone`.
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")]
/// Creates a writable virtual sensor from the given file at `path`.
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")]
/// Creates a virtual sensor from the given file at `path` with a custom read and write function.
/// Virtual sensors with custom read and write functions are neither `Send` nor `Sync`.
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")]
/// Creates a virtual sensor from a custom read and write function that is `Send` and `Sync`.
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")]
/// Creates a virtual sensor from a custom read and write function that is `Clone`.
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 }
}