chore: remove benches and old config macro
This commit is contained in:
parent
3686486847
commit
b223bc811e
10 changed files with 6 additions and 1067 deletions
18
Cargo.lock
generated
18
Cargo.lock
generated
|
@ -1,5 +1,7 @@
|
||||||
# This file is automatically @generated by Cargo.
|
# This file is automatically @generated by Cargo.
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "atty"
|
name = "atty"
|
||||||
version = "0.2.14"
|
version = "0.2.14"
|
||||||
|
@ -178,25 +180,15 @@ name = "enve"
|
||||||
version = "1.1.1"
|
version = "1.1.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"criterion",
|
"criterion",
|
||||||
"enve_mod",
|
|
||||||
"estring",
|
"estring",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "enve_mod"
|
|
||||||
version = "1.1.1"
|
|
||||||
dependencies = [
|
|
||||||
"enve",
|
|
||||||
"lazy_static",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "estring"
|
name = "estring"
|
||||||
version = "0.1.0"
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "72ea7e904ef7cb950eee02f9332b6a5c24c33bebeca6c027651b04f6c20658d9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "half"
|
name = "half"
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = []
|
||||||
"estring",
|
|
||||||
"enve_mod",
|
|
||||||
]
|
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "enve"
|
name = "enve"
|
||||||
|
@ -26,11 +23,8 @@ number = ["estring/number"]
|
||||||
bool = ["estring/bool"]
|
bool = ["estring/bool"]
|
||||||
vec = ["estring/vec"]
|
vec = ["estring/vec"]
|
||||||
|
|
||||||
macro = ["enve_mod"]
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
estring = "0.1"
|
estring = "0.1"
|
||||||
enve_mod = { version = "1.1", path = "./enve_mod", optional = true }
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
|
|
|
@ -1,84 +0,0 @@
|
||||||
use criterion::{criterion_group, criterion_main, Criterion, Fun};
|
|
||||||
use std::env;
|
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate lazy_static;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate enve;
|
|
||||||
|
|
||||||
fn setup_env_var(key: &'static str, initial: String) {
|
|
||||||
env::set_var(key, initial);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn source_get_env() -> u32 {
|
|
||||||
enve::get::<u32>("TEST").unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn lazy_get_env() -> u32 {
|
|
||||||
lazy_static! {
|
|
||||||
static ref RES: u32 = source_get_env();
|
|
||||||
};
|
|
||||||
|
|
||||||
return *RES;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn source_vs_lazy(c: &mut Criterion) {
|
|
||||||
setup_env_var("TEST", "1".to_string());
|
|
||||||
|
|
||||||
let source = Fun::new("source", |b, _| {
|
|
||||||
b.iter(move || assert_eq!(source_get_env(), 1))
|
|
||||||
});
|
|
||||||
let lazy = Fun::new("lazy", |b, _| {
|
|
||||||
b.iter(move || {
|
|
||||||
assert_eq!(lazy_get_env(), 1);
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
c.bench_functions("get_env", vec![source, lazy], 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn source_macro_vs_lazy_macro(c: &mut Criterion) {
|
|
||||||
config! {
|
|
||||||
TEST: &'static str,
|
|
||||||
TEST_WITH_DEFAULT: &'static str => "default",
|
|
||||||
|
|
||||||
static LAZY_TEST: &'static str,
|
|
||||||
static LAZY_TEST_WITH_DEFAULT: &'static str => "default",
|
|
||||||
}
|
|
||||||
|
|
||||||
setup_env_var("TEST", "test".to_string());
|
|
||||||
setup_env_var("LAZY_TEST", "test".to_string());
|
|
||||||
|
|
||||||
let source = Fun::new("source", |b, _| {
|
|
||||||
b.iter(move || {
|
|
||||||
assert_eq!(config::TEST(), "test");
|
|
||||||
})
|
|
||||||
});
|
|
||||||
let lazy = Fun::new("lazy", |b, _| {
|
|
||||||
b.iter(move || {
|
|
||||||
assert_eq!(config::LAZY_TEST(), "test");
|
|
||||||
})
|
|
||||||
});
|
|
||||||
let source_with_default = Fun::new("source_with_default", |b, _| {
|
|
||||||
b.iter(move || {
|
|
||||||
assert_eq!(config::TEST_WITH_DEFAULT(), "default");
|
|
||||||
})
|
|
||||||
});
|
|
||||||
let lazy_with_default = Fun::new("lazy_with_default", |b, _| {
|
|
||||||
b.iter(move || {
|
|
||||||
assert_eq!(config::LAZY_TEST_WITH_DEFAULT(), "default");
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
let funcs = vec![source, lazy, source_with_default, lazy_with_default];
|
|
||||||
|
|
||||||
c.bench_functions("macro", funcs, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
criterion_group! {
|
|
||||||
benches,
|
|
||||||
source_vs_lazy,
|
|
||||||
source_macro_vs_lazy_macro,
|
|
||||||
}
|
|
||||||
|
|
||||||
criterion_main!(benches);
|
|
|
@ -1,29 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "enve_mod"
|
|
||||||
version = "1.1.1"
|
|
||||||
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/pleshevskiy/enve"
|
|
||||||
homepage = "https://github.com/pleshevskiy/enve"
|
|
||||||
documentation = "https://docs.rs/enve"
|
|
||||||
readme = "../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.60"
|
|
||||||
quote = "1.0.9"
|
|
||||||
proc-macro2 = "1.0.24"
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
enve = { path = ".." }
|
|
||||||
lazy_static = "1.4.0"
|
|
||||||
|
|
||||||
[badges]
|
|
||||||
maintenance = { status = "actively-developed" }
|
|
|
@ -1,29 +0,0 @@
|
||||||
use crate::utils::SupportedBox;
|
|
||||||
use proc_macro2::TokenStream as TokenStream2;
|
|
||||||
use syn::{Attribute, Expr, Ident, Type};
|
|
||||||
|
|
||||||
pub(crate) struct RootNamespace {
|
|
||||||
pub name: Option<Ident>,
|
|
||||||
pub variables: Vec<Variable>,
|
|
||||||
pub namespaces: Vec<Namespace>,
|
|
||||||
pub meta: Vec<Attribute>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct Namespace {
|
|
||||||
pub name: Ident,
|
|
||||||
pub variables: Vec<Variable>,
|
|
||||||
pub namespaces: Vec<Namespace>,
|
|
||||||
pub env_prefix: Option<String>,
|
|
||||||
pub meta: Vec<Attribute>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) 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>,
|
|
||||||
pub supported_box: Option<SupportedBox>,
|
|
||||||
}
|
|
|
@ -1,186 +0,0 @@
|
||||||
use crate::ast::*;
|
|
||||||
use crate::utils::{vec_to_token_stream_2, SupportedBox};
|
|
||||||
use proc_macro2::TokenStream as TokenStream2;
|
|
||||||
use quote::{quote, ToTokens, TokenStreamExt};
|
|
||||||
|
|
||||||
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_else(|| 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 let Some(initial) = &self.initial {
|
|
||||||
match self.supported_box.clone() {
|
|
||||||
Some(SupportedBox::Vec(params)) => {
|
|
||||||
let sep = ¶ms.sep();
|
|
||||||
quote!(::itconfig::get_vec_env_or_set_default(#env_name, #sep, #initial))
|
|
||||||
}
|
|
||||||
_ => quote!(::itconfig::get_env_or_set_default(#env_name, #initial)),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
match self.supported_box.clone() {
|
|
||||||
Some(SupportedBox::Option) => {
|
|
||||||
quote!(::itconfig::maybe_get_env(#env_name))
|
|
||||||
}
|
|
||||||
Some(SupportedBox::OptionVec(params)) => {
|
|
||||||
let sep = ¶ms.sep();
|
|
||||||
quote!(::itconfig::maybe_get_vec_env(#env_name, #sep))
|
|
||||||
}
|
|
||||||
Some(SupportedBox::Vec(params)) => {
|
|
||||||
let sep = ¶ms.sep();
|
|
||||||
quote!(::itconfig::get_vec_env_or_panic(#env_name, #sep))
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
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
|
|
||||||
}
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,342 +0,0 @@
|
||||||
#![recursion_limit = "256"]
|
|
||||||
#![deny(clippy::all)]
|
|
||||||
#![forbid(unsafe_code)]
|
|
||||||
#![forbid(non_ascii_idents)]
|
|
||||||
|
|
||||||
mod ast;
|
|
||||||
mod expand;
|
|
||||||
mod parse;
|
|
||||||
mod utils;
|
|
||||||
|
|
||||||
extern crate proc_macro;
|
|
||||||
extern crate proc_macro2;
|
|
||||||
|
|
||||||
use self::proc_macro::TokenStream;
|
|
||||||
use ast::RootNamespace;
|
|
||||||
use quote::ToTokens;
|
|
||||||
use syn::parse_macro_input;
|
|
||||||
|
|
||||||
/// ### _This API requires the following crate features to be activated: `macro`_
|
|
||||||
///
|
|
||||||
/// Creates new public mod with function fo get each environment variable of mapping.
|
|
||||||
///
|
|
||||||
/// All variables are required and program will panic if some variables haven't value, but you
|
|
||||||
/// can add default value for specific variable.
|
|
||||||
///
|
|
||||||
/// Starts with v0.6.0 if you don't have an optional variable, the variable is set automatically.
|
|
||||||
///
|
|
||||||
/// Example usage
|
|
||||||
/// -------------
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # use itconfig::config;
|
|
||||||
/// # use std::env;
|
|
||||||
/// config! {
|
|
||||||
/// DATABASE_URL: String,
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// # fn main() {
|
|
||||||
/// # env::set_var("DATABASE_URL", "postgres://u:p@localhost:5432/db");
|
|
||||||
/// # config::init();
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// Config with default value
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # use itconfig::config;
|
|
||||||
/// # use std::env;
|
|
||||||
/// config! {
|
|
||||||
/// DATABASE_URL: String,
|
|
||||||
/// HOST: String => "127.0.0.1",
|
|
||||||
/// }
|
|
||||||
/// # fn main() {
|
|
||||||
/// # env::set_var("DATABASE_URL", "postgres://u:p@localhost:5432/db");
|
|
||||||
/// # config::init();
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// By default itconfig lib creates module with 'config' name. But you can use simple meta instruction
|
|
||||||
/// if you want to rename module. In the example below we renamed module to 'configuration'
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # use itconfig::config;
|
|
||||||
/// # use std::env;
|
|
||||||
/// config! {
|
|
||||||
/// #![config(name = "configuration")]
|
|
||||||
///
|
|
||||||
/// DEBUG: bool,
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// env::set_var("DEBUG", "t");
|
|
||||||
///
|
|
||||||
/// configuration::init();
|
|
||||||
/// assert_eq!(configuration::DEBUG(), true);
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// You also unwrap first config module
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # use itconfig::config;
|
|
||||||
/// # use std::env;
|
|
||||||
///
|
|
||||||
/// config! {
|
|
||||||
/// #![config(unwrap)]
|
|
||||||
///
|
|
||||||
/// DEBUG: bool,
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// env::set_var("DEBUG", "t");
|
|
||||||
///
|
|
||||||
/// init();
|
|
||||||
/// assert_eq!(DEBUG(), true);
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
///
|
|
||||||
/// Namespaces
|
|
||||||
/// ----------
|
|
||||||
///
|
|
||||||
/// You can use namespaces for env variables
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # use itconfig::config;
|
|
||||||
/// # use std::env;
|
|
||||||
///
|
|
||||||
/// config! {
|
|
||||||
/// DEBUG: bool,
|
|
||||||
/// DATABASE {
|
|
||||||
/// USERNAME: String,
|
|
||||||
/// PASSWORD: String,
|
|
||||||
/// HOST: String,
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
/// fn main() {
|
|
||||||
/// env::set_var("DEBUG", "t");
|
|
||||||
/// env::set_var("DATABASE_USERNAME", "user");
|
|
||||||
/// env::set_var("DATABASE_PASSWORD", "pass");
|
|
||||||
/// env::set_var("DATABASE_HOST", "localhost");
|
|
||||||
///
|
|
||||||
/// config::init();
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// Now you can use nested structure in namespaces without limits :)
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # use itconfig::config;
|
|
||||||
/// config! {
|
|
||||||
/// FIRST {
|
|
||||||
/// SECOND {
|
|
||||||
/// THIRD {
|
|
||||||
/// FOO: bool => true,
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
/// # fn main() { config::init () }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// Namespaces supports custom meta
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # use itconfig::config;
|
|
||||||
/// config! {
|
|
||||||
/// #[cfg(feature = "first")]
|
|
||||||
/// FIRST {
|
|
||||||
/// #[cfg(feature = "second")]
|
|
||||||
/// SECOND {
|
|
||||||
/// #[cfg(feature = "third")]
|
|
||||||
/// THIRD {
|
|
||||||
/// FOO: bool => true,
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
/// # fn main() { config::init () }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// Meta
|
|
||||||
/// ----
|
|
||||||
///
|
|
||||||
/// If you want to read custom env name for variable you can change it manually.
|
|
||||||
///
|
|
||||||
/// **A variable in the nameespace will lose environment prefix**
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # use itconfig::config;
|
|
||||||
/// # use std::env;
|
|
||||||
///
|
|
||||||
/// config! {
|
|
||||||
/// #[env_name = "MY_CUSTOM_NAME"]
|
|
||||||
/// PER_PAGE: i32,
|
|
||||||
///
|
|
||||||
/// APP {
|
|
||||||
/// #[env_name = "MY_CUSTOM_NAME"]
|
|
||||||
/// RECIPES_PER_PAGE: i32,
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// env::set_var("MY_CUSTOM_NAME", "95");
|
|
||||||
///
|
|
||||||
/// config::init();
|
|
||||||
/// assert_eq!(config::PER_PAGE(), 95);
|
|
||||||
/// assert_eq!(config::APP::RECIPES_PER_PAGE(), 95);
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// Also you can add custom meta for each variable. For example feature configurations.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # use itconfig::config;
|
|
||||||
/// config! {
|
|
||||||
/// #[cfg(feature = "postgres")]
|
|
||||||
/// DATABASE_URL: String,
|
|
||||||
///
|
|
||||||
/// #[cfg(not(feature = "postgres"))]
|
|
||||||
/// DATABASE_URL: String,
|
|
||||||
/// }
|
|
||||||
/// # fn main() { }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// Concatenate
|
|
||||||
/// -----------
|
|
||||||
///
|
|
||||||
/// Try to concatenate env variable or strings or both to you env variable. It's easy!
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # use itconfig::config;
|
|
||||||
/// # use std::env;
|
|
||||||
/// config! {
|
|
||||||
/// DATABASE_URL < (
|
|
||||||
/// "postgres://",
|
|
||||||
/// POSTGRES_USERNAME,
|
|
||||||
/// ":",
|
|
||||||
/// POSTGRES_PASSWORD,
|
|
||||||
/// "@",
|
|
||||||
/// POSTGRES_HOST => "localhost:5432",
|
|
||||||
/// "/",
|
|
||||||
/// POSTGRES_DB => "test",
|
|
||||||
/// ),
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// env::set_var("POSTGRES_USERNAME", "user");
|
|
||||||
/// env::set_var("POSTGRES_PASSWORD", "pass");
|
|
||||||
///
|
|
||||||
/// config::init();
|
|
||||||
/// assert_eq!(config::DATABASE_URL(), "postgres://user:pass@localhost:5432/test".to_string());
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// Concatinated variables can be only strings and support all features like namespaces and meta.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # use itconfig::config;
|
|
||||||
/// config! {
|
|
||||||
/// CONCATED_NAMESPACE {
|
|
||||||
/// #[env_name = "DATABASE_URL"]
|
|
||||||
/// CONCAT_ENVVAR < (
|
|
||||||
/// "postgres://",
|
|
||||||
/// NOT_DEFINED_PG_USERNAME => "user",
|
|
||||||
/// ":",
|
|
||||||
/// NOT_DEFINED_PG_PASSWORD => "pass",
|
|
||||||
/// "@",
|
|
||||||
/// NOT_DEFINED_PG_HOST => "localhost:5432",
|
|
||||||
/// "/",
|
|
||||||
/// NOT_DEFINED_PG_DB => "test",
|
|
||||||
/// ),
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
/// # fn main() { config::init () }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// Static
|
|
||||||
/// ------
|
|
||||||
///
|
|
||||||
/// Starting with 0.11 version you can use lazy static for improve speed of variable. This is very
|
|
||||||
/// useful, if you use variable more than once.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # use itconfig::config;
|
|
||||||
/// # use std::env;
|
|
||||||
/// config! {
|
|
||||||
/// static APP_BASE_URL => "/api",
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// fn main () {
|
|
||||||
/// env::set_var("APP_BASE_URL", "/api/v1");
|
|
||||||
///
|
|
||||||
/// config::init();
|
|
||||||
/// assert_eq!(config::APP_BASE_URL(), "/api/v1");
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// You also can use static with concat variables
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # use itconfig::config;
|
|
||||||
/// config! {
|
|
||||||
/// static CONNECTION_STRING < (
|
|
||||||
/// "postgres://",
|
|
||||||
/// NOT_DEFINED_PG_USERNAME => "user",
|
|
||||||
/// ":",
|
|
||||||
/// NOT_DEFINED_PG_PASSWORD => "pass",
|
|
||||||
/// "@",
|
|
||||||
/// NOT_DEFINED_PG_HOST => "localhost:5432",
|
|
||||||
/// "/",
|
|
||||||
/// NOT_DEFINED_PG_DB => "test",
|
|
||||||
/// ),
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// fn main () {
|
|
||||||
/// config::init();
|
|
||||||
/// assert_eq!(config::CONNECTION_STRING(), "postgres://user:pass@localhost:5432/test".to_string());
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
///
|
|
||||||
/// ---
|
|
||||||
///
|
|
||||||
/// This module will also contain helper method:
|
|
||||||
/// --------------------------------------------
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// pub fn init() {}
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// Run this at the main function for check all required variables without default value.
|
|
||||||
///
|
|
||||||
/// Panics
|
|
||||||
/// ------
|
|
||||||
///
|
|
||||||
/// If you miss some required variables your application will panic at startup.
|
|
||||||
///
|
|
||||||
/// Examples
|
|
||||||
/// --------
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # use itconfig::config;
|
|
||||||
/// // use dotenv::dotenv;
|
|
||||||
///
|
|
||||||
/// config! {
|
|
||||||
/// DEBUG: bool => true,
|
|
||||||
/// HOST: String => "127.0.0.1",
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// fn main () {
|
|
||||||
/// // dotenv().ok();
|
|
||||||
/// config::init();
|
|
||||||
/// assert_eq!(config::HOST(), String::from("127.0.0.1"));
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
#[proc_macro]
|
|
||||||
pub fn config(input: TokenStream) -> TokenStream {
|
|
||||||
let namespace = parse_macro_input!(input as RootNamespace);
|
|
||||||
namespace.into_token_stream().into()
|
|
||||||
}
|
|
|
@ -1,284 +0,0 @@
|
||||||
use crate::ast::*;
|
|
||||||
use crate::utils::{maybe_supported_box, SupportedBox, VecBoxParams};
|
|
||||||
use proc_macro2::{Ident, Span, TokenStream as TokenStream2};
|
|
||||||
use quote::quote;
|
|
||||||
use syn::ext::IdentExt;
|
|
||||||
use syn::parse::{Parse, ParseBuffer, ParseStream, Result};
|
|
||||||
use syn::token::{Brace, Colon, Comma, FatArrow, Lt};
|
|
||||||
use syn::{
|
|
||||||
braced, parenthesized, parse_str, Attribute, Error, Expr, Lit, Meta, MetaList, MetaNameValue,
|
|
||||||
NestedMeta, Token, Type,
|
|
||||||
};
|
|
||||||
|
|
||||||
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());
|
|
||||||
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") {
|
|
||||||
let env_prefix = parse_attribute(attr, "env_prefix", &namespace.env_prefix)?;
|
|
||||||
namespace.env_prefix = Some(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") {
|
|
||||||
let env_name = parse_attribute(attr, "env_name", &variable.env_name)?;
|
|
||||||
variable.env_name = Some(env_name);
|
|
||||||
} else {
|
|
||||||
match variable.supported_box {
|
|
||||||
Some(SupportedBox::Vec(params)) if attr.path.is_ident("sep") => {
|
|
||||||
let sep = parse_attribute(attr, "sep", ¶ms.sep_opt())?;
|
|
||||||
variable.supported_box =
|
|
||||||
Some(SupportedBox::Vec(VecBoxParams::new(Some(sep))));
|
|
||||||
}
|
|
||||||
_ => variable.meta.push(attr),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
variables.push(variable);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_attribute(attr: Attribute, name: &'static str, var: &Option<String>) -> Result<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(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 =
|
|
||||||
"expected #[config(name = \"...\")] or #[config(unwrap)]".to_string();
|
|
||||||
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 {
|
|
||||||
return Err(Error::new_spanned(attr, message));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(Meta::Path(path)) => {
|
|
||||||
if path.is_ident("unwrap") {
|
|
||||||
name = None;
|
|
||||||
with_module = false;
|
|
||||||
} else {
|
|
||||||
return Err(Error::new_spanned(attr, message));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return Err(Error::new_spanned(attr, message));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
let message = "expected #[config(...)]".to_string();
|
|
||||||
return 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))
|
|
||||||
.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")?
|
|
||||||
};
|
|
||||||
|
|
||||||
let supported_box = maybe_supported_box(&ty);
|
|
||||||
|
|
||||||
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_else(|| 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 {
|
|
||||||
supported_box,
|
|
||||||
is_static,
|
|
||||||
name,
|
|
||||||
ty,
|
|
||||||
initial,
|
|
||||||
concat_parts,
|
|
||||||
env_name: None,
|
|
||||||
meta: vec![],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,88 +0,0 @@
|
||||||
use proc_macro2::TokenStream as TokenStream2;
|
|
||||||
use quote::ToTokens;
|
|
||||||
use syn::{GenericArgument, Path, PathArguments, Type};
|
|
||||||
|
|
||||||
const OPTION_PATH_IDENTS: &[&str] = &["Option|", "std|option|Option|", "core|option|Option|"];
|
|
||||||
const VEC_PATH_IDENTS: &[&str] = &["Vec|", "std|vec|Vec|"];
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
|
||||||
pub(crate) struct VecBoxParams(Option<String>);
|
|
||||||
|
|
||||||
impl VecBoxParams {
|
|
||||||
#[inline]
|
|
||||||
pub(crate) fn new(sep: Option<String>) -> Self {
|
|
||||||
VecBoxParams(sep)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub(crate) fn sep_opt(&self) -> Option<String> {
|
|
||||||
self.0.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub(crate) fn sep(&self) -> String {
|
|
||||||
self.0.clone().unwrap_or_else(|| String::from(","))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub(crate) enum SupportedBox {
|
|
||||||
Vec(VecBoxParams),
|
|
||||||
Option,
|
|
||||||
OptionVec(VecBoxParams),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn vec_to_token_stream_2<T>(input: &[T]) -> Vec<TokenStream2>
|
|
||||||
where
|
|
||||||
T: ToTokens,
|
|
||||||
{
|
|
||||||
input.iter().map(|ns| ns.into_token_stream()).collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn path_ident(path: &Path) -> String {
|
|
||||||
path.segments
|
|
||||||
.iter()
|
|
||||||
.into_iter()
|
|
||||||
.fold(String::with_capacity(250), |mut acc, v| {
|
|
||||||
acc.push_str(&v.ident.to_string());
|
|
||||||
acc.push('|');
|
|
||||||
acc
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_option_path_ident(path_ident: &str) -> bool {
|
|
||||||
OPTION_PATH_IDENTS.iter().any(|s| path_ident == *s)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_vec_path_ident(path_ident: &str) -> bool {
|
|
||||||
VEC_PATH_IDENTS.iter().any(|s| path_ident == *s)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn maybe_supported_box(ty: &Type) -> Option<SupportedBox> {
|
|
||||||
match ty {
|
|
||||||
Type::Path(ty_path) if ty_path.qself.is_none() => {
|
|
||||||
let ty_path_ident = path_ident(&ty_path.path);
|
|
||||||
if is_option_path_ident(&ty_path_ident) {
|
|
||||||
if let PathArguments::AngleBracketed(params) =
|
|
||||||
&ty_path.path.segments.iter().last().unwrap().arguments
|
|
||||||
{
|
|
||||||
if let Some(GenericArgument::Type(Type::Path(inner_ty_path))) =
|
|
||||||
params.args.first()
|
|
||||||
{
|
|
||||||
let ty_path_ident = path_ident(&inner_ty_path.path);
|
|
||||||
if is_vec_path_ident(&ty_path_ident) {
|
|
||||||
return Some(SupportedBox::OptionVec(Default::default()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(SupportedBox::Option)
|
|
||||||
} else if is_vec_path_ident(&ty_path_ident) {
|
|
||||||
Some(SupportedBox::Vec(Default::default()))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -156,8 +156,3 @@ pub mod estr;
|
||||||
pub use self::core::*;
|
pub use self::core::*;
|
||||||
pub use self::core::{get, get_or_set_default, sget, sset};
|
pub use self::core::{get, get_or_set_default, sget, sset};
|
||||||
pub use self::error::Error;
|
pub use self::error::Error;
|
||||||
|
|
||||||
#[cfg(feature = "macro")]
|
|
||||||
extern crate enve_mod;
|
|
||||||
#[cfg(feature = "macro")]
|
|
||||||
pub use enve_mod::*;
|
|
||||||
|
|
Reference in a new issue