-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
cbb10a0
commit f587ebc
Showing
3 changed files
with
116 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,7 +2,16 @@ | |
name = "merge-cfg" | ||
version = "0.1.0" | ||
edition = "2021" | ||
authors = ["sasakiyori <[email protected]>"] | ||
license = "MIT" | ||
description = "Merge or cover config based on priorities." | ||
keywords = ["config"] | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[lib] | ||
proc-macro = true | ||
|
||
[dependencies] | ||
syn = "2.0" | ||
quote = "1.0" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,59 @@ | ||
# merge-cfg | ||
|
||
Merge or cover config based on priorities. | ||
|
||
## Usage | ||
|
||
You can get your configuration from config file in any way at first. Then derive `MergeCfg` to merge your configuration from command line arguments. | ||
|
||
```rust | ||
use merge_cfg::MergeCfg; | ||
|
||
#[derive(Debug, MergeCfg)] | ||
struct Config { | ||
id: u64, | ||
name: String, | ||
} | ||
|
||
fn main() { | ||
let mut cfg = Config { | ||
id: 1, | ||
name: "abc".to_string(), | ||
}; | ||
cfg.merge_cfg(); | ||
println!("{:?}", cfg); | ||
} | ||
``` | ||
|
||
Command line arguments format: `{field}={value}`, field name should be the same with what you defined in your structure: | ||
|
||
```shell | ||
$ cargo run | ||
Config { id: 1, name: "abc" } | ||
|
||
$ cargo run id=2 | ||
Config { id: 2, name: "abc" } | ||
|
||
$ cargo run name=xyz | ||
Config { id: 1, name: "xyz" } | ||
|
||
$ cargo run id=2 name=xyz | ||
Config { id: 2, name: "xyz" } | ||
``` | ||
## Roadmap | ||
- [ ] Support environment variables | ||
- [ ] Merge priority | ||
- [ ] Merge option (choose which to merge) | ||
- [ ] More command line argument formats | ||
- [x] Simple equal format: `{field}={value}` | ||
- [ ] [getopt](https://en.wikipedia.org/wiki/Getopt) format: `-h --{field} {value}` | ||
- [ ] Various use cases | ||
- [ ] Non-panic function | ||
- [ ] Immutable function | ||
- [ ] Field Alias | ||
- [ ] Support complex field type | ||
- [ ] Document | ||
- [ ] Readme | ||
- [ ] ... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,54 @@ | ||
pub fn add(left: usize, right: usize) -> usize { | ||
left + right | ||
} | ||
extern crate proc_macro; | ||
|
||
use proc_macro::TokenStream; | ||
use quote::quote; | ||
use syn::{parse_macro_input, Data, DeriveInput, Fields}; | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
#[proc_macro_derive(MergeCfg)] | ||
pub fn merge_cfg_derive(input: TokenStream) -> TokenStream { | ||
let ast = parse_macro_input!(input as DeriveInput); | ||
let struct_ident = &ast.ident; | ||
|
||
let mut merge_handle = quote! {}; | ||
match ast.data { | ||
Data::Struct(s) => match s.fields { | ||
Fields::Named(fields) => { | ||
for field in &fields.named { | ||
let field_ident = field.ident.as_ref().unwrap(); | ||
let field_name = field_ident.to_string(); | ||
let field_type = field.ty.clone(); | ||
// cast and set value | ||
merge_handle = quote! { | ||
#merge_handle | ||
#field_name => { | ||
self.#field_ident = kv[1].parse::<#field_type>().unwrap() | ||
} | ||
}; | ||
} | ||
} | ||
_ => panic!("MergeCfg can only be derived on structs with named fields"), | ||
}, | ||
_ => panic!("MergeCfg can only be derived on structs"), | ||
} | ||
|
||
#[test] | ||
fn it_works() { | ||
let result = add(2, 2); | ||
assert_eq!(result, 4); | ||
// final expanded code | ||
quote! { | ||
impl #struct_ident { | ||
pub fn merge_cfg(&mut self) { | ||
let args: Vec<String> = ::std::env::args().collect(); | ||
if args.len() > 1 { | ||
for arg in args.iter().skip(1) { | ||
let kv: Vec<&str> = arg.split('=').collect(); | ||
if kv.len() == 2 { | ||
match kv[0] { | ||
#merge_handle | ||
_ => {} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
.into() | ||
} |