1 unstable release
0.1.0 | Dec 1, 2024 |
---|
#91 in Configuration
156 downloads per month
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,
isizeand
usize`.
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:
- Whitespace is ignored at the start or end of the input.
- Input is not case-sensitive.
0XABC
is equivalent to0xabc
. +
is allowed as a sign prefix, unlike in Rust's syntax.- 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' )