use std::fs;
use std::io;
use std::path::Path;
use crate::feature::{Json, parse_json};
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum SubMsCpuPin {
Single,
Multi,
None,
}
impl SubMsCpuPin {
pub fn as_str(self) -> &'static str {
match self {
SubMsCpuPin::Single => "single",
SubMsCpuPin::Multi => "multi",
SubMsCpuPin::None => "none",
}
}
pub fn from_wire(s: &str) -> Option<Self> {
match s.trim().to_ascii_lowercase().as_str() {
"single" | "one" | "true" => Some(SubMsCpuPin::Single),
"multi" | "cores" => Some(SubMsCpuPin::Multi),
"none" | "off" | "false" => Some(SubMsCpuPin::None),
_ => None,
}
}
}
pub struct SubMsBenchConfig {
root: Json,
}
impl Default for SubMsBenchConfig {
fn default() -> Self {
Self::new()
}
}
impl SubMsBenchConfig {
pub fn new() -> Self {
Self {
root: Json::Obj(Vec::new()),
}
}
pub fn load_str(text: &str) -> Self {
let trimmed = text.trim();
if trimmed.is_empty() {
return Self::new();
}
match parse_json(trimmed) {
Ok(root @ Json::Obj(_)) => Self { root },
_ => Self::new(),
}
}
pub fn load(path: impl AsRef<Path>) -> io::Result<Self> {
match fs::read_to_string(path) {
Ok(text) => Ok(Self::load_str(&text)),
Err(e) if e.kind() == io::ErrorKind::NotFound => Ok(Self::new()),
Err(e) => Err(e),
}
}
pub fn to_json(&self) -> String {
self.root.to_pretty()
}
pub fn save(&self, path: impl AsRef<Path>) -> io::Result<()> {
let path = path.as_ref();
if let Some(parent) = path.parent() {
if !parent.as_os_str().is_empty() {
fs::create_dir_all(parent)?;
}
}
fs::write(path, self.to_json())
}
pub fn cpu_pin(&self) -> SubMsCpuPin {
match self.get("cpu_pin") {
Some(Json::Str(s)) => SubMsCpuPin::from_wire(s).unwrap_or(SubMsCpuPin::Single),
Some(Json::Bool(true)) => SubMsCpuPin::Single,
Some(Json::Bool(false)) => SubMsCpuPin::None,
_ => SubMsCpuPin::Single,
}
}
pub fn cores(&self) -> Option<u64> {
self.get_u64("cores")
}
pub fn sample_cap(&self) -> Option<u64> {
self.get_u64("sample_cap")
}
pub fn reason(&self) -> Option<&str> {
match self.get("reason") {
Some(Json::Str(s)) => Some(s.as_str()),
_ => None,
}
}
pub fn set_cpu_pin(&mut self, mode: SubMsCpuPin) -> &mut Self {
self.set("cpu_pin", Json::Str(mode.as_str().to_string()));
self
}
pub fn set_cores(&mut self, cores: u64) -> &mut Self {
self.set("cores", Json::Num(cores.to_string()));
self
}
pub fn set_sample_cap(&mut self, cap: u64) -> &mut Self {
self.set("sample_cap", Json::Num(cap.to_string()));
self
}
pub fn set_reason(&mut self, reason: &str) -> &mut Self {
self.set("reason", Json::Str(reason.to_string()));
self
}
fn get(&self, key: &str) -> Option<&Json> {
match &self.root {
Json::Obj(pairs) => pairs.iter().find(|(k, _)| k == key).map(|(_, v)| v),
_ => None,
}
}
fn get_u64(&self, key: &str) -> Option<u64> {
match self.get(key) {
Some(Json::Num(n)) => n.trim().parse::<u64>().ok(),
_ => None,
}
}
fn set(&mut self, key: &str, val: Json) {
if let Some(obj) = self.root.as_object_mut() {
if let Some(slot) = obj.iter_mut().find(|(k, _)| k == key) {
slot.1 = val;
} else {
obj.push((key.to_string(), val));
}
}
}
}
#[cfg(test)]
#[path = "bench_config_tests.rs"]
mod tests;