TOML compile-time constants
Install the CLI. This generates some boilerplate files and code:
cargo install toml_const_cli
# use toml_const_cli init --help to view more options
toml_const_cli init <MANIFEST_PATH> # path to Cargo.toml
Your package should now look like this:
package
├── .cargo # generated/modified by CLI
│ └── config.toml
├── .config # generated by CLI
│ ├── .gitignore
│ ├── package.debug.toml # debug variant
│ ├── package.deploy.toml # deploy/release variant
│ └── package.template.toml # defaults
├── src
│ └── main.rs
├── .gitignore
├── build.rs # generated by CLI
├── generated.rs # generated by build.rs
└── Cargo.toml
If you have an existing build script, add the following inside:
// inside build.rs
fn main() {
toml_const::run();
// ... rest of your build script
}
generated.rs
can now be included into your code:
include!("../generated.rs") // included in main, for example
It is recommended to include this file in a separate module:
// inside main.rs / lib.rs
mod consts;
// inside consts.rs
#![allow(unused)]
include!("../generated.rs")
And then use it:
let this: bool = consts::USE; // the USE const must always be defined
All valid TOML datatypes are generated as compile-time constants, except for tables/arrays that contain inner tables/arrays.
Arrays and tables are defined inside a lazy_static!
wrapper.
All tables are destructured, when possible, to keys that point to their TOML values. Namespaces are separated with an underscore "_
".
[table]
field = "string"
time = 11:20:00
integer = 3
[table.inner]
field = "another string"
datetime = 1979-05-27 07:32:00Z
one_billion = 1e09
[table.other]
normal_array = [1, 2, 3, 4, 5, 6]
[[arr_of_tables]]
this = "foo"
that = "bar"
[[arr_of_tables]]
this = "fizz"
that = "buzz"
[[arr_of_tables]]
this = "pee"
that = "poo"
// destructured first table
let f: &str = TABLE_FIELD;
let t: toml::value::Datetime = TABLE_TIME;
let i: i64 = TABLE_INTEGER;
// destructured second table
let tif: &str = TABLE_INNER_FIELD;
let tidt: toml::value::Datetime = TABLE_INNER_DATETIME;
let tib: i64 = TABLE_INNER_ONE_BILLION;
Last-level tables, or tables that do not contain inner tables or arrays, also have their key-value pairs stored as a HashMap<&'static str, String>
:
/// `table` does not have an associated hashmap, as it contains
/// an inner table `table.inner`.
///
/// The associatd hashmap for `table.inner` is TABLE_INNER.
let ht: &HashMap<&'static str, String> = &*TABLE_INNER;
// hashmaps lose type-specific information
let tif_string: &str = TABLE_INNER.get("FIELD").unwrap();
let tidt_string: &str = TABLE_INNER.get("DATETIME").unwrap();
let tib_string: &str = TABLE_INNER.get("ONE_BILLION").unwrap();
// but you can iterate over them at runtime
for key in TABLE_INNER.keys() {
// ...
}
Arrays can also be used. The type for all elements is inferred from the first element.
// iterate over array elements
for item: &i64 in TABLE_OTHER_NORMAL_ARRAY.iter() {
// ...
}
// iterate over array of tables
for subtable: &HashMap<&'static str, String> in ARR_OF_TABLES.iter() {
// ...
}
Generated code
// ...imports excluded
/// type: &'static str
pub const TABLE_INNER_FIELD: &'static str = "another string";
/// type: f64
pub const TABLE_INNER_ONE_BILLION: f64 = (1000000000_f64);
/// type: i64
pub const TABLE_INTEGER: i64 = (3_i64);
lazy_static::lazy_static! {
/// type: [HashMap<&'static str, String>; 3]
pub static ref ARR_OF_TABLES: [HashMap<&'static str, String>; 3] = [
HashMap::from([
("that", "bar".to_string()),("this", "foo".to_string()),])
,
HashMap::from([
("that", "buzz".to_string()),("this", "fizz".to_string()),])
,
HashMap::from([
("that", "poo".to_string()),("this", "pee".to_string()),])
];
}
/// type: &'static str
pub const TABLE_FIELD: &'static str = "string";
/// type: bool
pub const USE: bool = false;
/// type: Datetime
pub const TABLE_TIME: Datetime = Datetime {
date: None,
time: Some(Time {
hour: 11,
minute: 20,
second: 0,
nanosecond: 0,
}),
offset: None,
};
lazy_static::lazy_static! {
/// type: [i64; 6]
pub static ref OTHER_NORMAL_ARRAY: [i64; 6] = [
(1_i64),
(2_i64),
(3_i64),
(4_i64),
(5_i64),
(6_i64)
];
}
/// type: Datetime
pub const TABLE_INNER_DATETIME: Datetime = Datetime {
date: Some(Date {
year: 1979,
month: 5,
day: 27,
}),
time: Some(Time {
hour: 7,
minute: 32,
second: 0,
nanosecond: 0,
}),
offset: Some(Offset::Z),
};
lazy_static::lazy_static! {
/// type: HashMap<&'static str, String>
pub static ref TABLE_INNER: HashMap<&'static str, String> = HashMap::from([
("DATETIME", Datetime { date: Some(Date { year: 1979, month: 5, day: 27 } ), time: Some(Time { hour: 7, minute: 32, second: 0, nanosecond: 0 } ), offset: Some(Offset::Z) }.to_string()),
("FIELD", "another string".to_string()),
("ONE_BILLION", (1000000000_f64).to_string()),
]);
}
toml_const
generates 3 toml files into your root project directory (located in .config/
by default).
The contents from *.template.toml
is used as a base, matching keys from
*.debug.toml
or *.deploy.toml
will override the template values.
New keys defined in debug
or deploy
will be added as well.
Setting the top-level key use=true
will cause toml_const
to generate code from that particular config file.
debug use | deploy use | file(s) used |
---|---|---|
false |
false |
template: compilation warning |
false |
true |
template + deploy |
true |
false |
template + debug |
true |
true |
template + deploy |