sysfuss 0.3.0

sysfs wrapper for convenience
Documentation
use std::path::Path;
use std::convert::AsRef;
use std::io::Result as IoResult;

use crate::EitherErr2;
use crate::SysAttributeExt;

/// sysfs class entity functionality
#[cfg(feature = "derive")]
pub trait SysEntity: AsRef<Path> + core::fmt::Debug {
    /// Convert specialized entity into general entity path container
    fn to_entity_path(self) -> EntityPath;
    
    /// Get the entity's name
    fn name(&self) -> IoResult<String>;

    /// Try to get the entity's root sysfs dir (probably `/`)
    fn root(&self) -> Option<crate::SysPath> {
        crate::SysPath::from_entity_path(self)
    }
}

/// sysfs class entity functionality
#[cfg(not(feature = "derive"))]
pub trait SysEntity: AsRef<Path> {
    /// Convert specialized entity into general entity path container
    fn to_entity_path(self) -> EntityPath;

    /// Get the entity's name
    fn name(&self) -> IoResult<String>;

    /// Try to get the entity's root sysfs dir (probably `/`)
    fn root(&self) -> Option<crate::SysPath> {
        crate::SysPath::from_entity_path(self)
    }
}

/// sysfs class entity functionality extension
pub trait SysEntityRawExt: SysEntity {
    /// Get an attribute on the entity
    fn attribute<A: crate::SysAttribute, T: std::str::FromStr<Err=E>, E>(&self, attr: A) -> Result<T, EitherErr2<std::io::Error, E>>;
    /// Get an attribute by filename in the entity's directory
    fn attribute_str<A: AsRef<Path>>(&self, attr: A) -> IoResult<String>;
    
    /// Returns true when the entity has the attribute
    fn exists<A: crate::SysAttribute>(&self, attr: A) -> bool;
    
    /// Returns true when the entity has the attribute
    fn exists_str<A: AsRef<Path>>(&self, attr: A) -> bool;
}

impl <X: SysEntity> SysEntityRawExt for X {
    fn attribute<A: crate::SysAttribute, T: std::str::FromStr<Err=E>, E>(&self, attr: A) -> Result<T, EitherErr2<std::io::Error, E>> {
        attr.parse(self)
    }
    
    fn attribute_str<A: AsRef<Path>>(&self, attr: A) -> IoResult<String> {
        std::fs::read_to_string(self.as_ref().join(attr))
    }
    
    fn exists_str<A: AsRef<Path>>(&self, attr: A) -> bool {
        self.as_ref().join(attr).exists()
    }
    
    fn exists<A: crate::SysAttribute>(&self, attr: A) -> bool {
        attr.exists(self)
    }
}


/// sysfs class entity attribute type indicator
pub trait SysEntityAttributes<A: crate::SysAttribute>: SysEntity {
    /// Get attributes available on this entity;
    fn capabilities(&self) -> Vec<A>;
}

/// sysfs class entity attribute type extension
pub trait SysEntityAttributesExt<A: crate::SysAttribute>: SysEntityAttributes<A> + Sized {
    /// Returns true if self is capable of the provided capabilities
    fn capable<C: crate::capability::Capabilities<A, Self>>(&self, mut capabilities: C) -> bool {
        capabilities.satisfies(self)
    }

    /// Get an attribute on the entity
    fn attribute<T: std::str::FromStr<Err=E>, E>(&self, attr: A) -> Result<T, EitherErr2<std::io::Error, E>> {
        attr.parse(self)
    }

    /// Set an attribute on the entity
    fn set<V: std::string::ToString>(&self, attr: A, value: V) -> IoResult<()> {
        attr.write_str(self, &value.to_string())
    }

    /// Read entity attribute value
    fn read_value(&self, attr: &A) -> IoResult<Vec<u8>> {
        attr.read_value(self)
    }

    /// Write entity attribute value
    fn write_value(&self, attr: &A, value: &[u8]) -> IoResult<()> {
        attr.write_value(self, value)
    }

    /// Returns true when the entity has the attribute
    fn exists(&self, attr: &A) -> bool {
        attr.exists(self)
    }
}

impl <A: crate::SysAttribute, X: SysEntityAttributes<A>> SysEntityAttributesExt<A> for X {}

/// sysfs class entity implementors
#[cfg_attr(feature = "derive", derive(Debug, Clone))]
pub enum EntityPath {
    /// hwmon
    HwMon(crate::HwMonPath),
    /// power_supply
    PowerSupply(crate::PowerSupplyPath),
    /// Generic
    Generic(crate::BasicEntityPath),
    /// Miscellaneous
    Custom(std::sync::Arc<Box<dyn SysEntity>>),
}

impl EntityPath {
    fn inner(&self) -> &'_ dyn SysEntity {
        match self {
            Self::HwMon(inner) => inner,
            Self::PowerSupply(inner) => inner,
            Self::Generic(inner) => inner,
            Self::Custom(inner) => inner.as_ref().as_ref(),
        }
    }
}

impl AsRef<Path> for EntityPath {
    fn as_ref(&self) -> &Path {
        self.inner().as_ref()
    }
}

impl SysEntity for EntityPath {
    fn to_entity_path(self) -> Self {
        self
    }
    
    fn name(&self) -> IoResult<String> {
        self.inner().name()
    }
}