use crate::{helpers::err, io::SupportingFileExts, multi_ch_constructor::defaults};
use serde::Deserialize;
use std::{
fs::OpenOptions,
path::{Path, PathBuf},
};
#[derive(Clone, Debug, Deserialize)]
#[serde(from = "ProtoConfig")]
pub struct Config {
pub fmi_graph: PathBuf,
pub ch_fmi_graph: PathBuf,
pub contraction_ratio: String,
pub dim: usize,
pub cost_accuracy: f64,
pub num_threads: usize,
pub is_printing_osm_ids: bool,
pub is_using_external_edge_ids: bool,
}
impl SupportingFileExts for Config {
fn supported_exts<'a>() -> &'a [&'a str] {
&["yaml"]
}
}
impl Config {
pub fn try_from_str(yaml_str: &str) -> err::Result<Config> {
let proto_cfg: ProtoConfig = {
match serde_yaml::from_str(yaml_str) {
Ok(proto_cfg) => proto_cfg,
Err(e) => {
return Err(err::Msg::from(format!(
"Serde couldn't read yaml-str due to error: {}",
e
)))
}
}
};
Ok(Config::from(proto_cfg))
}
pub fn from_str(yaml_str: &str) -> Config {
match Config::try_from_str(yaml_str) {
Ok(cfg) => cfg,
Err(msg) => panic!("{}", msg),
}
}
pub fn try_from_yaml<P: AsRef<Path> + ?Sized>(path: &P) -> err::Result<Config> {
let path = path.as_ref();
let file = {
Config::find_supported_ext(path)?;
match OpenOptions::new().read(true).open(path) {
Ok(file) => file,
Err(e) => {
return Err(err::Msg::from(format!(
"Couldn't open {} due to error: {}",
path.display(),
e
)))
}
}
};
let proto_cfg: ProtoConfig = match serde_yaml::from_reader(file) {
Ok(proto_cfg) => proto_cfg,
Err(e) => {
return Err(err::Msg::from(format!(
"Serde couldn't read {} due to error: {}",
path.display(),
e
)))
}
};
Ok(Config::from(proto_cfg))
}
pub fn from_yaml<P: AsRef<Path> + ?Sized>(path: &P) -> Config {
match Config::try_from_yaml(path) {
Ok(cfg) => cfg,
Err(msg) => panic!("{}", msg),
}
}
}
impl From<ProtoConfig> for Config {
fn from(proto_cfg: ProtoConfig) -> Config {
Config {
fmi_graph: proto_cfg.fmi_graph,
ch_fmi_graph: proto_cfg.ch_fmi_graph,
contraction_ratio: proto_cfg
.contraction_ratio
.unwrap_or(String::from(defaults::CONTRACTION_RATIO)),
dim: proto_cfg.dim,
cost_accuracy: proto_cfg.cost_accuracy.unwrap_or(defaults::COST_ACCURACY),
num_threads: proto_cfg.num_threads.unwrap_or(defaults::NUM_THREADS),
is_printing_osm_ids: proto_cfg.is_printing_osm_ids,
is_using_external_edge_ids: proto_cfg.is_using_external_edge_ids,
}
}
}
#[derive(Debug, Deserialize)]
#[serde(try_from = "RawConfig")]
pub struct ProtoConfig {
pub fmi_graph: PathBuf,
pub ch_fmi_graph: PathBuf,
pub contraction_ratio: Option<String>,
pub dim: usize,
pub min_cost: Option<f64>,
pub cost_accuracy: Option<f64>,
pub num_threads: Option<usize>,
pub is_printing_osm_ids: bool,
pub is_using_external_edge_ids: bool,
}
impl From<RawConfig> for ProtoConfig {
fn from(raw_cfg: RawConfig) -> ProtoConfig {
let raw_cfg = raw_cfg.multi_ch_constructor;
ProtoConfig {
fmi_graph: raw_cfg.fmi_graph,
ch_fmi_graph: raw_cfg.ch_fmi_graph,
contraction_ratio: raw_cfg.contraction_ratio,
dim: raw_cfg.dim,
min_cost: raw_cfg.min_cost,
cost_accuracy: raw_cfg.cost_accuracy,
num_threads: raw_cfg.num_threads,
is_printing_osm_ids: raw_cfg.is_printing_osm_ids,
is_using_external_edge_ids: raw_cfg.is_using_external_edge_ids,
}
}
}
#[derive(Debug, Deserialize)]
pub struct RawConfig {
#[serde(rename = "multi-ch-constructor")]
pub multi_ch_constructor: RawContent,
}
#[derive(Debug, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct RawContent {
#[serde(rename = "fmi-graph")]
pub fmi_graph: PathBuf,
#[serde(rename = "contracted-graph")]
pub ch_fmi_graph: PathBuf,
#[serde(rename = "dimension")]
pub dim: usize,
#[serde(rename = "minimum-cost")]
pub min_cost: Option<f64>,
#[serde(rename = "cost-accuracy")]
pub cost_accuracy: Option<f64>,
#[serde(rename = "contraction-ratio")]
pub contraction_ratio: Option<String>,
#[serde(rename = "number_of_threads")]
pub num_threads: Option<usize>,
#[serde(rename = "is_printing_osm-ids")]
pub is_printing_osm_ids: bool,
#[serde(rename = "is_using_external_edge-ids")]
pub is_using_external_edge_ids: bool,
}