Merge pull request #18 from icetemple/task-16
feat: add itconfig proc macro
This commit is contained in:
commit
e501831014
20 changed files with 1258 additions and 1144 deletions
|
@ -1,6 +1,7 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
"itconfig",
|
"itconfig",
|
||||||
|
"itconfig-macro",
|
||||||
"itconfig-tests",
|
"itconfig-tests",
|
||||||
"examples/diesel",
|
"examples/diesel",
|
||||||
"examples/rocket", # nightly
|
"examples/rocket", # nightly
|
||||||
|
@ -9,5 +10,6 @@ members = [
|
||||||
|
|
||||||
default-members = [
|
default-members = [
|
||||||
"itconfig",
|
"itconfig",
|
||||||
|
"itconfig-macro",
|
||||||
"itconfig-tests",
|
"itconfig-tests",
|
||||||
]
|
]
|
||||||
|
|
33
README.md
33
README.md
|
@ -18,10 +18,29 @@ where you need variable. It uses little bit memory, but configuration lifetime i
|
||||||
as application lifetime. Because of it I decided to create my own library.
|
as application lifetime. Because of it I decided to create my own library.
|
||||||
|
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
These macros require a Rust compiler version 1.31 or newer.
|
||||||
|
|
||||||
|
Add `itconfig = { version = "1.0", features = ["macro"] }` as a dependency in `Cargo.toml`.
|
||||||
|
|
||||||
|
`Cargo.toml` example:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[package]
|
||||||
|
name = "my-crate"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Me <user@rust-lang.org>"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
itconfig = { version = "1.0", features = ["macro"] }
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
## Example usage
|
## Example usage
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
#[macro_use] extern crate itconfig;
|
use itconfig::config;
|
||||||
use std::env;
|
use std::env;
|
||||||
//use dotenv::dotenv;
|
//use dotenv::dotenv;
|
||||||
|
|
||||||
|
@ -69,11 +88,11 @@ fn main () {
|
||||||
// dotenv().ok();
|
// dotenv().ok();
|
||||||
env::set_var("FEATURE_NEW_MENU", "t");
|
env::set_var("FEATURE_NEW_MENU", "t");
|
||||||
|
|
||||||
cfg::init();
|
config::init();
|
||||||
assert_eq!(cfg::HOST(), String::from("127.0.0.1"));
|
assert_eq!(config::HOST(), String::from("127.0.0.1"));
|
||||||
assert_eq!(cfg::DATABASE_URL(), String::from("postgres://user:pass@localhost:5432/test"));
|
assert_eq!(config::DATABASE_URL(), String::from("postgres://user:pass@localhost:5432/test"));
|
||||||
assert_eq!(cfg::APP:ARTICLE:PER_PAGE(), 15);
|
assert_eq!(config::APP:ARTICLE:PER_PAGE(), 15);
|
||||||
assert_eq!(cfg::FEATURE::NEW_MENU(), true);
|
assert_eq!(config::FEATURE::NEW_MENU(), true);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -112,6 +131,7 @@ cargo test
|
||||||
* [x] Add nested namespaces
|
* [x] Add nested namespaces
|
||||||
* [x] Support meta for namespaces
|
* [x] Support meta for namespaces
|
||||||
* [x] Support array type
|
* [x] Support array type
|
||||||
|
* [x] Rewrite to proc macro
|
||||||
* [ ] Support hashmap type
|
* [ ] Support hashmap type
|
||||||
* [ ] Support custom env type
|
* [ ] Support custom env type
|
||||||
* [ ] Common configuration for namespace variables
|
* [ ] Common configuration for namespace variables
|
||||||
|
@ -121,7 +141,6 @@ cargo test
|
||||||
|
|
||||||
* **default** - ["macro", "primitives", "static"]
|
* **default** - ["macro", "primitives", "static"]
|
||||||
* **macro** - Activates `config!` macros for easy configure web application.
|
* **macro** - Activates `config!` macros for easy configure web application.
|
||||||
* **static** - Add `static` option to `config!` macros (uses optional `lazy_static` package).
|
|
||||||
* **array** - Add EnvString impl for vector type (uses optional `serde_json` package).
|
* **array** - Add EnvString impl for vector type (uses optional `serde_json` package).
|
||||||
* **primitives** - Group for features: `numbers` and `bool`.
|
* **primitives** - Group for features: `numbers` and `bool`.
|
||||||
* **numbers** - Group for features: `int`, `uint` and `float`.
|
* **numbers** - Group for features: `int`, `uint` and `float`.
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use super::cfg;
|
use super::config;
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
use diesel::pg::PgConnection;
|
use diesel::pg::PgConnection;
|
||||||
|
|
||||||
pub fn establish_connection() -> PgConnection {
|
pub fn establish_connection() -> PgConnection {
|
||||||
let database_url = cfg::DATABASE_URL();
|
let database_url = config::DATABASE_URL();
|
||||||
PgConnection::establish(database_url)
|
PgConnection::establish(database_url)
|
||||||
.expect(&format!("Error connecting to {}", database_url))
|
.expect(&format!("Error connecting to {}", database_url))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate itconfig;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate diesel;
|
extern crate diesel;
|
||||||
|
|
||||||
mod db;
|
mod db;
|
||||||
mod models;
|
mod models;
|
||||||
mod schema;
|
mod schema;
|
||||||
|
|
||||||
|
use itconfig::config;
|
||||||
use dotenv::dotenv;
|
use dotenv::dotenv;
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
use crate::models::*;
|
use crate::models::*;
|
||||||
|
@ -19,7 +18,7 @@ config! {
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
dotenv().ok();
|
dotenv().ok();
|
||||||
cfg::init();
|
config::init();
|
||||||
|
|
||||||
let connection = db::establish_connection();
|
let connection = db::establish_connection();
|
||||||
let posts = get_posts(&connection);
|
let posts = get_posts(&connection);
|
||||||
|
|
|
@ -14,6 +14,7 @@ tokio = { version = "0.2", features = ["macros"] }
|
||||||
bytes = "0.5"
|
bytes = "0.5"
|
||||||
futures-util = { version = "0.3", default-features = false }
|
futures-util = { version = "0.3", default-features = false }
|
||||||
pretty_env_logger = "0.3"
|
pretty_env_logger = "0.3"
|
||||||
|
lazy_static = "1.4.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["static"]
|
default = ["static"]
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
#[macro_use]
|
use itconfig::config;
|
||||||
extern crate itconfig;
|
|
||||||
|
|
||||||
use bytes::buf::BufExt;
|
use bytes::buf::BufExt;
|
||||||
use futures_util::{stream, StreamExt};
|
use futures_util::{stream, StreamExt};
|
||||||
use hyper::client::HttpConnector;
|
use hyper::client::HttpConnector;
|
||||||
|
@ -41,7 +39,7 @@ const POST_DATA: &'static str = r#"{"original": "data"}"#;
|
||||||
async fn client_request_response(client: &Client<HttpConnector>) -> HyperResult<Response<Body>> {
|
async fn client_request_response(client: &Client<HttpConnector>) -> HyperResult<Response<Body>> {
|
||||||
let req = Request::builder()
|
let req = Request::builder()
|
||||||
.method(Method::POST)
|
.method(Method::POST)
|
||||||
.uri(cfg::HYPER::JSON_API_URL())
|
.uri(config::HYPER::JSON_API_URL())
|
||||||
.header(header::CONTENT_TYPE, "application/json")
|
.header(header::CONTENT_TYPE, "application/json")
|
||||||
.body(Body::from(POST_DATA))
|
.body(Body::from(POST_DATA))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -113,10 +111,10 @@ async fn response_examples(
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> HyperResult<()> {
|
async fn main() -> HyperResult<()> {
|
||||||
cfg::init();
|
config::init();
|
||||||
pretty_env_logger::init();
|
pretty_env_logger::init();
|
||||||
|
|
||||||
let addr = cfg::HYPER::HOST().parse().unwrap();
|
let addr = config::HYPER::HOST().parse().unwrap();
|
||||||
|
|
||||||
// Share a `Client` with all `Service`s
|
// Share a `Client` with all `Service`s
|
||||||
let client = Client::new();
|
let client = Client::new();
|
||||||
|
|
|
@ -2,9 +2,8 @@
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate rocket;
|
extern crate rocket;
|
||||||
#[macro_use]
|
|
||||||
extern crate itconfig;
|
|
||||||
|
|
||||||
|
use itconfig::config;
|
||||||
|
|
||||||
config! {
|
config! {
|
||||||
ROCKET {
|
ROCKET {
|
||||||
|
@ -21,9 +20,9 @@ fn index() -> &'static str {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
cfg::init();
|
config::init();
|
||||||
|
|
||||||
rocket::ignite()
|
rocket::ignite()
|
||||||
.mount(cfg::ROCKET::BASE_URL(), routes![index])
|
.mount(config::ROCKET::BASE_URL(), routes![index])
|
||||||
.launch();
|
.launch();
|
||||||
}
|
}
|
30
itconfig-macro/Cargo.toml
Normal file
30
itconfig-macro/Cargo.toml
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
[package]
|
||||||
|
name = "itconfig-macro"
|
||||||
|
version = "1.0.0"
|
||||||
|
authors = ["Dmitriy Pleshevskiy <dmitriy@ideascup.me>"]
|
||||||
|
description = "Easy build a configs from environment variables and use it in globally."
|
||||||
|
categories = ["config", "web-programming"]
|
||||||
|
keywords = ["config", "env", "configuration", "environment", "macro"]
|
||||||
|
edition = "2018"
|
||||||
|
license = "MIT"
|
||||||
|
repository = "https://github.com/icetemple/itconfig-rs"
|
||||||
|
homepage = "https://github.com/icetemple/itconfig-rs"
|
||||||
|
documentation = "https://docs.rs/itconfig"
|
||||||
|
readme = "../itconfig/README.md"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
[lib]
|
||||||
|
proc-macro = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
syn = "1.0.16"
|
||||||
|
quote = "1.0.3"
|
||||||
|
proc-macro2 = "1.0.9"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
itconfig = { path = "../itconfig" }
|
||||||
|
lazy_static = "1.4.0"
|
||||||
|
|
||||||
|
[badges]
|
||||||
|
travis-ci = { repository = "icetemple/itconfig-rs" }
|
||||||
|
maintenance = { status = "actively-developed" }
|
30
itconfig-macro/src/ast.rs
Normal file
30
itconfig-macro/src/ast.rs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
use proc_macro2::TokenStream as TokenStream2;
|
||||||
|
use syn::{Type, Expr, Ident, Attribute};
|
||||||
|
|
||||||
|
|
||||||
|
pub struct RootNamespace {
|
||||||
|
pub name: Option<Ident>,
|
||||||
|
pub variables: Vec<Variable>,
|
||||||
|
pub namespaces: Vec<Namespace>,
|
||||||
|
pub meta: Vec<Attribute>,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub struct Namespace {
|
||||||
|
pub name: Ident,
|
||||||
|
pub variables: Vec<Variable>,
|
||||||
|
pub namespaces: Vec<Namespace>,
|
||||||
|
pub env_prefix: Option<String>,
|
||||||
|
pub meta: Vec<Attribute>,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub struct Variable {
|
||||||
|
pub is_static: bool,
|
||||||
|
pub name: Ident,
|
||||||
|
pub ty: Type,
|
||||||
|
pub initial: Option<Expr>,
|
||||||
|
pub concat_parts: Option<Vec<TokenStream2>>,
|
||||||
|
pub env_name: Option<String>,
|
||||||
|
pub meta: Vec<Attribute>,
|
||||||
|
}
|
170
itconfig-macro/src/expand.rs
Normal file
170
itconfig-macro/src/expand.rs
Normal file
|
@ -0,0 +1,170 @@
|
||||||
|
use crate::ast::*;
|
||||||
|
use quote::{quote, ToTokens, TokenStreamExt};
|
||||||
|
use proc_macro2::TokenStream as TokenStream2;
|
||||||
|
|
||||||
|
|
||||||
|
fn vec_to_token_stream_2<T>(input: &Vec<T>) -> Vec<TokenStream2>
|
||||||
|
where T: ToTokens
|
||||||
|
{
|
||||||
|
input.iter()
|
||||||
|
.map(|ns| ns.into_token_stream())
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl ToTokens for RootNamespace {
|
||||||
|
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
||||||
|
let name = &self.name;
|
||||||
|
let variables = vec_to_token_stream_2(&self.variables);
|
||||||
|
let namespaces = vec_to_token_stream_2(&self.namespaces);
|
||||||
|
|
||||||
|
let init_variables = self.variables.iter()
|
||||||
|
.map(|var| {
|
||||||
|
let name = &var.name;
|
||||||
|
let var_meta = vec_to_token_stream_2(&var.meta);
|
||||||
|
|
||||||
|
quote!(
|
||||||
|
#(#var_meta)*
|
||||||
|
#name();
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect::<Vec<TokenStream2>>();
|
||||||
|
let init_namespaces = self.namespaces.iter()
|
||||||
|
.map(|ns| {
|
||||||
|
let name = &ns.name;
|
||||||
|
let ns_meta = vec_to_token_stream_2(&ns.meta);
|
||||||
|
|
||||||
|
quote!(
|
||||||
|
#(#ns_meta)*
|
||||||
|
#name::init();
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect::<Vec<TokenStream2>>();
|
||||||
|
|
||||||
|
let inner_meta: Vec<TokenStream2> = if name.is_none() {
|
||||||
|
vec![]
|
||||||
|
} else if self.meta.is_empty() {
|
||||||
|
vec![quote!(#![allow(non_snake_case)])]
|
||||||
|
} else {
|
||||||
|
vec_to_token_stream_2(&self.meta)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
let inner_rules = quote! {
|
||||||
|
#(#inner_meta)*
|
||||||
|
|
||||||
|
#(#namespaces)*
|
||||||
|
|
||||||
|
#(#variables)*
|
||||||
|
|
||||||
|
pub fn init() {
|
||||||
|
#(#init_variables)*
|
||||||
|
#(#init_namespaces)*
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
tokens.append_all(
|
||||||
|
match self.name.as_ref() {
|
||||||
|
None => inner_rules,
|
||||||
|
Some(name) => quote! {
|
||||||
|
pub mod #name {
|
||||||
|
#inner_rules
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl ToTokens for Namespace {
|
||||||
|
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
||||||
|
let name = &self.name;
|
||||||
|
let variables = vec_to_token_stream_2(&self.variables);
|
||||||
|
let namespaces = vec_to_token_stream_2(&self.namespaces);
|
||||||
|
let meta = vec_to_token_stream_2(&self.meta);
|
||||||
|
|
||||||
|
let init_variables = self.variables.iter()
|
||||||
|
.map(|var| {
|
||||||
|
let name = &var.name;
|
||||||
|
let var_meta = vec_to_token_stream_2(&var.meta);
|
||||||
|
|
||||||
|
quote!(
|
||||||
|
#(#var_meta)*
|
||||||
|
#name();
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect::<Vec<TokenStream2>>();
|
||||||
|
let init_namespaces = self.namespaces.iter()
|
||||||
|
.map(|ns| {
|
||||||
|
let name = &ns.name;
|
||||||
|
let ns_meta = vec_to_token_stream_2(&ns.meta);
|
||||||
|
|
||||||
|
quote!(
|
||||||
|
#(#ns_meta)*
|
||||||
|
#name::init();
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect::<Vec<TokenStream2>>();
|
||||||
|
|
||||||
|
tokens.append_all(quote!(
|
||||||
|
#(#meta)*
|
||||||
|
pub mod #name {
|
||||||
|
#(#namespaces)*
|
||||||
|
|
||||||
|
#(#variables)*
|
||||||
|
|
||||||
|
pub fn init() {
|
||||||
|
#(#init_variables)*
|
||||||
|
#(#init_namespaces)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl ToTokens for Variable {
|
||||||
|
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
||||||
|
let ty = &self.ty;
|
||||||
|
let name = &self.name;
|
||||||
|
let env_name = &self.env_name.clone()
|
||||||
|
.unwrap_or(name.to_string().to_uppercase());
|
||||||
|
let meta = vec_to_token_stream_2(&self.meta);
|
||||||
|
|
||||||
|
let get_variable: TokenStream2 = if self.concat_parts.is_some() {
|
||||||
|
let concat_parts = self.concat_parts.as_ref().unwrap();
|
||||||
|
quote! {{
|
||||||
|
let value_parts: Vec<String> = vec!(#(#concat_parts),*);
|
||||||
|
let value = value_parts.join("");
|
||||||
|
::std::env::set_var(#env_name, value.as_str());
|
||||||
|
value
|
||||||
|
}}
|
||||||
|
} else if self.initial.is_some() {
|
||||||
|
let initial = self.initial.as_ref().unwrap();
|
||||||
|
quote!(::itconfig::get_env_or_set_default(#env_name, #initial))
|
||||||
|
} else {
|
||||||
|
quote!(::itconfig::get_env_or_panic(#env_name))
|
||||||
|
};
|
||||||
|
|
||||||
|
if self.is_static {
|
||||||
|
tokens.append_all(quote!(
|
||||||
|
#(#meta)*
|
||||||
|
pub fn #name() -> #ty {
|
||||||
|
::lazy_static::lazy_static! {
|
||||||
|
static ref #name: #ty = #get_variable;
|
||||||
|
}
|
||||||
|
|
||||||
|
(*#name).clone()
|
||||||
|
}
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
tokens.append_all(quote!(
|
||||||
|
#(#meta)*
|
||||||
|
pub fn #name() -> #ty {
|
||||||
|
#get_variable
|
||||||
|
}
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
338
itconfig-macro/src/lib.rs
Normal file
338
itconfig-macro/src/lib.rs
Normal file
|
@ -0,0 +1,338 @@
|
||||||
|
#![recursion_limit = "256"]
|
||||||
|
|
||||||
|
mod ast;
|
||||||
|
mod parse;
|
||||||
|
mod expand;
|
||||||
|
|
||||||
|
extern crate proc_macro;
|
||||||
|
extern crate proc_macro2;
|
||||||
|
use self::proc_macro::TokenStream;
|
||||||
|
use quote::ToTokens;
|
||||||
|
use syn::parse_macro_input;
|
||||||
|
use ast::RootNamespace;
|
||||||
|
|
||||||
|
|
||||||
|
/// ### _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()
|
||||||
|
}
|
262
itconfig-macro/src/parse.rs
Normal file
262
itconfig-macro/src/parse.rs
Normal file
|
@ -0,0 +1,262 @@
|
||||||
|
use crate::ast::*;
|
||||||
|
use syn::parse::{Parse, ParseStream, Result, ParseBuffer};
|
||||||
|
use syn::token::{FatArrow, Comma, Colon, Brace, Lt};
|
||||||
|
use syn::{braced, parenthesized, Type, Expr, Token, Lit, Attribute, Meta, MetaNameValue, Error, parse_str, MetaList, NestedMeta};
|
||||||
|
use proc_macro2::{Ident, Span, TokenStream as TokenStream2};
|
||||||
|
use syn::ext::IdentExt;
|
||||||
|
use quote::quote;
|
||||||
|
|
||||||
|
fn fill_env_prefix(
|
||||||
|
prefix: String
|
||||||
|
) -> Box<dyn Fn(Namespace) -> Namespace> {
|
||||||
|
Box::new(move |mut ns| {
|
||||||
|
let env_prefix = match &ns.env_prefix {
|
||||||
|
None => {
|
||||||
|
let env_prefix = format!(
|
||||||
|
"{}{}_",
|
||||||
|
prefix,
|
||||||
|
ns.name.clone().to_string()
|
||||||
|
);
|
||||||
|
ns.env_prefix = Some(env_prefix.clone());
|
||||||
|
env_prefix
|
||||||
|
}
|
||||||
|
Some(env_prefix) => {
|
||||||
|
env_prefix.clone()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if !ns.namespaces.is_empty() {
|
||||||
|
ns.namespaces = ns.namespaces.into_iter()
|
||||||
|
.map(fill_env_prefix(ns.env_prefix.clone().unwrap()))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ns.variables.is_empty() {
|
||||||
|
ns.variables = ns.variables.into_iter()
|
||||||
|
.map(|mut var| {
|
||||||
|
if var.env_name.is_none() {
|
||||||
|
var.env_name = Some(
|
||||||
|
format!("{}{}", env_prefix.clone(), &var.name.to_string())
|
||||||
|
.to_uppercase()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
var
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
ns
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_namespace_content(
|
||||||
|
input: &ParseBuffer,
|
||||||
|
variables: &mut Vec<Variable>,
|
||||||
|
namespaces: &mut Vec<Namespace>,
|
||||||
|
) -> Result<()> {
|
||||||
|
let attributes: Vec<Attribute> = input.call(Attribute::parse_outer)?;
|
||||||
|
if input.peek2(Brace) {
|
||||||
|
let mut namespace: Namespace = input.parse()?;
|
||||||
|
|
||||||
|
for attr in attributes {
|
||||||
|
if attr.path.is_ident("env_prefix") {
|
||||||
|
namespace.env_prefix = parse_attribute(attr, "env_prefix", &namespace.env_prefix)?;
|
||||||
|
} else {
|
||||||
|
namespace.meta.push(attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespaces.push(namespace);
|
||||||
|
} else {
|
||||||
|
let mut variable: Variable = input.parse()?;
|
||||||
|
|
||||||
|
for attr in attributes {
|
||||||
|
if attr.path.is_ident("env_name") {
|
||||||
|
variable.env_name = parse_attribute(attr, "env_name", &variable.env_name)?;
|
||||||
|
} else {
|
||||||
|
variable.meta.push(attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
variables.push(variable);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn parse_attribute(attr: Attribute, name: &'static str, var: &Option<String>) -> Result<Option<String>> {
|
||||||
|
if var.is_some() {
|
||||||
|
let message = format!("You cannot use {} meta twice", &name);
|
||||||
|
return Err(Error::new_spanned(attr, message));
|
||||||
|
}
|
||||||
|
|
||||||
|
match attr.parse_meta()? {
|
||||||
|
Meta::NameValue(MetaNameValue { lit: Lit::Str(lit_str), .. }) => {
|
||||||
|
Ok(Some(lit_str.value()))
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let message = format!("expected #[{} = \"...\"]", &name);
|
||||||
|
Err(Error::new_spanned(attr, message))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Parse for RootNamespace {
|
||||||
|
fn parse(input: ParseStream) -> Result<Self> {
|
||||||
|
let mut name: Option<Ident> = None;
|
||||||
|
let mut with_module = true;
|
||||||
|
let mut meta: Vec<Attribute> = vec![];
|
||||||
|
|
||||||
|
let attributes: Vec<Attribute> = input.call(Attribute::parse_inner)?;
|
||||||
|
for attr in attributes {
|
||||||
|
if attr.path.is_ident("config") {
|
||||||
|
match attr.parse_meta()? {
|
||||||
|
Meta::List(MetaList { nested, .. }) => {
|
||||||
|
let message = format!("expected #[config(name = \"...\")] or #[config(unwrap)]");
|
||||||
|
match nested.first().unwrap() {
|
||||||
|
NestedMeta::Meta(Meta::NameValue(MetaNameValue { path, lit: Lit::Str(lit_str), .. })) => {
|
||||||
|
if path.is_ident("name") {
|
||||||
|
name = Some(Ident::new(&lit_str.value(), Span::call_site()));
|
||||||
|
} else {
|
||||||
|
Err(Error::new_spanned(attr, message))?;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
NestedMeta::Meta(Meta::Path(path)) => {
|
||||||
|
if path.is_ident("unwrap") {
|
||||||
|
name = None;
|
||||||
|
with_module = false;
|
||||||
|
} else {
|
||||||
|
Err(Error::new_spanned(attr, message))?;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
Err(Error::new_spanned(attr, message))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let message = format!("expected #[config(...)]");
|
||||||
|
Err(Error::new_spanned(attr, message))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
meta.push(attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if with_module && name.is_none() {
|
||||||
|
name = Some(Ident::new("config", Span::call_site()));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut variables: Vec<Variable> = vec![];
|
||||||
|
let mut namespaces: Vec<Namespace> = vec![];
|
||||||
|
while !input.is_empty() {
|
||||||
|
parse_namespace_content(&input, &mut variables, &mut namespaces)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let prefix = String::new();
|
||||||
|
let namespaces = namespaces.into_iter()
|
||||||
|
.map(fill_env_prefix(prefix.clone()))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Ok(RootNamespace {
|
||||||
|
name,
|
||||||
|
variables,
|
||||||
|
namespaces,
|
||||||
|
meta,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Parse for Namespace {
|
||||||
|
fn parse(input: ParseStream) -> Result<Self> {
|
||||||
|
let name: Ident = input.parse()?;
|
||||||
|
let mut variables: Vec<Variable> = vec![];
|
||||||
|
let mut namespaces: Vec<Namespace> = vec![];
|
||||||
|
|
||||||
|
let content;
|
||||||
|
braced!(content in input);
|
||||||
|
while !content.is_empty() {
|
||||||
|
parse_namespace_content(&content, &mut variables, &mut namespaces)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
input.parse::<Comma>().ok();
|
||||||
|
|
||||||
|
Ok(Namespace {
|
||||||
|
name,
|
||||||
|
variables,
|
||||||
|
namespaces,
|
||||||
|
env_prefix: None,
|
||||||
|
meta: vec![],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Parse for Variable {
|
||||||
|
fn parse(input: ParseStream) -> Result<Self> {
|
||||||
|
let is_static = input.parse::<Token![static]>().ok().is_some();
|
||||||
|
let name: Ident = input.parse()?;
|
||||||
|
|
||||||
|
let is_concat = input.peek(Lt);
|
||||||
|
let mut concat_parts = None;
|
||||||
|
let mut initial = None;
|
||||||
|
|
||||||
|
let ty: Type = if is_concat {
|
||||||
|
parse_str("String")?
|
||||||
|
} else if input.peek(Colon) {
|
||||||
|
input.parse::<Colon>()?;
|
||||||
|
input.parse()?
|
||||||
|
} else {
|
||||||
|
parse_str("&'static str")?
|
||||||
|
};
|
||||||
|
|
||||||
|
if is_concat {
|
||||||
|
input.parse::<Lt>()?;
|
||||||
|
|
||||||
|
let content;
|
||||||
|
parenthesized!(content in input);
|
||||||
|
|
||||||
|
let mut tmp_vec: Vec<TokenStream2> = vec![];
|
||||||
|
while !content.is_empty() {
|
||||||
|
if content.peek(Ident::peek_any) {
|
||||||
|
let concat_var: Variable = content.parse()?;
|
||||||
|
let name = &concat_var.name;
|
||||||
|
let env_name = &concat_var.env_name.clone().unwrap_or(name.to_string());
|
||||||
|
|
||||||
|
let get_variable = if concat_var.initial.is_some() {
|
||||||
|
let initial = concat_var.initial.as_ref().unwrap();
|
||||||
|
quote!(::itconfig::get_env_or_set_default(#env_name, #initial))
|
||||||
|
} else {
|
||||||
|
quote!(::itconfig::get_env_or_panic(#env_name))
|
||||||
|
};
|
||||||
|
|
||||||
|
tmp_vec.push(get_variable);
|
||||||
|
} else {
|
||||||
|
let part: Lit = content.parse()?;
|
||||||
|
tmp_vec.push(quote!(#part.to_string()));
|
||||||
|
}
|
||||||
|
content.parse::<Comma>().ok();
|
||||||
|
}
|
||||||
|
concat_parts = Some(tmp_vec);
|
||||||
|
} else {
|
||||||
|
initial = input.parse::<FatArrow>().ok()
|
||||||
|
.and_then(|_| input.parse::<Expr>().ok());
|
||||||
|
};
|
||||||
|
|
||||||
|
input.parse::<Comma>().ok();
|
||||||
|
|
||||||
|
Ok(Variable {
|
||||||
|
is_static,
|
||||||
|
name,
|
||||||
|
ty,
|
||||||
|
initial,
|
||||||
|
concat_parts,
|
||||||
|
env_name: None,
|
||||||
|
meta: vec![],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,7 +9,7 @@ publish = false
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
itconfig = { path = '../itconfig' }
|
itconfig = { path = '../itconfig', features = ["macro"] }
|
||||||
criterion = "0.3.1"
|
criterion = "0.3.1"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
|
|
||||||
|
|
|
@ -59,22 +59,22 @@ fn source_macro_vs_lazy_macro(c: &mut Criterion) {
|
||||||
|
|
||||||
let source = Fun::new("source", |b, _| {
|
let source = Fun::new("source", |b, _| {
|
||||||
b.iter(move || {
|
b.iter(move || {
|
||||||
assert_eq!(cfg::TEST(), "test");
|
assert_eq!(config::TEST(), "test");
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
let lazy = Fun::new("lazy", |b, _| {
|
let lazy = Fun::new("lazy", |b, _| {
|
||||||
b.iter(move || {
|
b.iter(move || {
|
||||||
assert_eq!(cfg::LAZY_TEST(), "test");
|
assert_eq!(config::LAZY_TEST(), "test");
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
let source_with_default = Fun::new("source_with_default", |b, _| {
|
let source_with_default = Fun::new("source_with_default", |b, _| {
|
||||||
b.iter(move || {
|
b.iter(move || {
|
||||||
assert_eq!(cfg::TEST_WITH_DEFAULT(), "default");
|
assert_eq!(config::TEST_WITH_DEFAULT(), "default");
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
let lazy_with_default = Fun::new("lazy_with_default", |b, _| {
|
let lazy_with_default = Fun::new("lazy_with_default", |b, _| {
|
||||||
b.iter(move || {
|
b.iter(move || {
|
||||||
assert_eq!(cfg::LAZY_TEST_WITH_DEFAULT(), "default");
|
assert_eq!(config::LAZY_TEST_WITH_DEFAULT(), "default");
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,118 +1,114 @@
|
||||||
use std::env;
|
mod test_case_1 {
|
||||||
use std::env::VarError;
|
itconfig::config! {
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate itconfig;
|
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[should_panic(expected = "Environment variable \"MISS_VARIABLE\" is missing")]
|
|
||||||
fn should_panic_if_miss_env_variable() {
|
|
||||||
config! {
|
|
||||||
MISS_VARIABLE: bool,
|
MISS_VARIABLE: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg::init();
|
#[test]
|
||||||
|
#[should_panic(expected = "Environment variable \"MISS_VARIABLE\" is missing")]
|
||||||
|
fn should_panic_if_miss_env_variable() {
|
||||||
|
config::init();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
mod test_case_2 {
|
||||||
fn one_variable() {
|
use std::env;
|
||||||
env::set_var("DEBUG", "t");
|
|
||||||
|
|
||||||
config! {
|
itconfig::config! {
|
||||||
DEBUG: bool,
|
DEBUG: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg::init();
|
#[test]
|
||||||
assert_eq!(cfg::DEBUG(), true);
|
fn one_variable() {
|
||||||
env::remove_var("DEBUG");
|
env::set_var("DEBUG", "t");
|
||||||
|
|
||||||
|
config::init();
|
||||||
|
assert_eq!(config::DEBUG(), true);
|
||||||
|
env::remove_var("DEBUG");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn one_variable_with_default_value() {
|
mod test_case_3 {
|
||||||
config! {
|
itconfig::config! {
|
||||||
DEBUG: bool => true,
|
DEBUG: bool => true,
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg::init();
|
#[test]
|
||||||
assert_eq!(cfg::DEBUG(), true);
|
fn one_variable_with_default_value() {
|
||||||
|
config::init();
|
||||||
|
assert_eq!(config::DEBUG(), true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
mod test_case_4 {
|
||||||
fn few_variables_with_default_value() {
|
itconfig::config! {
|
||||||
config! {
|
|
||||||
FOO: bool => true,
|
FOO: bool => true,
|
||||||
BAR: bool => false,
|
BAR: bool => false,
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg::init();
|
#[test]
|
||||||
assert_eq!(cfg::FOO(), true);
|
fn few_variables_with_default_value() {
|
||||||
assert_eq!(cfg::BAR(), false);
|
config::init();
|
||||||
|
assert_eq!(config::FOO(), true);
|
||||||
|
assert_eq!(config::BAR(), false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
mod test_case_5 {
|
||||||
fn different_types_with_default_value() {
|
itconfig::config! {
|
||||||
config! {
|
|
||||||
NUMBER: i32 => 30,
|
NUMBER: i32 => 30,
|
||||||
BOOL: bool => true,
|
BOOL: bool => true,
|
||||||
STR: String => "str",
|
STR: String => "str",
|
||||||
STRING: String => "string".to_string(),
|
STRING: String => "string".to_string(),
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg::init();
|
#[test]
|
||||||
assert_eq!(cfg::NUMBER(), 30);
|
fn different_types_with_default_value() {
|
||||||
assert_eq!(cfg::BOOL(), true);
|
config::init();
|
||||||
assert_eq!(cfg::STR(), "str".to_string());
|
assert_eq!(config::NUMBER(), 30);
|
||||||
assert_eq!(cfg::STRING(), "string".to_string());
|
assert_eq!(config::BOOL(), true);
|
||||||
|
assert_eq!(config::STR(), "str".to_string());
|
||||||
|
assert_eq!(config::STRING(), "string".to_string());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
mod test_case_6 {
|
||||||
fn convert_bool_type_value_from_env() {
|
use std::env;
|
||||||
env::set_var("T_BOOL", "t");
|
|
||||||
env::set_var("TRUE_BOOL", "true");
|
|
||||||
env::set_var("NUM_BOOL", "1");
|
|
||||||
env::set_var("ON_BOOL", "on");
|
|
||||||
env::set_var("CAMEL_CASE", "True");
|
|
||||||
env::set_var("FALSE_BOOL", "false");
|
|
||||||
|
|
||||||
config! {
|
itconfig::config! {
|
||||||
T_BOOL: bool,
|
T_BOOL: bool,
|
||||||
TRUE_BOOL: bool,
|
TRUE_BOOL: bool,
|
||||||
NUM_BOOL: bool,
|
NUM_BOOL: bool,
|
||||||
ON_BOOL: bool,
|
ON_BOOL: bool,
|
||||||
CAMEL_CASE: bool,
|
CAMEL_CASE: bool,
|
||||||
FALSE_BOOL: bool,
|
FALSE_BOOL: bool,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg::init();
|
#[test]
|
||||||
assert_eq!(cfg::T_BOOL(), true);
|
fn convert_bool_type_value_from_env() {
|
||||||
assert_eq!(cfg::TRUE_BOOL(), true);
|
env::set_var("T_BOOL", "t");
|
||||||
assert_eq!(cfg::NUM_BOOL(), true);
|
env::set_var("TRUE_BOOL", "true");
|
||||||
assert_eq!(cfg::ON_BOOL(), true);
|
env::set_var("NUM_BOOL", "1");
|
||||||
assert_eq!(cfg::CAMEL_CASE(), true);
|
env::set_var("ON_BOOL", "on");
|
||||||
assert_eq!(cfg::FALSE_BOOL(), false);
|
env::set_var("CAMEL_CASE", "True");
|
||||||
|
env::set_var("FALSE_BOOL", "false");
|
||||||
|
|
||||||
|
config::init();
|
||||||
|
assert_eq!(config::T_BOOL(), true);
|
||||||
|
assert_eq!(config::TRUE_BOOL(), true);
|
||||||
|
assert_eq!(config::NUM_BOOL(), true);
|
||||||
|
assert_eq!(config::ON_BOOL(), true);
|
||||||
|
assert_eq!(config::CAMEL_CASE(), true);
|
||||||
|
assert_eq!(config::FALSE_BOOL(), false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn convert_number_type_value_from_env() {
|
|
||||||
env::set_var("I8", "10");
|
|
||||||
env::set_var("I16", "10");
|
|
||||||
env::set_var("I32", "10");
|
|
||||||
env::set_var("I64", "10");
|
|
||||||
env::set_var("I128", "10");
|
|
||||||
env::set_var("ISIZE","10");
|
|
||||||
env::set_var("U8", "10");
|
|
||||||
env::set_var("U16", "10");
|
|
||||||
env::set_var("U32", "10");
|
|
||||||
env::set_var("U64", "10");
|
|
||||||
env::set_var("U128", "10");
|
|
||||||
env::set_var("USIZE","10");
|
|
||||||
env::set_var("F32", "10");
|
|
||||||
env::set_var("F64","10");
|
|
||||||
|
|
||||||
config! {
|
mod test_case_7 {
|
||||||
|
use std::env;
|
||||||
|
|
||||||
|
itconfig::config! {
|
||||||
I8: i8,
|
I8: i8,
|
||||||
I16: i16,
|
I16: i16,
|
||||||
I32: i32,
|
I32: i32,
|
||||||
|
@ -129,40 +125,59 @@ fn convert_number_type_value_from_env() {
|
||||||
F64: f64,
|
F64: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg::init();
|
#[test]
|
||||||
assert_eq!(cfg::I8(), 10);
|
fn convert_number_type_value_from_env() {
|
||||||
assert_eq!(cfg::I16(), 10);
|
env::set_var("I8", "10");
|
||||||
assert_eq!(cfg::I32(), 10);
|
env::set_var("I16", "10");
|
||||||
assert_eq!(cfg::I64(), 10);
|
env::set_var("I32", "10");
|
||||||
assert_eq!(cfg::ISIZE(), 10);
|
env::set_var("I64", "10");
|
||||||
assert_eq!(cfg::U8(), 10);
|
env::set_var("I128", "10");
|
||||||
assert_eq!(cfg::U16(), 10);
|
env::set_var("ISIZE", "10");
|
||||||
assert_eq!(cfg::U32(), 10);
|
env::set_var("U8", "10");
|
||||||
assert_eq!(cfg::U64(), 10);
|
env::set_var("U16", "10");
|
||||||
assert_eq!(cfg::USIZE(), 10);
|
env::set_var("U32", "10");
|
||||||
assert_eq!(cfg::F32(), 10.0);
|
env::set_var("U64", "10");
|
||||||
assert_eq!(cfg::F64(), 10.0);
|
env::set_var("U128", "10");
|
||||||
|
env::set_var("USIZE", "10");
|
||||||
|
env::set_var("F32", "10");
|
||||||
|
env::set_var("F64", "10");
|
||||||
|
|
||||||
|
config::init();
|
||||||
|
assert_eq!(config::I8(), 10);
|
||||||
|
assert_eq!(config::I16(), 10);
|
||||||
|
assert_eq!(config::I32(), 10);
|
||||||
|
assert_eq!(config::I64(), 10);
|
||||||
|
assert_eq!(config::ISIZE(), 10);
|
||||||
|
assert_eq!(config::U8(), 10);
|
||||||
|
assert_eq!(config::U16(), 10);
|
||||||
|
assert_eq!(config::U32(), 10);
|
||||||
|
assert_eq!(config::U64(), 10);
|
||||||
|
assert_eq!(config::USIZE(), 10);
|
||||||
|
assert_eq!(config::F32(), 10.0);
|
||||||
|
assert_eq!(config::F64(), 10.0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
mod test_case_8 {
|
||||||
fn change_configuration_module_name() {
|
itconfig::config! {
|
||||||
config! {
|
#![config(name = "custom_config_name")]
|
||||||
#![mod_name = custom_config_name]
|
|
||||||
|
|
||||||
DEBUG: bool => true,
|
DEBUG: bool => true,
|
||||||
}
|
}
|
||||||
|
|
||||||
custom_config_name::init();
|
#[test]
|
||||||
assert_eq!(custom_config_name::DEBUG(), true);
|
fn change_configuration_module_name() {
|
||||||
|
custom_config_name::init();
|
||||||
|
assert_eq!(custom_config_name::DEBUG(), true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
mod test_case_9 {
|
||||||
fn configuration_with_namespace() {
|
use std::env;
|
||||||
env::set_var("DB_HOST", "t");
|
|
||||||
|
|
||||||
config! {
|
itconfig::config! {
|
||||||
DEBUG: bool => true,
|
DEBUG: bool => true,
|
||||||
|
|
||||||
DB {
|
DB {
|
||||||
|
@ -174,14 +189,18 @@ fn configuration_with_namespace() {
|
||||||
APP {}
|
APP {}
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg::init();
|
#[test]
|
||||||
assert_eq!(cfg::DEBUG(), true);
|
fn configuration_with_namespace() {
|
||||||
assert_eq!(cfg::DB::HOST(), true);
|
env::set_var("DB_HOST", "t");
|
||||||
|
|
||||||
|
config::init();
|
||||||
|
assert_eq!(config::DEBUG(), true);
|
||||||
|
assert_eq!(config::DB::HOST(), true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
mod test_case_10 {
|
||||||
fn configuration_with_nested_namespaces() {
|
itconfig::config! {
|
||||||
config! {
|
|
||||||
FIRST {
|
FIRST {
|
||||||
SECOND {
|
SECOND {
|
||||||
THIRD {
|
THIRD {
|
||||||
|
@ -191,14 +210,16 @@ fn configuration_with_nested_namespaces() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg::init();
|
#[test]
|
||||||
assert_eq!(cfg::FIRST::SECOND::THIRD::FOO(), 50);
|
fn configuration_with_nested_namespaces() {
|
||||||
|
config::init();
|
||||||
|
assert_eq!(config::FIRST::SECOND::THIRD::FOO(), 50);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "meta_namespace")]
|
|
||||||
#[test]
|
mod test_case_11 {
|
||||||
fn configuration_namespaces_with_custom_meta() {
|
itconfig::config! {
|
||||||
config! {
|
|
||||||
FIRST {
|
FIRST {
|
||||||
#[cfg(feature = "meta_namespace")]
|
#[cfg(feature = "meta_namespace")]
|
||||||
SECOND {
|
SECOND {
|
||||||
|
@ -209,16 +230,19 @@ fn configuration_namespaces_with_custom_meta() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg::init();
|
#[cfg(feature = "meta_namespace")]
|
||||||
assert_eq!(cfg::FIRST::SECOND::THIRD::FOO(), 50);
|
#[test]
|
||||||
|
fn configuration_namespaces_with_custom_meta() {
|
||||||
|
config::init();
|
||||||
|
assert_eq!(config::FIRST::SECOND::THIRD::FOO(), 50);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn configuration_variables_and_namespace_in_lowercase() {
|
|
||||||
env::set_var("TESTING", "t");
|
|
||||||
env::set_var("NAMESPACE_FOO", "t");
|
|
||||||
|
|
||||||
config! {
|
mod test_case_12 {
|
||||||
|
use std::env;
|
||||||
|
|
||||||
|
itconfig::config! {
|
||||||
testing: bool,
|
testing: bool,
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -226,17 +250,22 @@ fn configuration_variables_and_namespace_in_lowercase() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg::init();
|
#[test]
|
||||||
assert_eq!(cfg::testing(), true);
|
fn configuration_variables_and_namespace_in_lowercase() {
|
||||||
assert_eq!(cfg::namespace::foo(), true);
|
env::set_var("TESTING", "t");
|
||||||
|
env::set_var("NAMESPACE_FOO", "t");
|
||||||
|
|
||||||
|
config::init();
|
||||||
|
assert_eq!(config::testing(), true);
|
||||||
|
assert_eq!(config::namespace::foo(), true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
mod test_case_13 {
|
||||||
fn custom_environment_name_for_variable() {
|
use std::env;
|
||||||
env::set_var("MY_CUSTOM_NAME", "95");
|
|
||||||
|
|
||||||
config! {
|
itconfig::config! {
|
||||||
#[env_name = "MY_CUSTOM_NAME"]
|
#[env_name = "MY_CUSTOM_NAME"]
|
||||||
PER_PAGE: i32,
|
PER_PAGE: i32,
|
||||||
|
|
||||||
|
@ -246,16 +275,21 @@ fn custom_environment_name_for_variable() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg::init();
|
#[test]
|
||||||
assert_eq!(cfg::PER_PAGE(), 95);
|
fn custom_environment_name_for_variable() {
|
||||||
assert_eq!(cfg::APP::RECIPES_PER_PAGE(), 95);
|
env::set_var("MY_CUSTOM_NAME", "95");
|
||||||
|
|
||||||
|
config::init();
|
||||||
|
assert_eq!(config::PER_PAGE(), 95);
|
||||||
|
assert_eq!(config::APP::RECIPES_PER_PAGE(), 95);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn stranger_meta_data() {
|
|
||||||
env::set_var("MY_CUSTOM_NAME", "95");
|
|
||||||
|
|
||||||
config! {
|
mod test_case_14 {
|
||||||
|
use std::env;
|
||||||
|
|
||||||
|
itconfig::config! {
|
||||||
#[cfg(feature = "postgres")]
|
#[cfg(feature = "postgres")]
|
||||||
#[env_name = "MY_CUSTOM_NAME"]
|
#[env_name = "MY_CUSTOM_NAME"]
|
||||||
DATABASE_URL: String,
|
DATABASE_URL: String,
|
||||||
|
@ -265,40 +299,47 @@ fn stranger_meta_data() {
|
||||||
DATABASE_URL: i32,
|
DATABASE_URL: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg::init();
|
#[test]
|
||||||
#[cfg(not(feature = "postgres"))]
|
fn stranger_meta_data() {
|
||||||
assert_eq!(cfg::DATABASE_URL(), 95);
|
env::set_var("MY_CUSTOM_NAME", "95");
|
||||||
|
|
||||||
#[cfg(feature = "postgres")]
|
config::init();
|
||||||
assert_eq!(cfg::DATABASE_URL(), "95");
|
#[cfg(not(feature = "postgres"))]
|
||||||
|
assert_eq!(config::DATABASE_URL(), 95);
|
||||||
|
|
||||||
|
#[cfg(feature = "postgres")]
|
||||||
|
assert_eq!(config::DATABASE_URL(), "95");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn setting_default_env_variable() {
|
mod test_case_15 {
|
||||||
config! {
|
use std::env;
|
||||||
|
|
||||||
|
itconfig::config! {
|
||||||
DEFAULT_ENV_STRING: String => "localhost",
|
DEFAULT_ENV_STRING: String => "localhost",
|
||||||
DEFAULT_ENV_BOOLEAN: bool => true,
|
DEFAULT_ENV_BOOLEAN: bool => true,
|
||||||
DEFAULT_ENV_UINT: u32 => 40,
|
DEFAULT_ENV_UINT: u32 => 40,
|
||||||
DEFAULT_ENV_FLOAT: f64 => 40.9,
|
DEFAULT_ENV_FLOAT: f64 => 40.9,
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg::init();
|
|
||||||
|
|
||||||
assert_eq!(env::var("DEFAULT_ENV_STRING"), Ok("localhost".to_string()));
|
#[test]
|
||||||
assert_eq!(env::var("DEFAULT_ENV_BOOLEAN"), Ok("true".to_string()));
|
fn setting_default_env_variable() {
|
||||||
assert_eq!(env::var("DEFAULT_ENV_UINT"), Ok("40".to_string()));
|
config::init();
|
||||||
assert_eq!(env::var("DEFAULT_ENV_FLOAT"), Ok("40.9".to_string()));
|
|
||||||
|
assert_eq!(env::var("DEFAULT_ENV_STRING"), Ok("localhost".to_string()));
|
||||||
|
assert_eq!(env::var("DEFAULT_ENV_BOOLEAN"), Ok("true".to_string()));
|
||||||
|
assert_eq!(env::var("DEFAULT_ENV_UINT"), Ok("40".to_string()));
|
||||||
|
assert_eq!(env::var("DEFAULT_ENV_FLOAT"), Ok("40.9".to_string()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
mod test_case_16 {
|
||||||
fn concatenate_environment_variables() {
|
use std::env;
|
||||||
env::set_var("POSTGRES_USERNAME", "user");
|
|
||||||
env::set_var("POSTGRES_PASSWORD", "pass");
|
|
||||||
env::set_var("POSTGRES_HOST", "localhost");
|
|
||||||
env::set_var("POSTGRES_DB", "test");
|
|
||||||
|
|
||||||
config! {
|
itconfig::config! {
|
||||||
DATABASE_URL < (
|
DATABASE_URL < (
|
||||||
"postgres://",
|
"postgres://",
|
||||||
POSTGRES_USERNAME,
|
POSTGRES_USERNAME,
|
||||||
|
@ -311,16 +352,23 @@ fn concatenate_environment_variables() {
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg::init();
|
#[test]
|
||||||
assert_eq!(cfg::DATABASE_URL(), String::from("postgres://user:pass@localhost/test"));
|
fn concatenate_environment_variables() {
|
||||||
|
env::set_var("POSTGRES_USERNAME", "user");
|
||||||
|
env::set_var("POSTGRES_PASSWORD", "pass");
|
||||||
|
env::set_var("POSTGRES_HOST", "localhost");
|
||||||
|
env::set_var("POSTGRES_DB", "test");
|
||||||
|
|
||||||
|
config::init();
|
||||||
|
assert_eq!(config::DATABASE_URL(), String::from("postgres://user:pass@localhost/test"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
mod test_case_17 {
|
||||||
fn setting_default_concat_env_variable() {
|
use std::env;
|
||||||
env::set_var("SETTING_DEFAULT_CONCAT_ENV_VARIABLE", "custom");
|
|
||||||
|
|
||||||
config! {
|
itconfig::config! {
|
||||||
DEFAULT_CONCAT_ENV < (
|
DEFAULT_CONCAT_ENV < (
|
||||||
"string",
|
"string",
|
||||||
"/",
|
"/",
|
||||||
|
@ -328,15 +376,19 @@ fn setting_default_concat_env_variable() {
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg::init();
|
|
||||||
assert_eq!(env::var("DEFAULT_CONCAT_ENV"), Ok("string/custom".to_string()));
|
#[test]
|
||||||
|
fn setting_default_concat_env_variable() {
|
||||||
|
env::set_var("SETTING_DEFAULT_CONCAT_ENV_VARIABLE", "custom");
|
||||||
|
|
||||||
|
config::init();
|
||||||
|
assert_eq!(env::var("DEFAULT_CONCAT_ENV"), Ok("string/custom".to_string()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
mod test_case_18 {
|
||||||
#[should_panic(expected = "Environment variable \"PG_USERNAME\" is missing")]
|
itconfig::config! {
|
||||||
fn concatenate_not_defined_environment_variables() {
|
|
||||||
config! {
|
|
||||||
DATABASE_URL < (
|
DATABASE_URL < (
|
||||||
"postgres://",
|
"postgres://",
|
||||||
PG_USERNAME,
|
PG_USERNAME,
|
||||||
|
@ -348,13 +400,19 @@ fn concatenate_not_defined_environment_variables() {
|
||||||
PG_DB,
|
PG_DB,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
cfg::init();
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic(expected = "Environment variable \"PG_USERNAME\" is missing")]
|
||||||
|
fn concatenate_not_defined_environment_variables() {
|
||||||
|
config::init();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
mod test_case_19 {
|
||||||
fn default_value_for_concatenate_env_parameter() {
|
use std::env;
|
||||||
config! {
|
|
||||||
|
itconfig::config! {
|
||||||
CONCATENATED_DATABASE_URL < (
|
CONCATENATED_DATABASE_URL < (
|
||||||
"postgres://",
|
"postgres://",
|
||||||
NOT_DEFINED_PG_USERNAME => "user",
|
NOT_DEFINED_PG_USERNAME => "user",
|
||||||
|
@ -367,16 +425,23 @@ fn default_value_for_concatenate_env_parameter() {
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg::init();
|
|
||||||
assert_eq!(
|
#[test]
|
||||||
env::var("CONCATENATED_DATABASE_URL"),
|
fn default_value_for_concatenate_env_parameter() {
|
||||||
Ok("postgres://user:pass@localhost:5432/test".to_string())
|
config::init();
|
||||||
);
|
assert_eq!(
|
||||||
|
env::var("CONCATENATED_DATABASE_URL"),
|
||||||
|
Ok("postgres://user:pass@localhost:5432/test".to_string())
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn envname_meta_for_concatenated_env_variable() {
|
mod test_case_20 {
|
||||||
config! {
|
use std::env;
|
||||||
|
use std::env::VarError;
|
||||||
|
|
||||||
|
itconfig::config! {
|
||||||
#[env_name = "CUSTOM_CONCAT_ENVNAME"]
|
#[env_name = "CUSTOM_CONCAT_ENVNAME"]
|
||||||
CONCAT_ENVVAR < (
|
CONCAT_ENVVAR < (
|
||||||
"postgres://",
|
"postgres://",
|
||||||
|
@ -390,17 +455,23 @@ fn envname_meta_for_concatenated_env_variable() {
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg::init();
|
#[test]
|
||||||
assert_eq!(
|
fn envname_meta_for_concatenated_env_variable() {
|
||||||
env::var("CUSTOM_CONCAT_ENVNAME"),
|
config::init();
|
||||||
Ok("postgres://user:pass@localhost:5432/test".to_string())
|
assert_eq!(
|
||||||
);
|
env::var("CUSTOM_CONCAT_ENVNAME"),
|
||||||
assert_eq!(env::var("CONCAT_ENVVAR"), Err(VarError::NotPresent));
|
Ok("postgres://user:pass@localhost:5432/test".to_string())
|
||||||
|
);
|
||||||
|
assert_eq!(env::var("CONCAT_ENVVAR"), Err(VarError::NotPresent));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn concatenated_environment_variable_in_namespace() {
|
mod test_case_21 {
|
||||||
config! {
|
use std::env;
|
||||||
|
use std::env::VarError;
|
||||||
|
|
||||||
|
itconfig::config! {
|
||||||
CONCATED_NAMESPACE {
|
CONCATED_NAMESPACE {
|
||||||
CONCAT_ENVVAR < (
|
CONCAT_ENVVAR < (
|
||||||
"postgres://",
|
"postgres://",
|
||||||
|
@ -415,19 +486,21 @@ fn concatenated_environment_variable_in_namespace() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg::init();
|
|
||||||
assert_eq!(
|
#[test]
|
||||||
env::var("CONCATED_NAMESPACE_CONCAT_ENVVAR"),
|
fn concatenated_environment_variable_in_namespace() {
|
||||||
Ok("postgres://user:pass@localhost:5432/test".to_string())
|
config::init();
|
||||||
);
|
assert_eq!(
|
||||||
assert_eq!(env::var("CONCAT_ENVVAR"), Err(VarError::NotPresent));
|
env::var("CONCATED_NAMESPACE_CONCAT_ENVVAR"),
|
||||||
|
Ok("postgres://user:pass@localhost:5432/test".to_string())
|
||||||
|
);
|
||||||
|
assert_eq!(env::var("CONCAT_ENVVAR"), Err(VarError::NotPresent));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
mod test_case_22 {
|
||||||
#[cfg(feature = "static")]
|
itconfig::config! {
|
||||||
fn static_variables() {
|
|
||||||
config! {
|
|
||||||
static STATIC_STR => "test",
|
static STATIC_STR => "test",
|
||||||
static STATIC_STRING: String => "test",
|
static STATIC_STRING: String => "test",
|
||||||
static STATIC_I8: i8 => 1,
|
static STATIC_I8: i8 => 1,
|
||||||
|
@ -450,23 +523,27 @@ fn static_variables() {
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg::init();
|
|
||||||
|
|
||||||
assert_eq!(cfg::STATIC_STR(), "test");
|
#[test]
|
||||||
assert_eq!(cfg::STATIC_STRING(), "test".to_string());
|
fn static_variables() {
|
||||||
assert_eq!(cfg::STATIC_I8(), 1);
|
config::init();
|
||||||
assert_eq!(cfg::STATIC_I16(), 1);
|
|
||||||
assert_eq!(cfg::STATIC_I32(), 1);
|
assert_eq!(config::STATIC_STR(), "test");
|
||||||
assert_eq!(cfg::STATIC_I64(), 1);
|
assert_eq!(config::STATIC_STRING(), "test".to_string());
|
||||||
assert_eq!(cfg::STATIC_I128(), 1);
|
assert_eq!(config::STATIC_I8(), 1);
|
||||||
assert_eq!(cfg::STATIC_ISIZE(), 1);
|
assert_eq!(config::STATIC_I16(), 1);
|
||||||
assert_eq!(cfg::STATIC_U8(), 1);
|
assert_eq!(config::STATIC_I32(), 1);
|
||||||
assert_eq!(cfg::STATIC_U16(), 1);
|
assert_eq!(config::STATIC_I64(), 1);
|
||||||
assert_eq!(cfg::STATIC_U32(), 1);
|
assert_eq!(config::STATIC_I128(), 1);
|
||||||
assert_eq!(cfg::STATIC_U64(), 1);
|
assert_eq!(config::STATIC_ISIZE(), 1);
|
||||||
assert_eq!(cfg::STATIC_U128(), 1);
|
assert_eq!(config::STATIC_U8(), 1);
|
||||||
assert_eq!(cfg::STATIC_USIZE(), 1);
|
assert_eq!(config::STATIC_U16(), 1);
|
||||||
assert_eq!(cfg::STATIC_F32(), 1.0);
|
assert_eq!(config::STATIC_U32(), 1);
|
||||||
assert_eq!(cfg::STATIC_F64(), 1.0);
|
assert_eq!(config::STATIC_U64(), 1);
|
||||||
assert_eq!(cfg::STATIC_CONCAT_VARIABLE(), "static part".to_string())
|
assert_eq!(config::STATIC_U128(), 1);
|
||||||
|
assert_eq!(config::STATIC_USIZE(), 1);
|
||||||
|
assert_eq!(config::STATIC_F32(), 1.0);
|
||||||
|
assert_eq!(config::STATIC_F64(), 1.0);
|
||||||
|
assert_eq!(config::STATIC_CONCAT_VARIABLE(), "static part".to_string())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "itconfig"
|
name = "itconfig"
|
||||||
version = "0.11.2"
|
version = "1.0.0"
|
||||||
authors = ["Dmitriy Pleshevskiy <dmitriy@ideascup.me>"]
|
authors = ["Dmitriy Pleshevskiy <dmitriy@ideascup.me>"]
|
||||||
description = "Easy build a configs from environment variables and use it in globally."
|
description = "Easy build a configs from environment variables and use it in globally."
|
||||||
categories = ["config", "web-programming"]
|
categories = ["config", "web-programming"]
|
||||||
|
@ -15,15 +15,17 @@ readme = "README.md"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
failure = { version = "0.1.6", features = ["derive"]}
|
failure = { version = "0.1.7", features = ["derive"]}
|
||||||
lazy_static = { version = "1.4.0", optional = true }
|
|
||||||
serde_json = { version = "1.0.44", optional = true }
|
serde_json = { version = "1.0.44", optional = true }
|
||||||
|
itconfig-macro = { path = "../itconfig-macro", optional = true }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
lazy_static = "1.4.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["macro", "primitives", "static"]
|
default = ["primitives"]
|
||||||
|
|
||||||
macro = []
|
macro = ["itconfig-macro"]
|
||||||
static = ["lazy_static"]
|
|
||||||
|
|
||||||
array = ["serde_json"]
|
array = ["serde_json"]
|
||||||
|
|
||||||
|
|
|
@ -5,10 +5,29 @@ Easy build a configs from environment variables and use it in globally.
|
||||||
We recommend you start with the [documentation].
|
We recommend you start with the [documentation].
|
||||||
|
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
These macros require a Rust compiler version 1.31 or newer.
|
||||||
|
|
||||||
|
Add `itconfig = { version = "1.0", features = ["macro"] }` as a dependency in `Cargo.toml`.
|
||||||
|
|
||||||
|
`Cargo.toml` example:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[package]
|
||||||
|
name = "my-crate"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Me <user@rust-lang.org>"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
itconfig = { version = "1.0", features = ["macro"] }
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
## Example usage
|
## Example usage
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
#[macro_use] extern crate itconfig;
|
use std::itconfig;
|
||||||
use std::env;
|
use std::env;
|
||||||
//use dotenv::dotenv;
|
//use dotenv::dotenv;
|
||||||
|
|
||||||
|
@ -56,11 +75,11 @@ fn main () {
|
||||||
// dotenv().ok();
|
// dotenv().ok();
|
||||||
env::set_var("FEATURE_NEW_MENU", "t");
|
env::set_var("FEATURE_NEW_MENU", "t");
|
||||||
|
|
||||||
cfg::init();
|
config::init();
|
||||||
assert_eq!(cfg::HOST(), String::from("127.0.0.1"));
|
assert_eq!(config::HOST(), String::from("127.0.0.1"));
|
||||||
assert_eq!(cfg::DATABASE_URL(), String::from("postgres://user:pass@localhost:5432/test"));
|
assert_eq!(config::DATABASE_URL(), String::from("postgres://user:pass@localhost:5432/test"));
|
||||||
assert_eq!(cfg::APP:ARTICLE:PER_PAGE(), 15);
|
assert_eq!(config::APP:ARTICLE:PER_PAGE(), 15);
|
||||||
assert_eq!(cfg::FEATURE::NEW_MENU(), true);
|
assert_eq!(config::FEATURE::NEW_MENU(), true);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -93,6 +112,7 @@ fn main() {
|
||||||
* [x] Add nested namespaces
|
* [x] Add nested namespaces
|
||||||
* [x] Support meta for namespaces
|
* [x] Support meta for namespaces
|
||||||
* [x] Support array type
|
* [x] Support array type
|
||||||
|
* [x] Rewrite to proc macro
|
||||||
* [ ] Support hashmap type
|
* [ ] Support hashmap type
|
||||||
* [ ] Support custom env type
|
* [ ] Support custom env type
|
||||||
* [ ] Common configuration for namespace variables
|
* [ ] Common configuration for namespace variables
|
||||||
|
@ -102,7 +122,6 @@ fn main() {
|
||||||
|
|
||||||
* **default** - ["macro", "primitives", "static"]
|
* **default** - ["macro", "primitives", "static"]
|
||||||
* **macro** - Activates `config!` macros for easy configure web application.
|
* **macro** - Activates `config!` macros for easy configure web application.
|
||||||
* **static** - Add `static` option to `config!` macros (uses optional `lazy_static` package).
|
|
||||||
* **array** - Add EnvString impl for vector type (uses optional `serde_json` package).
|
* **array** - Add EnvString impl for vector type (uses optional `serde_json` package).
|
||||||
* **primitives** - Group for features: `numbers` and `bool`.
|
* **primitives** - Group for features: `numbers` and `bool`.
|
||||||
* **numbers** - Group for features: `int`, `uint` and `float`.
|
* **numbers** - Group for features: `int`, `uint` and `float`.
|
||||||
|
|
33
itconfig/src/cfg.rs
Normal file
33
itconfig/src/cfg.rs
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
config! {
|
||||||
|
#![config(unwrap)]
|
||||||
|
|
||||||
|
TEST => "hello",
|
||||||
|
static MAIN => "main",
|
||||||
|
TEST2 => "test",
|
||||||
|
|
||||||
|
CONCAT < (
|
||||||
|
TESTTTT => "hellooooooo",
|
||||||
|
" ",
|
||||||
|
"world",
|
||||||
|
),
|
||||||
|
|
||||||
|
NAMESPACE {
|
||||||
|
TEST: String => "test",
|
||||||
|
|
||||||
|
NAMESPACE {
|
||||||
|
TEST: &'static str => "test",
|
||||||
|
|
||||||
|
#[env_prefix = "HELLO_"]
|
||||||
|
NAMESPACE {
|
||||||
|
TEST: &'static str => "test",
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "linux"))]
|
||||||
|
#[env_prefix = "WORLD_"]
|
||||||
|
NAMESPACE {
|
||||||
|
#[env_name = "TEST_TEST_TEST"]
|
||||||
|
TEST: &'static str => "test",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,10 +12,30 @@
|
||||||
//! as application lifetime. Because of it I decided to create my own library.
|
//! as application lifetime. Because of it I decided to create my own library.
|
||||||
//!
|
//!
|
||||||
//!
|
//!
|
||||||
|
//! ## Installation
|
||||||
|
//!
|
||||||
|
//! These macros require a Rust compiler version 1.31 or newer.
|
||||||
|
//!
|
||||||
|
//! Add `itconfig = { version = "1.0", features = ["macro"] }` as a dependency in `Cargo.toml`.
|
||||||
|
//!
|
||||||
|
//!
|
||||||
|
//! `Cargo.toml` example:
|
||||||
|
//!
|
||||||
|
//! ```toml
|
||||||
|
//! [package]
|
||||||
|
//! name = "my-crate"
|
||||||
|
//! version = "0.1.0"
|
||||||
|
//! authors = ["Me <user@rust-lang.org>"]
|
||||||
|
//!
|
||||||
|
//! [dependencies]
|
||||||
|
//! itconfig = { version = "1.0", features = ["macro"] }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//!
|
||||||
//! ## Example usage
|
//! ## Example usage
|
||||||
//!
|
//!
|
||||||
//! ```rust
|
//! ```rust
|
||||||
//! #[macro_use] extern crate itconfig;
|
//! use itconfig::config;
|
||||||
//! use std::env;
|
//! use std::env;
|
||||||
//! // use dotenv::dotenv;
|
//! // use dotenv::dotenv;
|
||||||
//!
|
//!
|
||||||
|
@ -61,12 +81,12 @@
|
||||||
//! // dotenv().ok();
|
//! // dotenv().ok();
|
||||||
//! env::set_var("FEATURE_NEW_MENU", "t");
|
//! env::set_var("FEATURE_NEW_MENU", "t");
|
||||||
//!
|
//!
|
||||||
//! cfg::init();
|
//! config::init();
|
||||||
//! assert_eq!(cfg::HOST(), String::from("127.0.0.1"));
|
//! assert_eq!(config::HOST(), String::from("127.0.0.1"));
|
||||||
//! assert_eq!(cfg::DATABASE_URL(), String::from("postgres://user:pass@localhost:5432/test"));
|
//! assert_eq!(config::DATABASE_URL(), String::from("postgres://user:pass@localhost:5432/test"));
|
||||||
//! assert_eq!(cfg::APP::BASE_URL(), "/api");
|
//! assert_eq!(config::APP::BASE_URL(), "/api");
|
||||||
//! assert_eq!(cfg::APP::ARTICLE::PER_PAGE(), 15);
|
//! assert_eq!(config::APP::ARTICLE::PER_PAGE(), 15);
|
||||||
//! assert_eq!(cfg::FEATURE::NEW_MENU(), true);
|
//! assert_eq!(config::FEATURE::NEW_MENU(), true);
|
||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
@ -89,9 +109,8 @@
|
||||||
//!
|
//!
|
||||||
//! ## Available features
|
//! ## Available features
|
||||||
//!
|
//!
|
||||||
//! * **default** - ["macro", "primitives", "static"]
|
//! * **default** - ["primitives"]
|
||||||
//! * **macro** - Activates `config!` macros for easy configure web application.
|
//! * **macro** - Activates `config!` macros for easy configure web application.
|
||||||
//! * **static** - Add `static` option to `config!` macros (uses optional `lazy_static` package).
|
|
||||||
//! * **array** - Add EnvString impl for vector type (uses optional `serde_json` package).
|
//! * **array** - Add EnvString impl for vector type (uses optional `serde_json` package).
|
||||||
//! * **primitives** - Group for features: `numbers` and `bool`.
|
//! * **primitives** - Group for features: `numbers` and `bool`.
|
||||||
//! * **numbers** - Group for features: `int`, `uint` and `float`.
|
//! * **numbers** - Group for features: `int`, `uint` and `float`.
|
||||||
|
@ -129,8 +148,6 @@
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate failure;
|
extern crate failure;
|
||||||
#[cfg(feature = "static")]
|
|
||||||
pub extern crate lazy_static;
|
|
||||||
|
|
||||||
mod enverr;
|
mod enverr;
|
||||||
mod getenv;
|
mod getenv;
|
||||||
|
@ -146,9 +163,7 @@ pub mod prelude {
|
||||||
|
|
||||||
|
|
||||||
#[cfg(feature = "macro")]
|
#[cfg(feature = "macro")]
|
||||||
//#[allow(unused_imports)]
|
extern crate itconfig_macro;
|
||||||
#[macro_use]
|
|
||||||
mod r#macro;
|
|
||||||
#[cfg(feature = "macro")]
|
#[cfg(feature = "macro")]
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub use r#macro::*;
|
pub use itconfig_macro::*;
|
|
@ -1,880 +0,0 @@
|
||||||
|
|
||||||
/// ### _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
|
|
||||||
/// # #[macro_use] extern crate itconfig;
|
|
||||||
/// # use std::env;
|
|
||||||
/// # env::set_var("DATABASE_URL", "postgres://u:p@localhost:5432/db");
|
|
||||||
/// config! {
|
|
||||||
/// DATABASE_URL: String,
|
|
||||||
/// }
|
|
||||||
/// # cfg::init()
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// Config with default value
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # #[macro_use] extern crate itconfig;
|
|
||||||
/// # use std::env;
|
|
||||||
/// # env::set_var("DATABASE_URL", "postgres://u:p@localhost:5432/db");
|
|
||||||
/// config! {
|
|
||||||
/// DATABASE_URL: String,
|
|
||||||
/// HOST: String => "127.0.0.1",
|
|
||||||
/// }
|
|
||||||
/// # cfg::init()
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// By default itconfig lib creates module with 'cfg' name. But you can use simple meta instruction
|
|
||||||
/// if you want to rename module. In the example below we renamed module to 'configuration'
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # #[macro_use] extern crate itconfig;
|
|
||||||
/// # use std::env;
|
|
||||||
/// env::set_var("DEBUG", "t");
|
|
||||||
///
|
|
||||||
/// config! {
|
|
||||||
/// #![mod_name = configuration]
|
|
||||||
///
|
|
||||||
/// DEBUG: bool,
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// configuration::init();
|
|
||||||
/// assert_eq!(configuration::DEBUG(), true);
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// Namespaces
|
|
||||||
/// ----------
|
|
||||||
///
|
|
||||||
/// You can use namespaces for env variables
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # #[macro_use] extern crate itconfig;
|
|
||||||
/// # use std::env;
|
|
||||||
/// env::set_var("DEBUG", "t");
|
|
||||||
/// env::set_var("DATABASE_USERNAME", "user");
|
|
||||||
/// env::set_var("DATABASE_PASSWORD", "pass");
|
|
||||||
/// env::set_var("DATABASE_HOST", "localhost");
|
|
||||||
///
|
|
||||||
/// config! {
|
|
||||||
/// DEBUG: bool,
|
|
||||||
/// DATABASE {
|
|
||||||
/// USERNAME: String,
|
|
||||||
/// PASSWORD: String,
|
|
||||||
/// HOST: String,
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
/// # cfg::init()
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// Now you can use nested structure in namespaces without limits :)
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # #[macro_use] extern crate itconfig;
|
|
||||||
/// config! {
|
|
||||||
/// FIRST {
|
|
||||||
/// SECOND {
|
|
||||||
/// THIRD {
|
|
||||||
/// FOO: bool => true,
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
/// # cfg::init();
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// Namespaces supports custom meta
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # #[macro_use] extern crate itconfig;
|
|
||||||
/// config! {
|
|
||||||
/// #[cfg(feature = "first")]
|
|
||||||
/// FIRST {
|
|
||||||
/// #[cfg(feature = "second")]
|
|
||||||
/// SECOND {
|
|
||||||
/// #[cfg(feature = "third")]
|
|
||||||
/// THIRD {
|
|
||||||
/// FOO: bool => true,
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
/// # cfg::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
|
|
||||||
/// # #[macro_use] extern crate itconfig;
|
|
||||||
/// # use std::env;
|
|
||||||
/// env::set_var("MY_CUSTOM_NAME", "95");
|
|
||||||
///
|
|
||||||
/// config! {
|
|
||||||
/// #[env_name = "MY_CUSTOM_NAME"]
|
|
||||||
/// PER_PAGE: i32,
|
|
||||||
///
|
|
||||||
/// APP {
|
|
||||||
/// #[env_name = "MY_CUSTOM_NAME"]
|
|
||||||
/// RECIPES_PER_PAGE: i32,
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// cfg::init();
|
|
||||||
/// assert_eq!(cfg::PER_PAGE(), 95);
|
|
||||||
/// assert_eq!(cfg::APP::RECIPES_PER_PAGE(), 95);
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// Also you can add custom meta for each variable. For example feature configurations.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # #[macro_use] extern crate itconfig;
|
|
||||||
/// 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
|
|
||||||
/// # #[macro_use] extern crate itconfig;
|
|
||||||
/// # use std::env;
|
|
||||||
/// env::set_var("POSTGRES_USERNAME", "user");
|
|
||||||
/// env::set_var("POSTGRES_PASSWORD", "pass");
|
|
||||||
///
|
|
||||||
/// config! {
|
|
||||||
/// DATABASE_URL < (
|
|
||||||
/// "postgres://",
|
|
||||||
/// POSTGRES_USERNAME,
|
|
||||||
/// ":",
|
|
||||||
/// POSTGRES_PASSWORD,
|
|
||||||
/// "@",
|
|
||||||
/// POSTGRES_HOST => "localhost:5432",
|
|
||||||
/// "/",
|
|
||||||
/// POSTGRES_DB => "test",
|
|
||||||
/// ),
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// cfg::init();
|
|
||||||
/// assert_eq!(cfg::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
|
|
||||||
/// # #[macro_use] extern crate itconfig;
|
|
||||||
/// 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",
|
|
||||||
/// ),
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// cfg::init();
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// Static
|
|
||||||
/// ------
|
|
||||||
///
|
|
||||||
/// `with feauter = "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
|
|
||||||
/// # #[macro_use] extern crate itconfig;
|
|
||||||
/// # use std::env;
|
|
||||||
/// env::set_var("APP_BASE_URL", "/api/v1");
|
|
||||||
///
|
|
||||||
/// config! {
|
|
||||||
/// static APP_BASE_URL => "/api",
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// cfg::init();
|
|
||||||
/// assert_eq!(cfg::APP_BASE_URL(), "/api/v1");
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// You also can use static with concat variables
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # #[macro_use] extern crate itconfig;
|
|
||||||
/// 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",
|
|
||||||
/// ),
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// cfg::init();
|
|
||||||
/// assert_eq!(cfg::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
|
|
||||||
/// #[macro_use] extern crate itconfig;
|
|
||||||
/// // use dotenv::dotenv;
|
|
||||||
///
|
|
||||||
/// config! {
|
|
||||||
/// DEBUG: bool => true,
|
|
||||||
/// HOST: String => "127.0.0.1",
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// fn main () {
|
|
||||||
/// // dotenv().ok();
|
|
||||||
/// cfg::init();
|
|
||||||
/// assert_eq!(cfg::HOST(), String::from("127.0.0.1"));
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
#[macro_export(local_inner_macros)]
|
|
||||||
macro_rules! config {
|
|
||||||
($($tokens:tt)*) => {
|
|
||||||
__itconfig_parse_module! {
|
|
||||||
tokens = [$($tokens)*],
|
|
||||||
name = cfg,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
#[doc(hidden)]
|
|
||||||
macro_rules! __itconfig_invalid_syntax {
|
|
||||||
() => {
|
|
||||||
compile_error!(
|
|
||||||
"Invalid `config!` syntax. Please see the `config!` macro docs for more info.\
|
|
||||||
`https://docs.rs/itconfig/latest/itconfig/macro.config.html`"
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
#[doc(hidden)]
|
|
||||||
macro_rules! __itconfig_parse_module {
|
|
||||||
// Find module name
|
|
||||||
(
|
|
||||||
tokens = [
|
|
||||||
#![mod_name = $mod_name:ident]
|
|
||||||
$($rest:tt)*
|
|
||||||
],
|
|
||||||
name = $ignore:tt,
|
|
||||||
) => {
|
|
||||||
__itconfig_parse_module! {
|
|
||||||
tokens = [$($rest)*],
|
|
||||||
name = $mod_name,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Done parsing module
|
|
||||||
(
|
|
||||||
tokens = $tokens:tt,
|
|
||||||
name = $name:tt,
|
|
||||||
) => {
|
|
||||||
__itconfig_parse_variables! {
|
|
||||||
tokens = $tokens,
|
|
||||||
variables = [],
|
|
||||||
namespaces = [],
|
|
||||||
module = {
|
|
||||||
env_prefix = "",
|
|
||||||
name = $name,
|
|
||||||
meta = [],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Invalid syntax
|
|
||||||
($($tokens:tt)*) => {
|
|
||||||
__itconfig_invalid_syntax!();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[cfg(feature = "static")]
|
|
||||||
#[macro_export]
|
|
||||||
#[doc(hidden)]
|
|
||||||
macro_rules! __itconfig_impl_static_feature {
|
|
||||||
(@import_modules) => {
|
|
||||||
use $crate::lazy_static::lazy_static;
|
|
||||||
};
|
|
||||||
|
|
||||||
(
|
|
||||||
unparsed_meta = $meta:tt,
|
|
||||||
unparsed_concat = $concat:tt,
|
|
||||||
name = $name:ident,
|
|
||||||
ty = $ty:ty,
|
|
||||||
$(default = $default:expr,)?
|
|
||||||
tokens = $tokens:tt,
|
|
||||||
args = [$($args:tt)*],
|
|
||||||
) => {
|
|
||||||
__itconfig_parse_variables! {
|
|
||||||
current_variable = {
|
|
||||||
unparsed_meta = $meta,
|
|
||||||
meta = [],
|
|
||||||
unparsed_concat = $concat,
|
|
||||||
concat = [],
|
|
||||||
name = $name,
|
|
||||||
ty = $ty,
|
|
||||||
is_static = true,
|
|
||||||
$(default = $default,)?
|
|
||||||
},
|
|
||||||
tokens = $tokens,
|
|
||||||
$($args)*
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[cfg(not(feature = "static"))]
|
|
||||||
#[macro_export]
|
|
||||||
#[doc(hidden)]
|
|
||||||
macro_rules! __itconfig_impl_static_feature {
|
|
||||||
(@import_modules) => { };
|
|
||||||
|
|
||||||
($($tt:tt)*) => {
|
|
||||||
compile_error!(
|
|
||||||
"Feature `static` is required for enable this macro function.\
|
|
||||||
Please see the `config!` macro docs for more info.\
|
|
||||||
`https://docs.rs/itconfig/latest/itconfig/macro.config.html`"
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
#[doc(hidden)]
|
|
||||||
macro_rules! __itconfig_get_ty_or_default {
|
|
||||||
() => { &'static str };
|
|
||||||
($ty:ty) => { $ty };
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
#[doc(hidden)]
|
|
||||||
macro_rules! __itconfig_parse_variables {
|
|
||||||
// Find namespace
|
|
||||||
(
|
|
||||||
tokens = [
|
|
||||||
$(#$meta:tt)*
|
|
||||||
$ns_name:ident { $($ns_tokens:tt)* }
|
|
||||||
$($rest:tt)*
|
|
||||||
],
|
|
||||||
$($args:tt)*
|
|
||||||
) => {
|
|
||||||
__itconfig_parse_variables! {
|
|
||||||
tokens = [$($ns_tokens)*],
|
|
||||||
variables = [],
|
|
||||||
namespaces = [],
|
|
||||||
module = {
|
|
||||||
env_prefix = concat!(stringify!($ns_name), "_"),
|
|
||||||
name = $ns_name,
|
|
||||||
meta = [$(#$meta)*],
|
|
||||||
},
|
|
||||||
callback = {
|
|
||||||
tokens = [$($rest)*],
|
|
||||||
$($args)*
|
|
||||||
},
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Find static concatenated variable
|
|
||||||
(
|
|
||||||
tokens = [
|
|
||||||
$(#$meta:tt)*
|
|
||||||
static $name:ident < ($($inner:tt)+),
|
|
||||||
$($rest:tt)*
|
|
||||||
],
|
|
||||||
$($args:tt)*
|
|
||||||
) => {
|
|
||||||
__itconfig_impl_static_feature! {
|
|
||||||
unparsed_meta = [$(#$meta)*],
|
|
||||||
unparsed_concat = [$($inner)+],
|
|
||||||
name = $name,
|
|
||||||
ty = String,
|
|
||||||
tokens = [$($rest)*],
|
|
||||||
args = [$($args)*],
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Find concatenated variable
|
|
||||||
(
|
|
||||||
tokens = [
|
|
||||||
$(#$meta:tt)*
|
|
||||||
$name:ident < ($($inner:tt)+),
|
|
||||||
$($rest:tt)*
|
|
||||||
],
|
|
||||||
$($args:tt)*
|
|
||||||
) => {
|
|
||||||
__itconfig_parse_variables! {
|
|
||||||
current_variable = {
|
|
||||||
unparsed_meta = [$(#$meta)*],
|
|
||||||
meta = [],
|
|
||||||
unparsed_concat = [$($inner)+],
|
|
||||||
concat = [],
|
|
||||||
name = $name,
|
|
||||||
ty = String,
|
|
||||||
is_static = false,
|
|
||||||
},
|
|
||||||
tokens = [$($rest)*],
|
|
||||||
$($args)*
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Find static variable
|
|
||||||
(
|
|
||||||
tokens = [
|
|
||||||
$(#$meta:tt)*
|
|
||||||
static $name:ident $(: $ty:ty)? $(=> $default:expr)?,
|
|
||||||
$($rest:tt)*
|
|
||||||
],
|
|
||||||
$($args:tt)*
|
|
||||||
) => {
|
|
||||||
__itconfig_impl_static_feature! {
|
|
||||||
unparsed_meta = [$(#$meta)*],
|
|
||||||
unparsed_concat = [],
|
|
||||||
name = $name,
|
|
||||||
ty = __itconfig_get_ty_or_default!($($ty)?),
|
|
||||||
$(default = $default,)?
|
|
||||||
tokens = [$($rest)*],
|
|
||||||
args = [$($args)*],
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Find variable
|
|
||||||
(
|
|
||||||
tokens = [
|
|
||||||
$(#$meta:tt)*
|
|
||||||
$name:ident $(: $ty:ty)? $(=> $default:expr)?,
|
|
||||||
$($rest:tt)*
|
|
||||||
],
|
|
||||||
$($args:tt)*
|
|
||||||
) => {
|
|
||||||
__itconfig_parse_variables! {
|
|
||||||
current_variable = {
|
|
||||||
unparsed_meta = [$(#$meta)*],
|
|
||||||
meta = [],
|
|
||||||
unparsed_concat = [],
|
|
||||||
concat = [],
|
|
||||||
name = $name,
|
|
||||||
ty = __itconfig_get_ty_or_default!($($ty)?),
|
|
||||||
is_static = false,
|
|
||||||
$(default = $default,)?
|
|
||||||
},
|
|
||||||
tokens = [$($rest)*],
|
|
||||||
$($args)*
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Find meta with custom env name
|
|
||||||
(
|
|
||||||
current_variable = {
|
|
||||||
unparsed_meta = [
|
|
||||||
#[env_name = $env_name:expr]
|
|
||||||
$($rest:tt)*
|
|
||||||
],
|
|
||||||
meta = $meta:tt,
|
|
||||||
unparsed_concat = $unparsed_concat:tt,
|
|
||||||
concat = $concat:tt,
|
|
||||||
name = $name:ident,
|
|
||||||
$($current_variable:tt)*
|
|
||||||
},
|
|
||||||
$($args:tt)*
|
|
||||||
) => {
|
|
||||||
__itconfig_parse_variables! {
|
|
||||||
current_variable = {
|
|
||||||
unparsed_meta = [$($rest)*],
|
|
||||||
meta = $meta,
|
|
||||||
unparsed_concat = $unparsed_concat,
|
|
||||||
concat = $concat,
|
|
||||||
name = $name,
|
|
||||||
env_name = $env_name,
|
|
||||||
$($current_variable)*
|
|
||||||
},
|
|
||||||
$($args)*
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Find stranger meta
|
|
||||||
(
|
|
||||||
current_variable = {
|
|
||||||
unparsed_meta = [
|
|
||||||
#$stranger_meta:tt
|
|
||||||
$($rest:tt)*
|
|
||||||
],
|
|
||||||
meta = [$(#$meta:tt,)*],
|
|
||||||
$($current_variable:tt)*
|
|
||||||
},
|
|
||||||
$($args:tt)*
|
|
||||||
) => {
|
|
||||||
__itconfig_parse_variables! {
|
|
||||||
current_variable = {
|
|
||||||
unparsed_meta = [$($rest)*],
|
|
||||||
meta = [$(#$meta,)* #$stranger_meta,],
|
|
||||||
$($current_variable)*
|
|
||||||
},
|
|
||||||
$($args)*
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Parse concat params
|
|
||||||
(
|
|
||||||
current_variable = {
|
|
||||||
unparsed_meta = $unparsed_meta:tt,
|
|
||||||
meta = $meta:tt,
|
|
||||||
unparsed_concat = [
|
|
||||||
$concat_param:tt$( => $default:expr)?,
|
|
||||||
$($rest:tt)*
|
|
||||||
],
|
|
||||||
concat = [$($concat:expr,)*],
|
|
||||||
$($current_variable:tt)*
|
|
||||||
},
|
|
||||||
$($args:tt)*
|
|
||||||
) => {
|
|
||||||
__itconfig_parse_variables! {
|
|
||||||
current_variable = {
|
|
||||||
unparsed_meta = $unparsed_meta,
|
|
||||||
meta = $meta,
|
|
||||||
unparsed_concat = [$($rest)*],
|
|
||||||
concat = [$($concat,)* __itconfig_concat_param!($concat_param$( => $default)?),],
|
|
||||||
$($current_variable)*
|
|
||||||
},
|
|
||||||
$($args)*
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Done parsing variable
|
|
||||||
(
|
|
||||||
current_variable = {
|
|
||||||
unparsed_meta = [],
|
|
||||||
meta = $meta:tt,
|
|
||||||
unparsed_concat = [],
|
|
||||||
$($current_variable:tt)*
|
|
||||||
},
|
|
||||||
tokens = $tokens:tt,
|
|
||||||
variables = [$($variables:tt,)*],
|
|
||||||
$($args:tt)*
|
|
||||||
) => {
|
|
||||||
__itconfig_parse_variables! {
|
|
||||||
tokens = $tokens,
|
|
||||||
variables = [$($variables,)* { meta = $meta, $($current_variable)* },],
|
|
||||||
$($args)*
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Done parsing all variables of namespace
|
|
||||||
(
|
|
||||||
tokens = [],
|
|
||||||
variables = $ns_variables:tt,
|
|
||||||
namespaces = $ns_namespaces:tt,
|
|
||||||
module = $ns_module:tt,
|
|
||||||
callback = {
|
|
||||||
tokens = $tokens:tt,
|
|
||||||
variables = $variables:tt,
|
|
||||||
namespaces = [$($namespaces:tt,)*],
|
|
||||||
$($args:tt)*
|
|
||||||
},
|
|
||||||
) => {
|
|
||||||
__itconfig_parse_variables! {
|
|
||||||
tokens = $tokens,
|
|
||||||
variables = $variables,
|
|
||||||
namespaces = [
|
|
||||||
$($namespaces,)*
|
|
||||||
{
|
|
||||||
variables = $ns_variables,
|
|
||||||
namespaces = $ns_namespaces,
|
|
||||||
module = $ns_module,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
$($args)*
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Done parsing all variables
|
|
||||||
(
|
|
||||||
tokens = [],
|
|
||||||
$($args:tt)*
|
|
||||||
) => {
|
|
||||||
__itconfig_impl_namespace!($($args)*);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Invalid syntax
|
|
||||||
($($tokens:tt)*) => {
|
|
||||||
__itconfig_invalid_syntax!();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
#[doc(hidden)]
|
|
||||||
macro_rules! __itconfig_impl_namespace {
|
|
||||||
(
|
|
||||||
variables = [$({
|
|
||||||
meta = $var_meta:tt,
|
|
||||||
concat = $var_concat:tt,
|
|
||||||
name = $var_name:ident,
|
|
||||||
$(env_name = $env_name:expr,)?
|
|
||||||
ty = $ty:ty,
|
|
||||||
is_static = $is_static:ident,
|
|
||||||
$($variable:tt)*
|
|
||||||
},)*],
|
|
||||||
namespaces = [$({
|
|
||||||
variables = $ns_variable:tt,
|
|
||||||
namespaces = $ns_namespaces:tt,
|
|
||||||
module = {
|
|
||||||
env_prefix = $ns_env_prefix:expr,
|
|
||||||
name = $ns_mod_name:ident,
|
|
||||||
meta = [$(#$ns_meta:tt)*],
|
|
||||||
},
|
|
||||||
},)*],
|
|
||||||
module = {
|
|
||||||
env_prefix = $env_prefix:expr,
|
|
||||||
name = $mod_name:ident,
|
|
||||||
meta = [$(#$meta:tt)*],
|
|
||||||
},
|
|
||||||
) => {
|
|
||||||
$(#$meta)*
|
|
||||||
pub mod $mod_name {
|
|
||||||
#![allow(non_snake_case)]
|
|
||||||
|
|
||||||
__itconfig_impl_static_feature!( @import_modules );
|
|
||||||
|
|
||||||
$(__itconfig_impl_namespace! {
|
|
||||||
variables = $ns_variable,
|
|
||||||
namespaces = $ns_namespaces,
|
|
||||||
module = {
|
|
||||||
env_prefix = $ns_env_prefix,
|
|
||||||
name = $ns_mod_name,
|
|
||||||
meta = [$(#$ns_meta)*],
|
|
||||||
},
|
|
||||||
})*
|
|
||||||
|
|
||||||
pub fn init() {
|
|
||||||
$($var_name();)*
|
|
||||||
$(
|
|
||||||
$(#$ns_meta)*
|
|
||||||
$ns_mod_name::init();
|
|
||||||
)*
|
|
||||||
}
|
|
||||||
|
|
||||||
$(__itconfig_variable! {
|
|
||||||
meta = $var_meta,
|
|
||||||
concat = $var_concat,
|
|
||||||
name = $var_name,
|
|
||||||
env_prefix = $env_prefix,
|
|
||||||
$(env_name = $env_name,)?
|
|
||||||
ty = $ty,
|
|
||||||
is_static = $is_static,
|
|
||||||
$($variable)*
|
|
||||||
})*
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Invalid syntax
|
|
||||||
($($tokens:tt)*) => {
|
|
||||||
__itconfig_invalid_syntax!();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
#[doc(hidden)]
|
|
||||||
macro_rules! __itconfig_concat_param {
|
|
||||||
// Find env parameter with default value
|
|
||||||
($env_name:ident => $default:expr) => (
|
|
||||||
itconfig::get_env_or_default(
|
|
||||||
stringify!($env_name).to_uppercase().as_str(),
|
|
||||||
$default
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Find env parameter without default value
|
|
||||||
($env_name:ident) => (
|
|
||||||
itconfig::get_env_or_panic(stringify!($env_name).to_uppercase().as_str())
|
|
||||||
);
|
|
||||||
|
|
||||||
// Find string parameter
|
|
||||||
($str:expr) => ( $str.to_string() );
|
|
||||||
|
|
||||||
// Invalid syntax
|
|
||||||
($($tokens:tt)*) => {
|
|
||||||
__itconfig_invalid_syntax!();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
#[doc(hidden)]
|
|
||||||
macro_rules! __itconfig_variable {
|
|
||||||
// Set default env name
|
|
||||||
(
|
|
||||||
meta = $meta:tt,
|
|
||||||
concat = $concat:tt,
|
|
||||||
name = $name:ident,
|
|
||||||
env_prefix = $env_prefix:expr,
|
|
||||||
ty = $ty:ty,
|
|
||||||
$($args:tt)*
|
|
||||||
) => {
|
|
||||||
__itconfig_variable! {
|
|
||||||
meta = $meta,
|
|
||||||
concat = $concat,
|
|
||||||
name = $name,
|
|
||||||
env_prefix = $env_prefix,
|
|
||||||
env_name = concat!($env_prefix, stringify!($name)).to_uppercase(),
|
|
||||||
ty = $ty,
|
|
||||||
$($args)*
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Add method for env variable
|
|
||||||
(
|
|
||||||
meta = $meta:tt,
|
|
||||||
concat = $concat:tt,
|
|
||||||
name = $name:ident,
|
|
||||||
env_prefix = $env_prefix:expr,
|
|
||||||
env_name = $env_name:expr,
|
|
||||||
ty = $ty:ty,
|
|
||||||
is_static = $is_static:ident,
|
|
||||||
$(default = $default:expr,)?
|
|
||||||
) => {
|
|
||||||
__itconfig_variable!(
|
|
||||||
@wrap
|
|
||||||
is_static = $is_static,
|
|
||||||
meta = $meta,
|
|
||||||
name = $name,
|
|
||||||
ty = $ty,
|
|
||||||
value = __itconfig_variable!(
|
|
||||||
@inner
|
|
||||||
concat = $concat,
|
|
||||||
env_name = $env_name,
|
|
||||||
$(default = $default,)?
|
|
||||||
),
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Wrap static variables
|
|
||||||
(
|
|
||||||
@wrap
|
|
||||||
is_static = true,
|
|
||||||
meta = [$(#$meta:tt,)*],
|
|
||||||
name = $name:ident,
|
|
||||||
ty = $ty:ty,
|
|
||||||
value = $value:expr,
|
|
||||||
) => (
|
|
||||||
$(#$meta)*
|
|
||||||
pub fn $name() -> $ty {
|
|
||||||
lazy_static! {
|
|
||||||
static ref $name: $ty = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
(*$name).clone()
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Wrap functions
|
|
||||||
(
|
|
||||||
@wrap
|
|
||||||
is_static = false,
|
|
||||||
meta = [$(#$meta:tt,)*],
|
|
||||||
name = $name:ident,
|
|
||||||
ty = $ty:ty,
|
|
||||||
value = $value:expr,
|
|
||||||
) => (
|
|
||||||
$(#$meta)*
|
|
||||||
pub fn $name() -> $ty { $value }
|
|
||||||
);
|
|
||||||
|
|
||||||
// Concatenate function body
|
|
||||||
(
|
|
||||||
@inner
|
|
||||||
concat = [$($concat:expr,)+],
|
|
||||||
env_name = $env_name:expr,
|
|
||||||
$($args:tt)*
|
|
||||||
) => ({
|
|
||||||
let value_parts: Vec<String> = vec!($($concat),+);
|
|
||||||
let value = value_parts.join("");
|
|
||||||
std::env::set_var($env_name, value.as_str());
|
|
||||||
value
|
|
||||||
});
|
|
||||||
|
|
||||||
// Env without default
|
|
||||||
(
|
|
||||||
@inner
|
|
||||||
concat = [],
|
|
||||||
env_name = $env_name:expr,
|
|
||||||
) => (
|
|
||||||
itconfig::get_env_or_panic($env_name.to_string().as_str())
|
|
||||||
);
|
|
||||||
|
|
||||||
// Env with default
|
|
||||||
(
|
|
||||||
@inner
|
|
||||||
concat = [],
|
|
||||||
env_name = $env_name:expr,
|
|
||||||
default = $default:expr,
|
|
||||||
) => (
|
|
||||||
itconfig::get_env_or_set_default(
|
|
||||||
$env_name.to_string().as_str(),
|
|
||||||
$default
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Invalid syntax
|
|
||||||
($($tokens:tt)*) => {
|
|
||||||
__itconfig_invalid_syntax!();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
Reference in a new issue