From 175798acf3c929e6e5ba9b55749782fb1200bf97 Mon Sep 17 00:00:00 2001 From: Dmitriy Pleshevskiy Date: Sat, 8 Feb 2020 15:09:58 +0300 Subject: [PATCH] feat: add lazy static Closes #13 --- itconfig-tests/Cargo.toml | 3 +- itconfig-tests/benches/main_benches.rs | 63 ++++++++++--- itconfig-tests/tests/config_macro.rs | 48 ++++++++++ itconfig/Cargo.toml | 7 +- itconfig/src/envstr.rs | 9 ++ itconfig/src/lib.rs | 6 +- itconfig/src/macro.rs | 126 ++++++++++++++++++++++--- 7 files changed, 232 insertions(+), 30 deletions(-) diff --git a/itconfig-tests/Cargo.toml b/itconfig-tests/Cargo.toml index fbc6ede..f02b22a 100644 --- a/itconfig-tests/Cargo.toml +++ b/itconfig-tests/Cargo.toml @@ -14,8 +14,9 @@ criterion = "0.3.1" lazy_static = "1.4.0" [features] -default = ["meta_namespace"] +default = ["meta_namespace", "static"] meta_namespace = [] +static = ["itconfig/static"] [[bench]] name = "main_benches" diff --git a/itconfig-tests/benches/main_benches.rs b/itconfig-tests/benches/main_benches.rs index bdef991..56c9193 100644 --- a/itconfig-tests/benches/main_benches.rs +++ b/itconfig-tests/benches/main_benches.rs @@ -3,11 +3,13 @@ use std::env; #[macro_use] extern crate lazy_static; +#[macro_use] +extern crate itconfig; -fn setup_env_var(initial: &String) { - env::set_var("TEST", initial); +fn setup_env_var(key: &'static str, initial: String) { + env::set_var(key, initial); } @@ -26,33 +28,66 @@ fn lazy_get_env() -> u32 { fn source_vs_lazy(c: &mut Criterion) { - let source = Fun::new("source", |b, initial: &String| { - setup_env_var(initial); - let int: u32 = initial.parse().unwrap(); + setup_env_var("TEST", "1".to_string()); + let source = Fun::new("source", |b, _| { b.iter(move || { - assert_eq!(source_get_env(), int) + assert_eq!(source_get_env(), 1) }) }); - let lazy = Fun::new("lazy", |b, initial: &String| { - setup_env_var(initial); - let int: u32 = initial.parse().unwrap(); - + let lazy = Fun::new("lazy", |b, _| { b.iter(move || { - assert_eq!(lazy_get_env(), int); + assert_eq!(lazy_get_env(), 1); }) }); - let funcs = vec![source, lazy]; - - c.bench_functions("get_env", funcs, "1".to_string()); + 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!(cfg::TEST(), "test"); + }) + }); + let lazy = Fun::new("lazy", |b, _| { + b.iter(move || { + assert_eq!(cfg::LAZY_TEST(), "test"); + }) + }); + let source_with_default = Fun::new("source_with_default", |b, _| { + b.iter(move || { + assert_eq!(cfg::TEST_WITH_DEFAULT(), "default"); + }) + }); + let lazy_with_default = Fun::new("lazy_with_default", |b, _| { + b.iter(move || { + assert_eq!(cfg::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); diff --git a/itconfig-tests/tests/config_macro.rs b/itconfig-tests/tests/config_macro.rs index 4bd7d02..0507387 100644 --- a/itconfig-tests/tests/config_macro.rs +++ b/itconfig-tests/tests/config_macro.rs @@ -422,3 +422,51 @@ fn concatenated_environment_variable_in_namespace() { ); assert_eq!(env::var("CONCAT_ENVVAR"), Err(VarError::NotPresent)); } + + +#[test] +#[cfg(feature = "static")] +fn static_variables() { + config! { + static STATIC_STR => "test", + static STATIC_STRING: String => "test", + static STATIC_I8: i8 => 1, + static STATIC_I16: i16 => 1, + static STATIC_I32: i32 => 1, + static STATIC_I64: i64 => 1, + static STATIC_I128: i128 => 1, + static STATIC_ISIZE: isize => 1, + static STATIC_U8: u8 => 1, + static STATIC_U16: u16 => 1, + static STATIC_U32: u32 => 1, + static STATIC_U64: u64 => 1, + static STATIC_U128: u128 => 1, + static STATIC_USIZE: usize => 1, + static STATIC_F32: f32 => 1, + static STATIC_F64: f64 => 1, + static STATIC_CONCAT_VARIABLE < ( + "static ", + STATIC_CONCAT_PART => "part", + ), + } + + cfg::init(); + + assert_eq!(cfg::STATIC_STR(), "test"); + assert_eq!(cfg::STATIC_STRING(), "test".to_string()); + assert_eq!(cfg::STATIC_I8(), 1); + assert_eq!(cfg::STATIC_I16(), 1); + assert_eq!(cfg::STATIC_I32(), 1); + assert_eq!(cfg::STATIC_I64(), 1); + assert_eq!(cfg::STATIC_I128(), 1); + assert_eq!(cfg::STATIC_ISIZE(), 1); + assert_eq!(cfg::STATIC_U8(), 1); + assert_eq!(cfg::STATIC_U16(), 1); + assert_eq!(cfg::STATIC_U32(), 1); + assert_eq!(cfg::STATIC_U64(), 1); + assert_eq!(cfg::STATIC_U128(), 1); + assert_eq!(cfg::STATIC_USIZE(), 1); + assert_eq!(cfg::STATIC_F32(), 1.0); + assert_eq!(cfg::STATIC_F64(), 1.0); + assert_eq!(cfg::STATIC_CONCAT_VARIABLE(), "static part".to_string()) +} diff --git a/itconfig/Cargo.toml b/itconfig/Cargo.toml index fbd46e5..6e92a30 100644 --- a/itconfig/Cargo.toml +++ b/itconfig/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "itconfig" -version = "0.10.2" +version = "0.11.0" authors = ["Dmitriy Pleshevskiy "] description = "Easy build a configs from environment variables and use it in globally." categories = ["config", "web-programming"] @@ -16,11 +16,14 @@ readme = "README.md" [dependencies] failure = { version = "0.1.6", features = ["derive"]} +lazy_static = { version = "1.4.0", optional = true } serde_json = { version = "1.0.44", optional = true } [features] -default = ["macro", "primitives"] +default = ["macro", "primitives", "static"] + macro = [] +static = ["lazy_static"] array = ["serde_json"] diff --git a/itconfig/src/envstr.rs b/itconfig/src/envstr.rs index 4fa7016..c46a1b2 100644 --- a/itconfig/src/envstr.rs +++ b/itconfig/src/envstr.rs @@ -119,6 +119,15 @@ impl FromEnvString for String { } +impl FromEnvString for &'static str { + type Err = (); + + fn from_env_string(s: &EnvString) -> Result { + Ok(Box::leak(s.0.clone().into_boxed_str())) + } +} + + #[doc(hidden)] #[derive(Debug, PartialEq, Clone)] pub struct EnvString(String); diff --git a/itconfig/src/lib.rs b/itconfig/src/lib.rs index 2b98cac..56cfe99 100644 --- a/itconfig/src/lib.rs +++ b/itconfig/src/lib.rs @@ -87,12 +87,14 @@ // Rustc lints. -#![deny(unused_imports)] +//#![deny(unused_imports)] ///////////////////////////////////////////////////////////////////////////// #[macro_use] extern crate failure; +#[cfg(feature = "static")] +extern crate lazy_static; mod enverr; mod getenv; @@ -108,7 +110,7 @@ pub mod prelude { #[cfg(feature = "macro")] -#[allow(unused_imports)] +//#[allow(unused_imports)] #[macro_use] mod r#macro; #[cfg(feature = "macro")] diff --git a/itconfig/src/macro.rs b/itconfig/src/macro.rs index 87fa5e0..47118f5 100644 --- a/itconfig/src/macro.rs +++ b/itconfig/src/macro.rs @@ -301,6 +301,14 @@ macro_rules! __itconfig_parse_module { } +#[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 { @@ -329,6 +337,30 @@ macro_rules! __itconfig_parse_variables { } }; + // Find static concatenated variable + ( + tokens = [ + $(#$meta:tt)* + static $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 = true, + }, + tokens = [$($rest)*], + $($args)* + } + }; + // Find concatenated variable ( tokens = [ @@ -346,17 +378,18 @@ macro_rules! __itconfig_parse_variables { concat = [], name = $name, ty = String, + is_static = false, }, tokens = [$($rest)*], $($args)* } }; - // Find variable + // Find static variable ( tokens = [ $(#$meta:tt)* - $name:ident : $ty:ty$( => $default:expr)?, + static $name:ident $(: $ty:ty)? $(=> $default:expr)?, $($rest:tt)* ], $($args:tt)* @@ -368,7 +401,33 @@ macro_rules! __itconfig_parse_variables { unparsed_concat = [], concat = [], name = $name, - ty = $ty, + ty = __itconfig_get_ty_or_default!($($ty)?), + is_static = true, + $(default = $default,)? + }, + tokens = [$($rest)*], + $($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)*], @@ -523,6 +582,9 @@ macro_rules! __itconfig_impl_namespace { 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 = [$({ @@ -543,6 +605,8 @@ macro_rules! __itconfig_impl_namespace { $(#$meta)* pub mod $mod_name { #![allow(non_snake_case)] + #[cfg(feature = "static")] + use lazy_static::lazy_static; $(__itconfig_impl_namespace! { variables = $ns_variable, @@ -567,6 +631,9 @@ macro_rules! __itconfig_impl_namespace { concat = $var_concat, name = $var_name, env_prefix = $env_prefix, + $(env_name = $env_name,)? + ty = $ty, + is_static = $is_static, $($variable)* })* } @@ -630,37 +697,74 @@ macro_rules! __itconfig_variable { // Add method for env variable ( - meta = [$(#$meta:tt,)*], + 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,)? ) => { - $(#$meta)* - pub fn $name() -> $ty { - __itconfig_variable! { + __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 = vec!($($concat),+); let value = value_parts.join(""); std::env::set_var($env_name, value.as_str()); value - ); + }); // Env without default (