extern crate num_cpus; use std::env; use std::fs::*; use std::io::*; use std::path::*; fn cpu_count(out_path: &PathBuf) { let cpu_count = std::env::var("SYSTEM_CPU_COUNT") .map(|cpu_count_string| -> usize { cpu_count_string.parse().unwrap_or(num_cpus::get()) }) .unwrap_or(num_cpus::get()); println!("cargo:rerun-if-env-changed=SYSTEM_CPU_COUNT"); let mut target = File::create(out_path.join("cpu_count.rs")).unwrap(); target .write_fmt(format_args!("pub const CPU_COUNT: usize = {};", cpu_count)) .ok(); } fn get_root_dir() -> PathBuf { let out_dir = env::var("OUT_DIR").unwrap(); let mut out_dir = Path::new(&out_dir); assert!(out_dir.is_dir()); loop { let is_end = out_dir.file_name().unwrap() == "target"; out_dir = Path::new(out_dir.parent().unwrap()); if is_end { break; } } return out_dir.to_path_buf(); } extern crate toml; use std::collections::LinkedList; use std::convert::TryFrom; fn static_config(project_path: &PathBuf, cargo_root_path: &PathBuf, out_path: &PathBuf) { let config_path = std::env::var("STATIC_TOML_PATH") .map(PathBuf::from) .unwrap_or(cargo_root_path.join("static_config.toml")); let mut usize_def_string = String::new(); let mut usize_val_string = String::new(); let mut match_string = String::new(); let template_path = project_path .join("template") .join("static_config.rs.template"); let target_path = out_path.join("static_config.rs"); println!("cargo:rerun-if-changed={}", template_path.to_str().unwrap()); println!("cargo:rerun-if-changed={}", config_path.to_str().unwrap()); let mut template = File::open(template_path).unwrap(); let mut target = File::create(target_path).unwrap(); if config_path.exists() { let mut config_file = File::open(config_path).unwrap(); let mut config_string = String::new(); config_file.read_to_string(&mut config_string).ok(); let config = config_string.parse::().unwrap(); let mut queue = LinkedList::new(); queue.push_back((String::from(""), config)); loop { let current; let prefix; if let Some((_prefix, _current)) = queue.pop_front() { current = _current; prefix = _prefix; } else { break; } match current { toml::Value::String(val) => { match_string += &format!( "\n\"{}\" => ParamType::STRING(\"{}\"),", prefix, val.replace("\\", "\\\\").replace("\"", "\\\"") ); } toml::Value::Integer(val) => loop { if let Some(target) = usize::try_from(val).ok() { let const_name = prefix.replace(".", "_").replace(" ", "_").to_uppercase(); usize_def_string += &format!("\npub {}: usize,", const_name); usize_val_string += &format!("\n{}: {},", const_name, target); } if let Some(target) = u8::try_from(val).ok() { match_string += &format!("\n\"{}\" => ParamType::U8({}),", prefix, target); break; } if let Some(target) = u16::try_from(val).ok() { match_string += &format!("\n\"{}\" => ParamType::U16({}),", prefix, target); break; } if let Some(target) = u32::try_from(val).ok() { match_string += &format!("\n\"{}\" => ParamType::U32({}),", prefix, target); break; } if let Some(target) = u64::try_from(val).ok() { match_string += &format!("\n\"{}\" => ParamType::U64({}),", prefix, target); break; } if let Some(target) = u128::try_from(val).ok() { match_string += &format!("\n\"{}\" => ParamType::U128({}),", prefix, target); break; } if let Some(target) = i8::try_from(val).ok() { match_string += &format!("\n\"{}\" => ParamType::I8({}),", prefix, target); break; } if let Some(target) = i16::try_from(val).ok() { match_string += &format!("\n\"{}\" => ParamType::I16({}),", prefix, target); break; } if let Some(target) = i32::try_from(val).ok() { match_string += &format!("\n\"{}\" => ParamType::I32({}),", prefix, target); break; } if let Some(target) = i64::try_from(val).ok() { match_string += &format!("\n\"{}\" => ParamType::I64({}),", prefix, target); break; } if let Some(target) = i128::try_from(val).ok() { match_string += &format!("\n\"{}\" => ParamType::I128({}),", prefix, target); break; } panic!("Cannot find suitable integer type") }, toml::Value::Float(val) => { match_string += &format!("\n\"{}\" => ParamType::FLOAT({}),", prefix, val); } toml::Value::Boolean(val) => { match_string += &format!("\n\"{}\" => ParamType::BOOL({}),", prefix, val); } toml::Value::Datetime(_) | toml::Value::Array(_) => { panic!("Datetime and arrays are not available in static toml config") } toml::Value::Table(val) => { for (k, v) in val { let new_prefix = if prefix.len() == 0 { k } else { format!("{}.{}", prefix, k) }; queue.push_back((new_prefix, v)); } } } } } let mut template_string = String::new(); template.read_to_string(&mut template_string).ok(); template_string = template_string.replace("%%MATCH_STRING%%", &match_string); template_string = template_string.replace("%%USIZE_DEF%%", &usize_def_string); template_string = template_string.replace("%%USIZE_VAL%%", &usize_val_string); target.write_fmt(format_args!("{}", template_string)).ok(); } fn main() { let project_path = PathBuf::from(".").canonicalize().unwrap(); //let manifest_path = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); let cargo_root_path = get_root_dir(); let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()) .canonicalize() .unwrap(); cpu_count(&out_path); static_config(&project_path, &cargo_root_path, &out_path); }