toml_const 0.1.0

Compile-time constants from TOML
Documentation

toml_const

TOML compile-time constants

Getting started

Add these in your Cargo.toml file:

build = "build.rs"

[[bin]]
name = "toml_const_gen"
path = "src/toml_const_gen.rs"

[dependencies]
toml = "0.8"
lazy_static = "1.4"
toml_const = { git = "https://github.com/cruzerngz/toml_const.git" }

[build-dependencies]
toml_const = { git = "https://github.com/cruzerngz/toml_const.git" }
# crate not published on crates.io yet!
# toml_const = "0.1"

Create a new binary file src/toml_const_gen.rs with the following code:

use std::process::ExitCode;

use toml_const::cli;

fn main() -> ExitCode {
    // use a logging library of your choice
    pretty_env_logger::init();

    cli::run()
}

Run the binary. MANIFEST_PATH is the path to your Cargo.toml package manifest:

# run "cargo run... -- init --help" to see more arguments
cargo run --bin toml_const_gen -- init <MANIFEST_PATH>

The binary will create and configure some files.

Create a build script, build.rs, in the same directory as Cargo.toml:

// build.rs code
fn main() {
    toml_const::run();

    // ... rest of your build script
}

Your package should now look like this:

package
├── build.rs
├── Cargo.toml
├── .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
├── generated.rs # generated by build.rs
├── .gitignore
└── src
    ├── main.rs
    └── toml_const_gen.rs

The generated file generated.rs can now be included into your code:

include!("../generated.rs") // include in main

It is recommended 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 = consts::USE; // the USE const must always be defined

Usage

All valid TOML datatypes are generated as compile-time constants, except for arrays and tables.

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 "_".

For example, this:

[table]
field = "string"
time = 11:20:00
integer = 3

[table.inner]
field = "another string"
datetime = 1979-05-27 07:32:00Z
one_billion = 1e09

Turns to this:

// ...imports excluded

/// type: i64
pub const TABLE_INTEGER: i64 = (3_i64);
/// type: f64
pub const TABLE_INNER_ONE_BILLION: f64 = (1000000000_f64);
/// type: &'static str
pub const TABLE_INNER_FIELD: &'static str = "another string";
/// type: Datetime
pub const TABLE_TIME: Datetime = Datetime {
    date: None,
    time: Some(Time {
        hour: 11,
        minute: 20,
        second: 0,
        nanosecond: 0,
    }),
    offset: None,
};
/// type: &'static str
pub const TABLE_FIELD: &'static str = "string";
/// 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),
};

Toml key table.time is is converted to TABLE_TIME.

A nested table value table.inner.one_billion is destructured to TABLE_INNER_ONE_BILLION.

Additionally, 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` contains the `inner` table
// so it is not a last-level table.
//
// HashMaps and arrays are wrapped in 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()),
]);

This might be useful when iterating over unknown key-value pairs during runtime. You do lose type information, though.

Template, debug, deploy

toml_const generates 3 toml files into your root project directory.

The contents from *.template.toml is used as a base, matching keys from *.debug.toml or *.deploy.toml will override the template values.

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