Skip to content

Commit

Permalink
feat: support Vec<T>
Browse files Browse the repository at this point in the history
  • Loading branch information
sasakiyori committed Nov 6, 2023
1 parent f587ebc commit c89ee52
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 21 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "merge-cfg"
version = "0.1.0"
version = "0.1.1"
edition = "2021"
authors = ["sasakiyori <[email protected]>"]
license = "MIT"
Expand Down
15 changes: 10 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@ use merge_cfg::MergeCfg;
struct Config {
id: u64,
name: String,
scores: Vec<i32>,
}

fn main() {
let mut cfg = Config {
id: 1,
name: "abc".to_string(),
scores: vec![-1],
};
cfg.merge_cfg();
println!("{:?}", cfg);
Expand All @@ -29,16 +31,19 @@ Command line arguments format: `{field}={value}`, field name should be the same

```shell
$ cargo run
Config { id: 1, name: "abc" }
Config { id: 1, name: "abc", scores: [-1] }

$ cargo run id=2
Config { id: 2, name: "abc" }
Config { id: 2, name: "abc", scores: [-1] }

$ cargo run name=xyz
Config { id: 1, name: "xyz" }
Config { id: 1, name: "xyz", scores: [-1] }

$ cargo run id=2 name=xyz
Config { id: 2, name: "xyz" }
$ cargo run scores=100 scores=-1000
Config { id: 1, name: "abc", scores: [100, -1000] }

$ cargo run id=2 name=xyz scores=100
Config { id: 2, name: "xyz", scores: [100] }
```
## Roadmap
Expand Down
61 changes: 46 additions & 15 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
extern crate proc_macro;

use proc_macro::TokenStream;
use proc_macro::{Span, TokenStream};
use quote::quote;
use syn::{parse_macro_input, Data, DeriveInput, Fields};
use syn::{
parse_macro_input, Data, DeriveInput, Fields, GenericArgument, Ident, PathArguments, Type,
};

#[proc_macro_derive(MergeCfg)]
pub fn merge_cfg_derive(input: TokenStream) -> TokenStream {
Expand All @@ -18,10 +20,36 @@ pub fn merge_cfg_derive(input: TokenStream) -> TokenStream {
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()
match &field_type {
// currently just support Vec<T>
Type::Path(p) if p.path.segments.first().unwrap().ident.eq("Vec") => {
if let PathArguments::AngleBracketed(generic_args) =
&p.path.segments.first().unwrap().arguments
{
let args = &generic_args.args;
if args.len().eq(&1) {
if let GenericArgument::Type(Type::Path(ap)) = &args[0] {
// get type string
let ty = ap.path.get_ident().unwrap().to_string();
// get type identity
let ty_ident = Ident::new(&ty, Span::call_site().into());
merge_handle = quote! {
#merge_handle
#field_name => {
self.#field_ident = v.iter().map(|s| s.parse::<#ty_ident>().unwrap()).collect()
}
};
}
}
}
}
_ => {
merge_handle = quote! {
#merge_handle
#field_name => {
self.#field_ident = v.first().unwrap().parse::<#field_type>().unwrap()
}
};
}
};
}
Expand All @@ -36,17 +64,20 @@ pub fn merge_cfg_derive(input: TokenStream) -> TokenStream {
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
_ => {}
}
}
if args.len() > 1 {
let mut map = ::std::collections::HashMap::<String, Vec<String>>::new();
for arg in args.iter().skip(1) {
if let Some((k, v)) = arg.split_once('=') {
map.entry(k.to_string()).or_default().push(v.to_string());
}
}
map.iter().for_each(|(k, v)| {
match k.as_str() {
#merge_handle
_ => {},
}
});
}
}
}
}
Expand Down

0 comments on commit c89ee52

Please sign in to comment.