Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding CustomFn layer #34

Merged
merged 5 commits into from
Jun 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ For now it supports :

- Default settings (inside your codebase with `#[serde(default = ...)]` coming from [serde](https://serde.rs))
- Reading from `TOML`, `YAML`, `JSON`, `DHALL`, `INI` files
- Executing a custom function or closure to supply values via a [serde_json::Value]
- Reading from environment variables: it supports `HashMap` structure with `MY_VARIABLE="mykey=myvalue,mykey2=myvalue2"` and also array like `MY_VARIABLE=first,second` thanks to [envy](https://github.com/softprops/envy).
- All [serde](https://serde.rs) attributes can be used in your struct to customize your configuration as you wish
- Reading your configuration from your command line built with [clap](https://github.com/clap-rs/clap) (ATTENTION: if you're using version < v3 use the `twelf@0.1.8` version, if you're using `[email protected]` please use `[email protected]`)
- Reading your configuration from your command line built with [clap](https://github.com/clap-rs/clap) (ATTENTION: if you're using version < v3 use the `[email protected]` version)

# Usage

Expand All @@ -23,6 +24,7 @@ For now it supports :
use twelf::{config, Layer};

#[config]
#[derive(Default)]
struct Conf {
test: String,
another: usize,
Expand All @@ -49,7 +51,6 @@ struct Conf {

// Will generate global arguments for each of your fields inside your configuration struct
let app = clap::Command::new("test").args(&Conf::clap_args());
// If you're looking for how to use with clap derive feature, check in the examples directory (twelf/examples/clap_derive.rs)

// Init configuration with layers, each layers override only existing fields
let config = Conf::with_layers(&[
Expand All @@ -68,9 +69,13 @@ Check [here](./twelf/examples) for more examples.
Twelf supports crate features, if you only want support for `json`, `env` and `toml` then you just have to add this to your `Cargo.toml`

```toml
twelf = { version = "0.4", default-features = false, features = ["json", "toml", "env"] }
twelf = { version = "0.11", default-features = false, features = ["json", "toml", "env"] }
```

`default_trait` enables code for a layer that integrate fields derived with the [std::default::Default] trait.

`custom_fn` enables code for a layer that allows a custom closure to be executed.

Default features are `["env", "clap"]`

# Contributing
Expand Down
1 change: 1 addition & 0 deletions config-derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,4 @@
toml = []
yaml = []
default_trait = []
custom_fn = []
10 changes: 8 additions & 2 deletions config-derive/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ For now it supports :

- Default settings (inside your codebase with `#[serde(default = ...)]` coming from [serde](https://serde.rs))
- Reading from `TOML`, `YAML`, `JSON`, `DHALL`, `INI` files
- Executing a custom function or closure to supply values via a [serde_json::Value]
- Reading from environment variables: it supports `HashMap` structure with `MY_VARIABLE="mykey=myvalue,mykey2=myvalue2"` and also array like `MY_VARIABLE=first,second` thanks to [envy](https://github.com/softprops/envy).
- All [serde](https://serde.rs) attributes can be used in your struct to customize your configuration as you wish
- Reading your configuration from your command line built with [clap](https://github.com/clap-rs/clap) (ATTENTION: if you're using version < v3 use the `twelf@1.8` version)
- Reading your configuration from your command line built with [clap](https://github.com/clap-rs/clap) (ATTENTION: if you're using version < v3 use the `twelf@0.8` version)

# Usage

Expand All @@ -23,6 +24,7 @@ For now it supports :
use twelf::{config, Layer};

#[config]
#[derive(Default)]
struct Conf {
test: String,
another: usize,
Expand Down Expand Up @@ -67,9 +69,13 @@ Check [here](./twelf/examples) for more examples.
Twelf supports crate features, if you only want support for `json`, `env` and `toml` then you just have to add this to your `Cargo.toml`

```toml
twelf = { version = "0.3", default-features = false, features = ["json", "toml", "env"] }
twelf = { version = "0.11", default-features = false, features = ["json", "toml", "env"] }
```

`default_trait` enables code for a layer that integrate fields derived with the [std::default::Default] trait.

`custom_fn` enables code for a layer that allows a custom closure to be executed.

Default features are `["env", "clap"]`

# Contributing
Expand Down
14 changes: 12 additions & 2 deletions config-derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ pub fn config(_attrs: TokenStream, item: TokenStream) -> TokenStream {
let yaml_branch = build_yaml_branch();
let dhall_branch = build_dhall_branch();
let default_trait_branch = build_default_trait_branch();
let custom_fn_branch = build_custom_fn_branch();

#[cfg(not(feature = "ini"))]
let ini_branch = quote! {};
Expand All @@ -141,9 +142,9 @@ pub fn config(_attrs: TokenStream, item: TokenStream) -> TokenStream {
docs,
);

#[cfg(not(feature = "default_trait"))]
#[cfg(all(not(feature = "default_trait"), not(feature = "custom_fn")))]
let derive_serialize = quote! {};
#[cfg(feature = "default_trait")]
#[cfg(any(feature = "default_trait", feature = "custom_fn"))]
let derive_serialize = quote! { #[derive(::twelf::reexports::serde::Serialize)] };

let code = quote! {
Expand Down Expand Up @@ -192,6 +193,7 @@ pub fn config(_attrs: TokenStream, item: TokenStream) -> TokenStream {
#ini_branch
#clap_branch
#default_trait_branch
#custom_fn_branch
other => unimplemented!("{:?}", other)
};

Expand Down Expand Up @@ -327,3 +329,11 @@ fn build_default_trait_branch() -> proc_macro2::TokenStream {
let default_trait_branch = quote! {};
default_trait_branch
}

fn build_custom_fn_branch() -> proc_macro2::TokenStream {
#[cfg(feature = "custom_fn")]
let custom_branch = quote! { ::twelf::Layer::CustomFn(custom_fn) => (custom_fn.clone().0(),None), };
#[cfg(not(feature = "custom_fn"))]
let custom_branch = quote! {};
custom_branch
}
2 changes: 2 additions & 0 deletions twelf/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
serde_yaml = { version = "0.8.23", optional = true }
thiserror = "1"
toml_rs = { version = "0.5.8", package = "toml", optional = true }
dyn-clone = { version = "1.0.0", optional = true }

[features]
clap = ["clap_rs", "config-derive/clap", "envy"]
Expand All @@ -34,3 +35,4 @@
toml = ["toml_rs", "config-derive/toml"]
yaml = ["serde_yaml", "config-derive/yaml"]
default_trait = ["config-derive/default_trait"]
custom_fn = ["dyn-clone", "config-derive/custom_fn"]
8 changes: 7 additions & 1 deletion twelf/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ For now it supports :

- Default settings (inside your codebase with `#[serde(default = ...)]` coming from [serde](https://serde.rs))
- Reading from `TOML`, `YAML`, `JSON`, `DHALL`, `INI` files
- Executing a custom function or closure to supply values via a [serde_json::Value]
- Reading from environment variables: it supports `HashMap` structure with `MY_VARIABLE="mykey=myvalue,mykey2=myvalue2"` and also array like `MY_VARIABLE=first,second` thanks to [envy](https://github.com/softprops/envy).
- All [serde](https://serde.rs) attributes can be used in your struct to customize your configuration as you wish
- Reading your configuration from your command line built with [clap](https://github.com/clap-rs/clap) (ATTENTION: if you're using version < v3 use the `[email protected]` version)
Expand All @@ -23,6 +24,7 @@ For now it supports :
use twelf::{config, Layer};

#[config]
#[derive(Default)]
struct Conf {
test: String,
another: usize,
Expand Down Expand Up @@ -67,9 +69,13 @@ Check [here](./twelf/examples) for more examples.
Twelf supports crate features, if you only want support for `json`, `env` and `toml` then you just have to add this to your `Cargo.toml`

```toml
twelf = { version = "0.3", default-features = false, features = ["json", "toml", "env"] }
twelf = { version = "0.11", default-features = false, features = ["json", "toml", "env"] }
```

`default_trait` enables code for a layer that integrate fields derived with the [std::default::Default] trait.

`custom_fn` enables code for a layer that allows a custom closure to be executed.

Default features are `["env", "clap"]`

# Contributing
Expand Down
4 changes: 2 additions & 2 deletions twelf/examples/advanced_struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ use twelf::reexports::serde::{Deserialize, Serialize};
use twelf::{config, Layer};

#[config]
#[derive(Debug)]
#[derive(Debug, Default)]
struct Config {
list: Vec<String>,
labels: HashMap<String, String>,
#[serde(flatten)]
nested: Nested,
}

#[derive(Debug, Deserialize, Serialize)]
#[derive(Debug, Default, Deserialize, Serialize)]
struct Nested {
inner: String,
}
Expand Down
2 changes: 1 addition & 1 deletion twelf/examples/clap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use clap_rs as clap;
use twelf::{config, Layer};

#[config]
#[derive(Debug)]
#[derive(Debug, Default)]
struct Config {
/// Documentation inside clap, to specifiy db_host
db_host: String,
Expand Down
2 changes: 1 addition & 1 deletion twelf/examples/clap_derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use clap_rs as clap;
use twelf::{config, Layer};

#[config]
#[derive(Parser, Debug)]
#[derive(Parser, Debug, Default)]
#[clap(author, version, about, long_about = None)]
struct Config {
#[clap(long, help = "Documentation inside clap, to specifiy db_host")]
Expand Down
2 changes: 1 addition & 1 deletion twelf/examples/default_env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use twelf::{config, Layer};

#[config]
#[derive(Debug)]
#[derive(Debug, Default)]
struct Config {
db_host: String,
threads: usize,
Expand Down
2 changes: 1 addition & 1 deletion twelf/examples/simple_env_json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use twelf::{config, Layer};

#[config]
#[derive(Debug)]
#[derive(Debug, Default)]
struct Config {
db_host: String,
threads: usize,
Expand Down
32 changes: 32 additions & 0 deletions twelf/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,36 @@ pub enum Layer {
/// Default layer, using std::default::Default trait
#[cfg(feature = "default_trait")]
DefaultTrait,
/// Custom layer, takes any function or closure that outputs a [serde_json::Value].
#[cfg(feature = "custom_fn")]
CustomFn(custom_fn::CustomFn),
}

#[cfg(feature = "custom_fn")]
pub mod custom_fn {
use dyn_clone::{DynClone, clone_box};

pub struct CustomFn(pub Box<dyn CustomFnTrait>);

impl<T> From<T> for CustomFn where T: FnOnce() -> crate::reexports::serde_json::Value + Clone + 'static {
fn from(func: T) -> Self {
CustomFn(Box::new(func) as Box<dyn CustomFnTrait>)
}
}

pub trait CustomFnTrait: FnOnce() -> crate::reexports::serde_json::Value + DynClone {}

impl<T> CustomFnTrait for T where T: Clone + FnOnce() -> crate::reexports::serde_json::Value {}

impl Clone for CustomFn {
fn clone(&self) -> Self {
CustomFn(clone_box(&*self.0) as Box<dyn CustomFnTrait>)
}
}

impl core::fmt::Debug for CustomFn {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "CustomFn")
}
}
}
6 changes: 4 additions & 2 deletions twelf/tests/clap.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![cfg(feature = "clap")]

use std::collections::HashMap;

use clap_rs as clap;
Expand All @@ -10,7 +12,7 @@ const JSON_TEST_FILE: &str = "./tests/fixtures/test.json";
#[test]
fn clap_with_array_and_hashmap() {
#[config]
#[derive(Debug)]
#[derive(Debug, Default)]
struct Conf {
/// My custom documentation on elements-snake in clap
elements_snake: HashMap<String, String>,
Expand Down Expand Up @@ -50,7 +52,7 @@ fn clap_with_array_and_hashmap() {
#[test]
fn clap_derive_array() {
#[config]
#[derive(Parser,Debug)]
#[derive(Parser,Debug, Default)]
#[clap(author, version, about, long_about = None)]
struct Conf {
#[clap(long, default_value_t = 55)]
Expand Down
32 changes: 32 additions & 0 deletions twelf/tests/custom_fn.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#![cfg(feature = "custom_fn")]

use config_derive::config;
use twelf::Layer;

use serde_json::value::to_value;

#[test]
fn simple_custom_fn() {
#[config]
#[derive(Debug, Default)]
struct TestCfg {
test: String,
another: usize,
}

std::env::set_var("ANOTHER", "5");

let func = || {
to_value(TestCfg{test: "from func".to_string(), another: 25}).unwrap()
};

let prio = vec![Layer::CustomFn(func.into()), Layer::Env(None)];
let config = TestCfg::with_layers(&prio).unwrap();
assert_eq!(config.test, String::from("from func"));
assert_eq!(config.another, 5usize);

let prio = vec![Layer::Env(None), Layer::CustomFn(func.into())];
let config = TestCfg::with_layers(&prio).unwrap();
assert_eq!(config.test, String::from("from func"));
assert_eq!(config.another, 25usize);
}
2 changes: 1 addition & 1 deletion twelf/tests/default.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![cfg(features = "default_trait")]
#![cfg(feature = "default_trait")]
use config_derive::config;
use twelf::Layer;

Expand Down
12 changes: 7 additions & 5 deletions twelf/tests/dhall.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![cfg(feature = "dhall")]

use std::collections::HashMap;

use config_derive::config;
Expand All @@ -12,7 +14,7 @@ const DHALL_TEST_FILE: &str = "./tests/fixtures/test.dhall";
#[test]
fn dhall_simple_types() {
#[config]
#[derive(Debug)]
#[derive(Debug, Default)]
struct TestCfg {
test: String,
another: usize,
Expand All @@ -32,7 +34,7 @@ fn dhall_simple_types() {
#[test]
fn dhall_simple_with_prefix() {
#[config]
#[derive(Debug)]
#[derive(Debug, Default)]
struct Conf {
elements_def: HashMap<String, String>,
#[serde(default = "default_array")]
Expand All @@ -57,7 +59,7 @@ fn dhall_simple_with_prefix() {
#[test]
fn dhall_simple_with_option() {
#[config]
#[derive(Debug)]
#[derive(Debug, Default)]
struct Conf {
elements_def: Option<HashMap<String, String>>,
array_def: Option<Vec<String>>,
Expand All @@ -80,7 +82,7 @@ fn dhall_simple_with_option() {
#[test]
fn dhall_with_array_and_hashmap_string() {
#[config]
#[derive(Debug)]
#[derive(Debug, Default)]
struct Conf {
elements: HashMap<String, String>,
#[serde(default = "default_array")]
Expand Down Expand Up @@ -113,7 +115,7 @@ fn dhall_with_array_and_hashmap_string() {
#[test]
fn dhall_with_array_and_hashmap_with_default() {
#[config]
#[derive(Debug)]
#[derive(Debug, Default)]
struct Conf {
elements_def: HashMap<String, String>,
#[serde(default = "default_array")]
Expand Down
Loading