use std::fs;
use std::io;
use std::path::Path;
use lazy_static::lazy_static;
use regex::Regex;
use super::Controller;
use crate::{
attr_file::{AttrFile, ReadAttr, WriteAttr},
hierarchy::HierarchyNode,
};
pub trait PidsController: Controller {
fn current(&self) -> Box<dyn '_ + ReadAttr<usize>>;
fn max(&self) -> Box<dyn '_ + AttrFile<Option<usize>>>;
fn events(&self) -> Box<dyn '_ + ReadAttr<usize>>;
}
impl PidsController for HierarchyNode {
fn current(&self) -> Box<dyn '_ + ReadAttr<usize>> {
let file = self.as_path().join("pids.current");
Box::new(CurrentFile(file))
}
fn max(&self) -> Box<dyn '_ + AttrFile<Option<usize>>> {
let file = self.as_path().join("pids.max");
Box::new(MaxFile(file))
}
fn events(&self) -> Box<dyn '_ + ReadAttr<usize>> {
let file = self.as_path().join("pids.events");
Box::new(EventFile(file))
}
}
struct CurrentFile<P: AsRef<Path>>(P);
impl<P: AsRef<Path>> ReadAttr<usize> for CurrentFile<P> {
fn read(&self) -> io::Result<usize> {
let file = self.0.as_ref();
let s = fs::read_to_string(&file)?;
match s.trim().parse() {
Ok(number) => Ok(number),
Err(_) => Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("failed to parse number of pids from {}", file.display()),
)),
}
}
}
struct MaxFile<P: AsRef<Path>>(P);
impl<P: AsRef<Path>> ReadAttr<Option<usize>> for MaxFile<P> {
fn read(&self) -> io::Result<Option<usize>> {
lazy_static! {
static ref RE: Regex = Regex::new(r"^(max|\d+)$").unwrap();
}
let file = self.0.as_ref();
let s = fs::read_to_string(&file)?;
match RE.captures(&s.trim()) {
Some(cap) => match &cap[1] {
"max" => Ok(None),
number => Ok(Some(number.parse().unwrap())),
},
None => Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("failed to read max pids limit from {}", file.display()),
)),
}
}
}
impl<P: AsRef<Path>> WriteAttr<Option<usize>> for MaxFile<P> {
fn write(&self, max: &Option<usize>) -> io::Result<()> {
match max {
Some(max) => fs::write(&self.0, format!("{}", max)),
None => fs::write(&self.0, b"max"),
}
}
}
struct EventFile<P: AsRef<Path>>(P);
impl<P: AsRef<Path>> ReadAttr<usize> for EventFile<P> {
fn read(&self) -> io::Result<usize> {
lazy_static! {
static ref RE: Regex = Regex::new(r"^max (\d+)$").unwrap();
}
let file = self.0.as_ref();
let s = fs::read_to_string(&file)?;
match RE.captures(&s.trim()) {
Some(cap) => Ok(cap[1].parse().unwrap()),
None => Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("failed to read pids event from {}", file.display()),
)),
}
}
}