esp-hal/esp-config/src/lib.rs

111 lines
3.5 KiB
Rust

#![doc = include_str!("../README.md")]
//! ## Feature Flags
#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]
#![doc(html_logo_url = "https://avatars.githubusercontent.com/u/46717278")]
#![cfg_attr(not(feature = "build"), no_std)]
#![deny(missing_docs, rust_2018_idioms)]
#[cfg(feature = "build")]
mod generate;
#[cfg(feature = "build")]
pub use generate::{generate_config, Error, Validator, Value};
/// Parse the value of an environment variable as a [bool] at compile time.
#[macro_export]
macro_rules! esp_config_bool {
( $var:expr ) => {
match env!($var).as_bytes() {
b"true" => true,
b"false" => false,
_ => ::core::panic!("boolean value must be either 'true' or 'false'"),
}
};
}
// TODO: From 1.82 on, we can use `<$ty>::from_str_radix(env!($var), 10)`
/// Parse the value of an environment variable as an integer at compile time.
#[macro_export]
macro_rules! esp_config_int {
( $ty:ty, $var:expr ) => {
const {
const BYTES: &[u8] = env!($var).as_bytes();
$crate::esp_config_int_parse!($ty, BYTES)
}
};
}
/// Get the string value of an environment variable at compile time.
#[macro_export]
macro_rules! esp_config_str {
( $var:expr ) => {
env!($var)
};
}
/// Parse a string like "777" into an integer, which _can_ be used in a `const`
/// context
#[doc(hidden)] // To avoid confusion with `esp_config_int`, hide this in the docs
#[macro_export]
macro_rules! esp_config_int_parse {
( $ty:ty, $bytes:expr ) => {{
let mut bytes = $bytes;
let mut val: $ty = 0;
let mut sign_seen = false;
let mut is_negative = false;
while let [byte, rest @ ..] = bytes {
match *byte {
b'0'..=b'9' => {
val = val * 10 + (*byte - b'0') as $ty;
}
b'-' | b'+' if !sign_seen => {
is_negative = *byte == b'-';
sign_seen = true;
}
_ => ::core::panic!("invalid character encountered while parsing integer"),
}
bytes = rest;
}
if is_negative {
let original = val;
// Subtract the value twice to get a negative:
val -= original;
val -= original;
}
val
}};
}
#[cfg(test)]
mod test {
// We can only test success in the const context
const _: () = {
core::assert!(esp_config_int_parse!(i64, "-77777".as_bytes()) == -77777);
core::assert!(esp_config_int_parse!(isize, "-7777".as_bytes()) == -7777);
core::assert!(esp_config_int_parse!(i32, "-999".as_bytes()) == -999);
core::assert!(esp_config_int_parse!(i16, "-99".as_bytes()) == -99);
core::assert!(esp_config_int_parse!(i8, "-9".as_bytes()) == -9);
core::assert!(esp_config_int_parse!(u64, "77777".as_bytes()) == 77777);
core::assert!(esp_config_int_parse!(usize, "7777".as_bytes()) == 7777);
core::assert!(esp_config_int_parse!(u32, "999".as_bytes()) == 999);
core::assert!(esp_config_int_parse!(u16, "99".as_bytes()) == 99);
core::assert!(esp_config_int_parse!(u8, "9".as_bytes()) == 9);
};
#[test]
#[should_panic]
fn test_expect_positive() {
esp_config_int_parse!(u8, "-5".as_bytes());
}
#[test]
#[should_panic]
fn test_invalid_digit() {
esp_config_int_parse!(u32, "a".as_bytes());
}
}