use crate::BccError;
use std::fs::File;
use std::io::Read;
use std::str::FromStr;
const CPUONLINE: &str = "/sys/devices/system/cpu/online";
fn read_cpu_range(cpu_range_str: &str) -> Result<Vec<usize>, BccError> {
let mut cpus = Vec::new();
let cpu_range_str_trim = cpu_range_str.trim();
for cpu_range in cpu_range_str_trim.split(',') {
let rangeop: Vec<&str> = cpu_range.splitn(2, '-').collect();
let first = match usize::from_str(rangeop[0]) {
Ok(res) => res,
Err(_) => {
return Err(BccError::InvalidCpuRange {
range: cpu_range_str.to_string(),
})
}
};
if rangeop.len() == 1 {
cpus.push(first);
continue;
}
let last = match usize::from_str(rangeop[1]) {
Ok(res) => res,
Err(_) => {
return Err(BccError::InvalidCpuRange {
range: cpu_range_str.to_string(),
})
}
};
for n in first..=last {
cpus.push(n);
}
}
Ok(cpus)
}
pub fn get() -> Result<Vec<usize>, BccError> {
let mut buffer = String::new();
File::open(CPUONLINE)?.read_to_string(&mut buffer)?;
read_cpu_range(&buffer)
}
#[cfg(test)]
mod tests {
use super::read_cpu_range;
use lazy_static::*;
struct TestData<'a> {
data: &'a str,
expected: Vec<usize>,
valid: bool,
}
lazy_static! {
static ref TEST: Vec<TestData<'static>> = vec![
TestData {
data: "",
expected: Vec::new(),
valid: false,
},
TestData {
data: "0-3\n",
expected: vec![0, 1, 2, 3],
valid: true,
},
TestData {
data: " 0-2,5",
expected: vec![0, 1, 2, 5],
valid: true,
},
TestData {
data: "0,2,4-5,7-9",
expected: vec![0, 2, 4, 5, 7, 8, 9],
valid: true,
},
TestData {
data: "0,2",
expected: vec![0, 2],
valid: true,
},
TestData {
data: "0",
expected: vec![0],
valid: true,
},
TestData {
data: "-2,5",
expected: Vec::new(),
valid: false,
},
TestData {
data: "2-@,5",
expected: Vec::new(),
valid: false,
},
TestData {
data: "-",
expected: Vec::new(),
valid: false,
},
];
}
#[test]
fn test_cpu_online() {
for i in 0..TEST.len() {
let t = &TEST[i];
let res = read_cpu_range(t.data);
assert!((t.valid && res.is_ok()) || (!t.valid && res.is_err()));
if let Ok(v) = res {
for i in 0..v.len() {
assert_eq!(v[i], t.expected[i]);
}
}
}
}
}