define_struct! {
pub struct InternalInterrupt {
name: String,
counts: Vec<usize>,
details: String,
}
}
define_struct! {
pub struct DeviceInterrupt {
irq_number: usize,
counts: Vec<usize>,
type_device: String,
}
}
define_struct! {
pub struct Interrupts {
cpu_num: usize,
internals: Vec<InternalInterrupt>,
devices: Vec<DeviceInterrupt>,
}
}
use std::str::FromStr;
impl FromStr for InternalInterrupt {
type Err = crate::ProcErr;
fn from_str(s: &str) -> Result<InternalInterrupt, crate::ProcErr> {
let columns: Vec<&str> = s.split_ascii_whitespace().collect();
if columns.len() < 2 {
return Err("require at least two clolums to parse an InternalInterrupt".into())
}
let name = columns[0].trim_end_matches(':').to_string();
let mut cpu_num = 0;
let mut counts = vec![];
for item in columns[1..].iter() {
if let Ok(n) = item.parse::<usize>() {
cpu_num += 1;
counts.push(n);
}else {
break;
}
}
if counts.is_empty() {
return Err("interrupt count not found".into());
}
let details = columns[1+cpu_num..].join(" ");
Ok(InternalInterrupt{
name, counts, details
})
}
}
impl FromStr for DeviceInterrupt {
type Err = crate::ProcErr;
fn from_str(s: &str) -> Result<DeviceInterrupt, Self::Err> {
let columns: Vec<&str> = s.split_ascii_whitespace().collect();
if columns.len() < 4{
return Err("require at least four clolums to parse an InternalInterrupt".into())
}
let irq_number = columns[0].trim_end_matches(':').parse::<usize>()?;
let mut cpu_num = 0;
let mut counts = vec![];
for item in columns[1..].iter() {
if let Ok(n) = item.parse::<usize>() {
cpu_num += 1;
counts.push(n);
}else {
break;
}
}
if counts.is_empty() {
return Err("interrupt count not found".into());
}
let type_device = columns[1+cpu_num..].join(" ");
Ok(DeviceInterrupt{
irq_number, counts, type_device
})
}
}
impl FromStr for Interrupts {
type Err = crate::ProcErr;
fn from_str(s: &str) -> Result<Interrupts, Self::Err> {
let lines: Vec<&str> = s.lines().collect();
if lines.is_empty() {
return Err("no enough lines to parse Interrupts".into());
}
let cpu_num = lines[0].split_ascii_whitespace().count();
let mut internals = vec![];
let mut devices = vec![];
let mut skip_lines = 1;
for line in lines.iter().skip(skip_lines) {
if let Ok(itnl) = line.parse::<InternalInterrupt>() {
internals.push(itnl);
skip_lines += 1;
}else {
break;
}
}
for line in lines.iter().skip(skip_lines) {
let dvs = line.parse::<DeviceInterrupt>()?;
devices.push(dvs);
}
Ok(Interrupts{
cpu_num, internals, devices
})
}
}
instance_impl! {
interrupts, "/proc/interrupts", Interrupts
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_parse_internal1() {
let source = "MCP: 250 Machine check polls";
let correct = InternalInterrupt {
name: "MCP".to_string(),
counts: vec![250],
details: "Machine check polls".to_string()
};
assert_eq!(correct, source.parse::<InternalInterrupt>().unwrap())
}
#[test]
fn test_parse_internal2() {
let source = "MIS: 0";
let correct = InternalInterrupt {
name: "MIS".to_string(),
counts: vec![0],
details: "".to_string()
};
assert_eq!(correct, source.parse::<InternalInterrupt>().unwrap())
}
#[test]
fn test_parse_device() {
let source = "1: 9 IO-APIC 1-edge i8042";
let correct = DeviceInterrupt {
irq_number: 1,
counts: vec![9],
type_device: "IO-APIC 1-edge i8042".to_string()
};
assert_eq!(correct, source.parse::<DeviceInterrupt>().unwrap());
}
}