2020-03-12 23:20:34 +03:00
|
|
|
#![recursion_limit = "256"]
|
2021-04-15 23:54:28 +03:00
|
|
|
#![deny(clippy::all)]
|
2020-11-12 10:45:06 +03:00
|
|
|
#![forbid(unsafe_code)]
|
2021-06-22 10:20:22 +03:00
|
|
|
#![forbid(non_ascii_idents)]
|
2020-03-12 23:20:34 +03:00
|
|
|
|
|
|
|
mod ast;
|
|
|
|
mod expand;
|
2020-07-02 20:54:17 +03:00
|
|
|
mod parse;
|
2021-04-15 23:45:57 +03:00
|
|
|
mod utils;
|
2020-03-12 23:20:34 +03:00
|
|
|
|
|
|
|
extern crate proc_macro;
|
|
|
|
extern crate proc_macro2;
|
2021-04-15 23:45:57 +03:00
|
|
|
|
2020-03-12 23:20:34 +03:00
|
|
|
use self::proc_macro::TokenStream;
|
2020-07-02 20:54:17 +03:00
|
|
|
use ast::RootNamespace;
|
2020-03-12 23:20:34 +03:00
|
|
|
use quote::ToTokens;
|
|
|
|
use syn::parse_macro_input;
|
|
|
|
|
|
|
|
/// ### _This API requires the following crate features to be activated: `macro`_
|
|
|
|
///
|
|
|
|
/// Creates new public mod with function fo get each environment variable of mapping.
|
|
|
|
///
|
|
|
|
/// All variables are required and program will panic if some variables haven't value, but you
|
|
|
|
/// can add default value for specific variable.
|
|
|
|
///
|
|
|
|
/// Starts with v0.6.0 if you don't have an optional variable, the variable is set automatically.
|
|
|
|
///
|
|
|
|
/// Example usage
|
|
|
|
/// -------------
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// # use itconfig::config;
|
|
|
|
/// # use std::env;
|
|
|
|
/// config! {
|
|
|
|
/// DATABASE_URL: String,
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// # fn main() {
|
|
|
|
/// # env::set_var("DATABASE_URL", "postgres://u:p@localhost:5432/db");
|
|
|
|
/// # config::init();
|
|
|
|
/// # }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// Config with default value
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// # use itconfig::config;
|
|
|
|
/// # use std::env;
|
|
|
|
/// config! {
|
|
|
|
/// DATABASE_URL: String,
|
|
|
|
/// HOST: String => "127.0.0.1",
|
|
|
|
/// }
|
|
|
|
/// # fn main() {
|
|
|
|
/// # env::set_var("DATABASE_URL", "postgres://u:p@localhost:5432/db");
|
|
|
|
/// # config::init();
|
|
|
|
/// # }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// By default itconfig lib creates module with 'config' name. But you can use simple meta instruction
|
|
|
|
/// if you want to rename module. In the example below we renamed module to 'configuration'
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// # use itconfig::config;
|
|
|
|
/// # use std::env;
|
|
|
|
/// config! {
|
|
|
|
/// #![config(name = "configuration")]
|
|
|
|
///
|
|
|
|
/// DEBUG: bool,
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// fn main() {
|
|
|
|
/// env::set_var("DEBUG", "t");
|
|
|
|
///
|
|
|
|
/// configuration::init();
|
|
|
|
/// assert_eq!(configuration::DEBUG(), true);
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// You also unwrap first config module
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// # use itconfig::config;
|
|
|
|
/// # use std::env;
|
|
|
|
///
|
|
|
|
/// config! {
|
|
|
|
/// #![config(unwrap)]
|
|
|
|
///
|
|
|
|
/// DEBUG: bool,
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// fn main() {
|
|
|
|
/// env::set_var("DEBUG", "t");
|
|
|
|
///
|
|
|
|
/// init();
|
|
|
|
/// assert_eq!(DEBUG(), true);
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// Namespaces
|
|
|
|
/// ----------
|
|
|
|
///
|
|
|
|
/// You can use namespaces for env variables
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// # use itconfig::config;
|
|
|
|
/// # use std::env;
|
|
|
|
///
|
|
|
|
/// config! {
|
|
|
|
/// DEBUG: bool,
|
|
|
|
/// DATABASE {
|
|
|
|
/// USERNAME: String,
|
|
|
|
/// PASSWORD: String,
|
|
|
|
/// HOST: String,
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// fn main() {
|
|
|
|
/// env::set_var("DEBUG", "t");
|
|
|
|
/// env::set_var("DATABASE_USERNAME", "user");
|
|
|
|
/// env::set_var("DATABASE_PASSWORD", "pass");
|
|
|
|
/// env::set_var("DATABASE_HOST", "localhost");
|
|
|
|
///
|
|
|
|
/// config::init();
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// Now you can use nested structure in namespaces without limits :)
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// # use itconfig::config;
|
|
|
|
/// config! {
|
|
|
|
/// FIRST {
|
|
|
|
/// SECOND {
|
|
|
|
/// THIRD {
|
|
|
|
/// FOO: bool => true,
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// # fn main() { config::init () }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// Namespaces supports custom meta
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// # use itconfig::config;
|
|
|
|
/// config! {
|
|
|
|
/// #[cfg(feature = "first")]
|
|
|
|
/// FIRST {
|
|
|
|
/// #[cfg(feature = "second")]
|
|
|
|
/// SECOND {
|
|
|
|
/// #[cfg(feature = "third")]
|
|
|
|
/// THIRD {
|
|
|
|
/// FOO: bool => true,
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// # fn main() { config::init () }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// Meta
|
|
|
|
/// ----
|
|
|
|
///
|
|
|
|
/// If you want to read custom env name for variable you can change it manually.
|
|
|
|
///
|
|
|
|
/// **A variable in the nameespace will lose environment prefix**
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// # use itconfig::config;
|
|
|
|
/// # use std::env;
|
|
|
|
///
|
|
|
|
/// config! {
|
|
|
|
/// #[env_name = "MY_CUSTOM_NAME"]
|
|
|
|
/// PER_PAGE: i32,
|
|
|
|
///
|
|
|
|
/// APP {
|
|
|
|
/// #[env_name = "MY_CUSTOM_NAME"]
|
|
|
|
/// RECIPES_PER_PAGE: i32,
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// fn main() {
|
|
|
|
/// env::set_var("MY_CUSTOM_NAME", "95");
|
|
|
|
///
|
|
|
|
/// config::init();
|
|
|
|
/// assert_eq!(config::PER_PAGE(), 95);
|
|
|
|
/// assert_eq!(config::APP::RECIPES_PER_PAGE(), 95);
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// Also you can add custom meta for each variable. For example feature configurations.
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// # use itconfig::config;
|
|
|
|
/// config! {
|
|
|
|
/// #[cfg(feature = "postgres")]
|
|
|
|
/// DATABASE_URL: String,
|
|
|
|
///
|
|
|
|
/// #[cfg(not(feature = "postgres"))]
|
|
|
|
/// DATABASE_URL: String,
|
|
|
|
/// }
|
|
|
|
/// # fn main() { }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// Concatenate
|
|
|
|
/// -----------
|
|
|
|
///
|
|
|
|
/// Try to concatenate env variable or strings or both to you env variable. It's easy!
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// # use itconfig::config;
|
|
|
|
/// # use std::env;
|
|
|
|
/// config! {
|
|
|
|
/// DATABASE_URL < (
|
|
|
|
/// "postgres://",
|
|
|
|
/// POSTGRES_USERNAME,
|
|
|
|
/// ":",
|
|
|
|
/// POSTGRES_PASSWORD,
|
|
|
|
/// "@",
|
|
|
|
/// POSTGRES_HOST => "localhost:5432",
|
|
|
|
/// "/",
|
|
|
|
/// POSTGRES_DB => "test",
|
|
|
|
/// ),
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// fn main() {
|
|
|
|
/// env::set_var("POSTGRES_USERNAME", "user");
|
|
|
|
/// env::set_var("POSTGRES_PASSWORD", "pass");
|
|
|
|
///
|
|
|
|
/// config::init();
|
|
|
|
/// assert_eq!(config::DATABASE_URL(), "postgres://user:pass@localhost:5432/test".to_string());
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// Concatinated variables can be only strings and support all features like namespaces and meta.
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// # use itconfig::config;
|
|
|
|
/// config! {
|
|
|
|
/// CONCATED_NAMESPACE {
|
|
|
|
/// #[env_name = "DATABASE_URL"]
|
|
|
|
/// CONCAT_ENVVAR < (
|
|
|
|
/// "postgres://",
|
|
|
|
/// NOT_DEFINED_PG_USERNAME => "user",
|
|
|
|
/// ":",
|
|
|
|
/// NOT_DEFINED_PG_PASSWORD => "pass",
|
|
|
|
/// "@",
|
|
|
|
/// NOT_DEFINED_PG_HOST => "localhost:5432",
|
|
|
|
/// "/",
|
|
|
|
/// NOT_DEFINED_PG_DB => "test",
|
|
|
|
/// ),
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// # fn main() { config::init () }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// Static
|
|
|
|
/// ------
|
|
|
|
///
|
|
|
|
/// Starting with 0.11 version you can use lazy static for improve speed of variable. This is very
|
|
|
|
/// useful, if you use variable more than once.
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// # use itconfig::config;
|
|
|
|
/// # use std::env;
|
|
|
|
/// config! {
|
|
|
|
/// static APP_BASE_URL => "/api",
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// fn main () {
|
|
|
|
/// env::set_var("APP_BASE_URL", "/api/v1");
|
|
|
|
///
|
|
|
|
/// config::init();
|
|
|
|
/// assert_eq!(config::APP_BASE_URL(), "/api/v1");
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// You also can use static with concat variables
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// # use itconfig::config;
|
|
|
|
/// config! {
|
|
|
|
/// static CONNECTION_STRING < (
|
|
|
|
/// "postgres://",
|
|
|
|
/// NOT_DEFINED_PG_USERNAME => "user",
|
|
|
|
/// ":",
|
|
|
|
/// NOT_DEFINED_PG_PASSWORD => "pass",
|
|
|
|
/// "@",
|
|
|
|
/// NOT_DEFINED_PG_HOST => "localhost:5432",
|
|
|
|
/// "/",
|
|
|
|
/// NOT_DEFINED_PG_DB => "test",
|
|
|
|
/// ),
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// fn main () {
|
|
|
|
/// config::init();
|
|
|
|
/// assert_eq!(config::CONNECTION_STRING(), "postgres://user:pass@localhost:5432/test".to_string());
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// ---
|
|
|
|
///
|
|
|
|
/// This module will also contain helper method:
|
|
|
|
/// --------------------------------------------
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// pub fn init() {}
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// Run this at the main function for check all required variables without default value.
|
|
|
|
///
|
|
|
|
/// Panics
|
|
|
|
/// ------
|
|
|
|
///
|
|
|
|
/// If you miss some required variables your application will panic at startup.
|
|
|
|
///
|
|
|
|
/// Examples
|
|
|
|
/// --------
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// # use itconfig::config;
|
|
|
|
/// // use dotenv::dotenv;
|
|
|
|
///
|
|
|
|
/// config! {
|
|
|
|
/// DEBUG: bool => true,
|
|
|
|
/// HOST: String => "127.0.0.1",
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// fn main () {
|
|
|
|
/// // dotenv().ok();
|
|
|
|
/// config::init();
|
|
|
|
/// assert_eq!(config::HOST(), String::from("127.0.0.1"));
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
#[proc_macro]
|
|
|
|
pub fn config(input: TokenStream) -> TokenStream {
|
|
|
|
let namespace = parse_macro_input!(input as RootNamespace);
|
|
|
|
namespace.into_token_stream().into()
|
2020-07-02 20:54:17 +03:00
|
|
|
}
|