use std::{
collections::HashMap,
ffi::{OsStr, OsString},
io::{Error, ErrorKind, Result},
os::unix::prelude::OsStrExt,
path::{Component, Path, PathBuf},
};
use super::{
util::{FunctionDir, Status},
Function, Handle,
};
#[derive(Debug, Clone)]
pub struct OtherBuilder {
driver: OsString,
properties: HashMap<PathBuf, Vec<u8>>,
}
impl OtherBuilder {
pub fn build(self) -> (Other, Handle) {
let dir = FunctionDir::new();
(Other { dir: dir.clone() }, Handle::new(OtherFunction { builder: self, dir }))
}
pub fn set(&mut self, name: impl AsRef<Path>, value: impl AsRef<[u8]>) -> Result<()> {
let path = name.as_ref().to_path_buf();
if !path.components().all(|c| matches!(c, Component::Normal(_))) {
return Err(Error::new(ErrorKind::InvalidInput, "property path must be relative"));
}
self.properties.insert(path, value.as_ref().to_vec());
Ok(())
}
}
#[derive(Debug)]
struct OtherFunction {
builder: OtherBuilder,
dir: FunctionDir,
}
impl Function for OtherFunction {
fn driver(&self) -> OsString {
self.builder.driver.clone()
}
fn dir(&self) -> FunctionDir {
self.dir.clone()
}
fn register(&self) -> Result<()> {
for (prop, val) in &self.builder.properties {
self.dir.write(prop, val)?;
}
Ok(())
}
}
#[derive(Debug)]
pub struct Other {
dir: FunctionDir,
}
impl Other {
pub fn new(driver: impl AsRef<OsStr>) -> Result<(Other, Handle)> {
Ok(Self::builder(driver)?.build())
}
pub fn builder(driver: impl AsRef<OsStr>) -> Result<OtherBuilder> {
let driver = driver.as_ref();
if driver.as_bytes().contains(&b'.') || driver.as_bytes().contains(&b'/') || !driver.is_ascii() {
return Err(Error::new(ErrorKind::InvalidInput, "invalid driver name"));
}
Ok(OtherBuilder { driver: driver.to_os_string(), properties: HashMap::new() })
}
pub fn status(&self) -> Status {
self.dir.status()
}
pub fn get(&self, name: impl AsRef<Path>) -> Result<Vec<u8>> {
self.dir.read(name)
}
}