Expand description


This is a crate for generating compile-time constants in your build.rs file. This crate supports converting types that are typically heap-allocated into fixed-size constants. It includes support for primitives, strings, vectors, maps, sets, and comes with a derive macro to allow implementation with structs and enums.

See this example:

// build.rs

use const_gen::*;
use std::{env, fs, path::Path};

// First, let's dummy up some structs. Enabling the "derive" 
// feature allows us to do this simply, but implementing the
// CompileConst trait by hand is straightforward.

struct TestStruct
    test_u8: u8,
    test_vec: Vec<String>,

struct TestTup(u8, u16);

/// Example inherited documentation
enum TestEnum
    Variant3 { named: u8 }

fn main() 
    // Use the OUT_DIR environment variable to get an 
    // appropriate path.
    let out_dir = env::var_os("OUT_DIR").unwrap();
    let dest_path = Path::new(&out_dir).join("const_gen.rs");

    // Now let's dummy up some data to use in our const 
    // generation
    let test_vec: Vec<u8> = vec!(1,2,3,4,5,10,4);
    let test_struct = TestStruct
        test_u8: 12, 
        test_vec: vec!(String::from("Hello there.")) 
    let test_tup_struct = TestTup(4, 55,);
    let test_enum = TestEnum::Variant1;
    let test_enum_tup = TestEnum::Variant2(23);
    let test_enum_structlike = TestEnum::Variant3{ named: 78 };

    // Now we'll generate the const declarations. We're also 
    // going to test with some primitive types. 
    let const_declarations = vec!
        // Here are type definitions for our enums and structs 
        // above. Attributes from build.rs will not be preserved, 
        // so we need to pass any we want in.
        const_definition!(#[derive(Debug)] pub TestStruct),
        const_definition!(#[derive(Debug)] TestTup),
        const_definition!(#[derive(Debug)] TestEnum),

        // And here are constant definitions for particular 
        // values.
        const_declaration!(TEST_U8 = 27u8),
        const_declaration!(#[doc = "/// Example inherited documentation"] TEST_F32 = 33.5f32),
        const_declaration!(TEST_VEC = test_vec),
        const_declaration!(TEST_STRING = "I'm a string!"),
        const_declaration!(TEST_COW = 
        const_declaration!(pub TEST_STRUCT = test_struct),
        const_declaration!(TEST_TUP_STRUCT = test_tup_struct),
        const_declaration!(TEST_ENUM = test_enum),
        const_declaration!(TEST_ENUM_TUP = test_enum_tup),
        const_declaration!(TEST_ENUM_STRUCTLIKE = 

    // Note: The `const_definition!` and `const_declaration!` 
    // macros above are just simple wrappers for CompileConst 
    // trait methods of the same name. Using those methods
    // would entail the following sytax:
    // TestStruct::const_definition("#[derive(Debug)]")
    // test_struct.const_declaration("TEST_STRUCT")
    // These may be preferable in cases where const names
    // or type attributes have been procedurally generated
    // somehow and need to be treated as strings.

    // If the "phf" feature is enabled, this crate will also 
    // support converting HashMap and HashSet types into 
    // compile-time constant phf map and set types respectively.

    // Lastly, output to the destination file.
    fs::write(&dest_path, const_declarations).unwrap();


Now, in our main.rs file we can do something like this:

// Include our constants
include!(concat!(env!("OUT_DIR"), "/const_gen.rs"));

// And that's it, we can access all of the const values below.
// It plays quite well with rust-analyzer, etc
fn main() 
    println!("{}", TEST_U8);
    println!("{}", TEST_F32);
    println!("{:?}", TEST_VEC);
    println!("{}", TEST_STRING);
    println!("{}", TEST_COW);
    println!("{:?}", TEST_STRUCT);
    println!("{:?}", TEST_TUP_STRUCT);
    println!("{:?}", TEST_ENUM);
    println!("{:?}", TEST_ENUM_TUP);
    println!("{:?}", TEST_ENUM_STRUCTLIKE);

The actual generated output looks like (an unformatted version of) this:

struct TestStruct 
    test_u8: u8,
    test_vec: &'static [&'static str],
struct TestTup(u8, u16);
/// Example inherited documentation
enum TestEnum 
    Variant3 { named: u8 },
const TEST_U8: u8 = 27u8;
/// Example inherited documentation
const TEST_F32: f32 = 33.5f32;
const TEST_VEC: &'static [u8] = 
    &[1u8, 2u8, 3u8, 4u8, 5u8, 10u8, 4u8];
const TEST_STRING: &'static str = "I'm a string!";
const TEST_COW: &'static str = "Cow!";
const TEST_STRUCT: TestStruct = TestStruct 
    test_u8: 12u8,
    test_vec: &["Hello there."],
const TEST_TUP_STRUCT: TestTup = TestTup(4u8, 55u16);
const TEST_ENUM: TestEnum = TestEnum::Variant1;
const TEST_ENUM_TUP: TestEnum = TestEnum::Variant2(23u8);
const TEST_ENUM_STRUCTLIKE: TestEnum = TestEnum::Variant3
    named: 78u8

Out-of-the-box Implementations

The following table shows what types have implementations of the CompileConst trait already defined

TypeConst Representation
<all numeric primitives>no conversion
boolno conversion
String, &str, str&’static str
Vec<T>, &[T]&’static [T]
[T; N where N is 0-256][T’s CompileConst representation; N]
Box<T>, Cow<T>, Rc<T>, Arc<T>T’s CompileConst representation
Option<T>Option<T’s CompileConst representation>
HashMap<K,V>phf::Map<K, V>, with K and V’s CompileConst representation
HashSet<E>phf::Set<E>, with E’s CompileConst representation
()no conversion
<tuples with 2-16 variants>A tuple with the CompileConst representation of each variant

There is also a CompileConstArray trait which generates fixed-size arrays rather than static slices for the following

TypeConst Array Representation
Vec<T>, &[T][T; N]
String, &str, str[char; N]
Box<T>, Cow<T>, Rc<T>, Arc<T>T’s CompileConstArray representation
()no conversion
<tuples with 2-16 variants>A tuple with the CompileConstArray representation of each variant. Only supported if each variant implements CompileConstArray.


This crate will use the endianness, pointer widths, etc of the host machine rather than the target. Eg, doing things like calling to_ne_bytes on an integer and storing the results in a const will result in a byte representation that may not be equivalent to that same integer on the target machine.


At the current time, all features are default.


The phf feature implements the CompileConst trait for HashMaps and HashSets. It will generate a phf::Map for HashMap types and a phf::Set for HashSet types. Note that phf does NOT need to be included in your build dependencies, but it ought to be included in your runtime dependencies in order to use the constants.


The derive feature adds #[derive(CompileConst)] for structs and enums. The requirement is that all members implement CompileConst as well. The #[inherit_docs] attribute may be added to cause generated definition to inherit rustdocs.


Like const_declaration, but for const array types

A macro to help in the creation of const declarations. Allows this syntax: const_declaration!(visibility VAR_NAME = value) This is syntactic sugar for calling the CompileConst::const_declaration function.

A macro to help in the creation of const definitions. Allows this syntax: const_definition!(#[attribute1] #[attributeN] visibility TypeName) This is syntactic sugar for calling the CompileConst::const_definition function.


Trait which defines how a type should be represented as a constant

Trait which defines how an array-representable type should be represented as a const array

Derive Macros

Derives the CompileConst trait for structs and enums. Requires that all fields also implement the CompileConst trait.