Thanks to visit codestin.com
Credit goes to lib.rs

#env-var #parse-env #define

build envparse

Parse compile-time environment variables into consts

1 unstable release

0.1.0 Dec 1, 2024

#585 in Configuration

Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App

23,737 downloads per month

Unlicense OR MIT OR Apache-2.0

63KB
1K SLoC

envparse

Quick and dirty crate for parsing values out of an environment var provided at compile time. See also: docs.

Usage

Here's an example

const MAX_LEN: usize = envparse::parse_env!("MYCRATE_MAX_THING_LEN" as usize else 64);
struct Thing {
    len: [u8; MAX_LEN],
}

You can bound by ranges too. This one will fail because the MUST_BE_USER_PROVIDED var isn't provided.

const MAX_LEN_LOG2: u32 = envparse::parse_env!("MYCRATE_MAX_LEN_LOG2" as u32 in 0..32);
const MAX_LEN: usize = 1 << MAX_LEN_LOG2;
struct Thing {
    len: [u8; MAX_LEN],
}

You can also try

const MAX_LEN_LOG2: u32 = match envparse::parse_env!(try "OPTIONAL_MAX_LEN_LOG2" as u32 in 0..32) {
    Some(v) => v,
    None => 5,
}
const MAX_LEN: usize = 1 << MAX_LEN_LOG2;
struct Thing {
    len: [u8; MAX_LEN],
}


lib.rs:

A crate which allows parsing environment variables defined at compile time into constants using const fn (rather than proc macros).

See parse_env for the main entry point into the library.

Motivation

env! and option_env! macros are useful for allowing certain forms of compile-time customization for libraries and programs, however they're unfortunately limited: they always produce a &str or Option<&str> as a result. This works so long as you need a string, and not something like a number.

In many cases, it's desirable to allow something like an array size to be configured at compile time. This pattern is fairly common in C and C++ code, where it's handled by allowing the user to tune these values for their use, possibly by providing something like -DFOOBAR_SIZE=32[^1] via an environment variable like CFLAGS.

Unfortunately, using one of these strings as an array length requires it be parsed at compile time, either in a proc macro, or a const fn. Both of these have downsides: proc macros are extremely slow to compile, and

Unfortunately, const fn is very limited in Rust, so parsing this is a pain. That's what this library is for.

[^1]: Or /D with MSVC — you get the idea.

use envparse::parse_env;
// parse `MYCRATE_MAX_THING_LEN` from the environment,
// defaulting to 4 if not provided.
const MAX_THING_LEN: usize = parse_env!("MYCRATE_MAX_THING_LEN" as usize else 4);
struct Thing {
    len: [u8; MAX_THING_LEN],
}

Supported types

Currently, the following types are supported:

Primitive integers

The primitive integer types are all supported: i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isizeandusize`.

These mostly follow a (slight superset of) Rust's syntax, with the exception that a trailing type indicator is not allowed.

Booleans

Booleans are supported, following some mostly ad-hoc conventions described by the table. As with integers, the parsing is not case-sensitive and ignores leading and trailing whitespace

Note that the empty string is not considered a valid bool, so FOOBAR="" neither works to enable or disable something.

bool value accepted strings (case-insensitive, trimmed)
false 0, false, f, off, no or n
true 1, true, t, on, yes or y

Syntax

Integers

Integers are parsed as follows with a couple notes:

  1. Whitespace is ignored at the start or end of the input.
  2. Input is not case-sensitive. 0XABC is equivalent to 0xabc.
  3. + is allowed as a sign prefix, unlike in Rust's syntax.
  4. Unsigned integers reject a leading - sign early, but for the most part bounds/ranges are not checked until after parsing.
integer: ('+' | '-')? (dec_int | oct_int | bin_int | hex_int)

dec_int: digit_dec (digit_dec | '_')*
hex_int: '0x' (digit_hex | '_')* digit_hex (digit_hex | '_')*
oct_int: '0o' (digit_oct | '_')* digit_oct (digit_oct | '_')*
bin_int: '0b' (digit_bin | '_')* digit_bin (digit_bin | '_')*
digit_bin: [0-1]
digit_oct: [0-7]
digit_dec: [0-9]
digit_hex: [0-9a-fA-F]

Booleans

This is entirely case-insensitive, and any whitespace is trimmed from either end.

We're fairly forgiving here (perhaps more-so than we should be), in order to be compatible with some other ways of configuration (rustc's command line arguments, for example).

boolean: (true_str | false_str)
false_str: ( '0' | 'false' | 'f' | 'off' | 'no'  | 'n' )
true_str:  ( '1' | 'true'  | 't' | 'on'  | 'yes' | 'y' )

No runtime deps