-
-
Save riskable/829f3f544a827a56da64957f52d46c1f to your computer and use it in GitHub Desktop.
A build.rs made for generating a config.rs that's full of const values from a Config.toml (in a no_std project)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//! Reads our Config.toml and generates userconfig.rs by converting the values to constants | |
//! that end up being placed in `src/config.rs` via: | |
//! `include!(concat!(env!("OUT_DIR"), "/userconfig.rs"));` | |
use core::include; | |
use std::env; | |
use std::fs; | |
use std::path::Path; | |
// So we can use the date for the serial number | |
use chrono::{DateTime, Utc}; | |
use toml; | |
use toml::Value; | |
// A little hack that lets us use our configuration structs without having to duplicate them here: | |
include!(concat!( | |
env!("CARGO_MANIFEST_DIR"), | |
"/src/config_structs.rs" | |
)); | |
// NOTE: config_structs.rs includes the serde import so we don't need it here | |
fn main() { | |
let now: DateTime<Utc> = Utc::now(); | |
// So we can have a build-time firmware serial number in main.rs like so: | |
// concat!(env!("SERIALNOW"), " v1.0:BEEF") | |
println!("cargo:rustc-env=SERIALNOW={}", now.timestamp()); | |
let out_dir = env::var_os("OUT_DIR").unwrap(); | |
let dest_path = Path::new(&out_dir).join("userconfig.rs"); | |
let mut out = String::new(); | |
let contents = fs::read_to_string(concat!(env!("CARGO_MANIFEST_DIR"), "/Config.toml")).unwrap(); | |
// Need the toml in Table form so we can extract values by key: | |
let config_table: Value = toml::from_str(&contents).unwrap(); | |
let config: Config = toml::from_str(&contents[..]).unwrap(); | |
// out.push_str(format!("// config: {:?}", config).as_str()); | |
// TODO: Figure out a way to iterate over configurable items instead of having them hard coded like this | |
for fname in KeyboardConfig::field_names().iter() { | |
let meta = &config.keyboard.gen_meta_tuple(fname); | |
let value = config_table["keyboard"].get(fname); | |
let mut _const_out = String::new(); | |
if let Some(val) = value { | |
// out.push_str(format!("// val.type_str(): {:?}\n", val.type_str()).as_str()); | |
if meta.2.ends_with("str") { | |
_const_out = format!( | |
"pub const KEYBOARD_{}: {} = {};\n", | |
meta.1.to_uppercase(), | |
"&'static str", | |
val | |
); | |
} else { | |
_const_out = format!( | |
"pub const KEYBOARD_{}: {} = {};\n", | |
meta.1.to_uppercase(), | |
meta.2, | |
val | |
); | |
} | |
out.push_str(&_const_out); | |
} | |
} | |
for fname in MouseConfig::field_names().iter() { | |
let meta = &config.mouse.gen_meta_tuple(fname); | |
let value = config_table["mouse"].get(meta.1); | |
if let Some(val) = value { | |
let const_out = format!( | |
"pub const {}_{}: {} = {};\n", | |
meta.0.to_uppercase().split("CONFIG").next().unwrap(), | |
meta.1.to_uppercase(), | |
meta.2, | |
val | |
); | |
out.push_str(&const_out); | |
} | |
} | |
for fname in LedsConfig::field_names().iter() { | |
let meta = &config.leds.gen_meta_tuple(fname); | |
let value = config_table["leds"].get(meta.1); | |
if let Some(val) = value { | |
let const_out = format!( | |
"pub const {}_{}: {} = {};\n", | |
meta.0.to_uppercase().split("CONFIG").next().unwrap(), | |
meta.1.to_uppercase(), | |
meta.2, | |
val | |
); | |
out.push_str(&const_out); | |
} | |
} | |
for fname in EncoderConfig::field_names().iter() { | |
let meta = &config.encoder.gen_meta_tuple(fname); | |
let value = config_table["encoder"].get(meta.1); | |
if let Some(val) = value { | |
let const_out = format!( | |
"pub const {}_{}: {} = {};\n", | |
meta.0.to_uppercase().split("CONFIG").next().unwrap(), | |
meta.1.to_uppercase(), | |
meta.2, | |
val | |
); | |
out.push_str(&const_out); | |
} | |
} | |
for fname in DisplayConfig::field_names().iter() { | |
let meta = &config.display.gen_meta_tuple(fname); | |
let value = config_table["display"].get(meta.1); | |
if let Some(val) = value { | |
let const_out = format!( | |
"pub const {}_{}: {} = {};\n", | |
meta.0.to_uppercase().split("CONFIG").next().unwrap(), | |
meta.1.to_uppercase(), | |
meta.2, | |
val | |
); | |
out.push_str(&const_out); | |
} | |
} | |
for fname in InfraredConfig::field_names().iter() { | |
let meta = &config.infrared.gen_meta_tuple(fname); | |
let value = config_table["infrared"].get(meta.1); | |
if let Some(val) = value { | |
let const_out = format!( | |
"pub const {}_{}: {} = {};\n", | |
meta.0.to_uppercase().split("CONFIG").next().unwrap(), | |
meta.1.to_uppercase(), | |
meta.2, | |
val | |
); | |
out.push_str(&const_out); | |
} | |
} | |
for fname in DevConfig::field_names().iter() { | |
let meta = &config.dev.gen_meta_tuple(fname); | |
let value = config_table["dev"].get(meta.1); | |
if let Some(val) = value { | |
let const_out = format!( | |
"pub const {}_{}: {} = {};\n", | |
meta.0.to_uppercase().split("CONFIG").next().unwrap(), | |
meta.1.to_uppercase(), | |
meta.2, | |
val | |
); | |
out.push_str(&const_out); | |
} | |
} | |
fs::write(&dest_path, out).unwrap(); | |
println!("cargo:rerun-if-changed=Config.toml"); | |
println!("cargo:rerun-if-changed=build.rs"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment