diff --git a/config-parser/config-parser-macro/src/generator_functions.rs b/config-parser/config-parser-macro/src/generator_functions.rs index 89d3d46..eabe3ed 100644 --- a/config-parser/config-parser-macro/src/generator_functions.rs +++ b/config-parser/config-parser-macro/src/generator_functions.rs @@ -83,6 +83,43 @@ pub fn gen_to_string(name: &Ident, fields: &Punctuated) -> TokenSt } } +pub fn gen_default(fields: &Punctuated) -> TokenStream { + let mut defaults: TokenStream = TokenStream::new(); + 'fields: for field in fields.iter() { + let attr = &field.attrs; + let name = match &field.ident { + Some(value) => value, + // skip anonymous fields + None => continue 'fields, + }; + let ty = &field.ty; + for attribute in attr { + if let Attribute{ meta: Meta::Path( Path{segments: attr_name, ..} ), .. } = attribute { + match attr_name.first() { + Some(value) => if value.ident == "default_value" { + let default_value = get_attribute_value(attribute); + defaults.extend(quote! { + #name: #default_value, + }); + } else if value.ident == "nested_config" { + defaults.extend(quote! { + #name: #ty.default()?; + }); + }, + None => (), + } + } + } + }; + quote!{ + /// returns an instance with default values + pub fn default(&mut self) -> std::io::Result<()> { + #defaults + Ok(()) + } + } +} + pub fn gen_config_assignments(fields: &Punctuated, config_map_name: &syn::Ident) -> TokenStream { let mut assignments : TokenStream = TokenStream::new(); 'fields: for field in fields.iter() { @@ -127,3 +164,7 @@ pub fn gen_config_assignments(fields: &Punctuated, config_map_name assignments } +fn get_attribute_value(attribute: &Attribute) -> TokenStream { + //if let Attribute{ Meta::List } + TokenStream::new() +} diff --git a/config-parser/config-parser-macro/src/lib.rs b/config-parser/config-parser-macro/src/lib.rs index db2f6d5..47cdede 100644 --- a/config-parser/config-parser-macro/src/lib.rs +++ b/config-parser/config-parser-macro/src/lib.rs @@ -11,7 +11,7 @@ use generator_functions::*; /// which parses a string and fills the fills recognised values into the struct /// - implements `write_default_config() -> Result` /// which write a default configuration, in case the documentation is lacking -#[proc_macro_derive(ConfigParser, attributes(nested_config, no_config, style_config))] +#[proc_macro_derive(ConfigParser, attributes(default_value, nested_config, no_config, style_config))] pub fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let ast = parse_macro_input!(input as DeriveInput); let name = &ast.ident; @@ -21,6 +21,9 @@ pub fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { } else { panic!("the macro `ConfigParser` applies only to structs!"); }; + if name.to_string() == "GeneralSettings" { + println!("ast = {:#?}", ast); + } let assignments: TokenStream = gen_config_assignments(fields, &config_name); let func_parse_string: TokenStream = gen_parse_from_string(&config_name, &assignments); let func_parse_map: TokenStream = gen_parse_from_map(&config_name, &assignments); diff --git a/src/config.rs b/src/config.rs index 3b295f2..a89ebc6 100644 --- a/src/config.rs +++ b/src/config.rs @@ -20,8 +20,11 @@ pub struct Config { #[derive(Debug, Clone, Default, ConfigParser)] pub struct GeneralSettings { + #[default_value(false)] pub show_stack_on_push: bool, + #[no_config] pub show_stack_on_pop: bool, + #[default_value = false] pub show_books_on_bookmark: bool, } diff --git a/test.rs b/test.rs new file mode 100644 index 0000000..f8cf61e --- /dev/null +++ b/test.rs @@ -0,0 +1,195 @@ +ast = DeriveInput { + attrs: [], + vis: Visibility::Public( + Pub, + ), + ident: Ident { + ident: "GeneralSettings", + span: #0 bytes(10021..10036), + }, + generics: Generics { + lt_token: None, + params: [], + gt_token: None, + where_clause: None, + }, + data: Data::Struct { + struct_token: Struct, + fields: Fields::Named { + brace_token: Brace, + named: [ + Field { + attrs: [ + Attribute { + pound_token: Pound, + style: AttrStyle::Outer, + bracket_token: Bracket, + meta: Meta::List { + path: Path { + leading_colon: None, + segments: [ + PathSegment { + ident: Ident { + ident: "default_value", + span: #0 bytes(10045..10058), + }, + arguments: PathArguments::None, + }, + ], + }, + delimiter: MacroDelimiter::Paren( + Paren, + ), + tokens: TokenStream [ + Ident { + ident: "false", + span: #0 bytes(10059..10064), + }, + ], + }, + }, + ], + vis: Visibility::Public( + Pub, + ), + mutability: FieldMutability::None, + ident: Some( + Ident { + ident: "show_stack_on_push", + span: #0 bytes(10075..10093), + }, + ), + colon_token: Some( + Colon, + ), + ty: Type::Path { + qself: None, + path: Path { + leading_colon: None, + segments: [ + PathSegment { + ident: Ident { + ident: "bool", + span: #0 bytes(10095..10099), + }, + arguments: PathArguments::None, + }, + ], + }, + }, + }, + Comma, + Field { + attrs: [ + Attribute { + pound_token: Pound, + style: AttrStyle::Outer, + bracket_token: Bracket, + meta: Meta::Path { + leading_colon: None, + segments: [ + PathSegment { + ident: Ident { + ident: "no_config", + span: #0 bytes(10107..10116), + }, + arguments: PathArguments::None, + }, + ], + }, + }, + ], + vis: Visibility::Public( + Pub, + ), + mutability: FieldMutability::None, + ident: Some( + Ident { + ident: "show_stack_on_pop", + span: #0 bytes(10126..10143), + }, + ), + colon_token: Some( + Colon, + ), + ty: Type::Path { + qself: None, + path: Path { + leading_colon: None, + segments: [ + PathSegment { + ident: Ident { + ident: "bool", + span: #0 bytes(10145..10149), + }, + arguments: PathArguments::None, + }, + ], + }, + }, + }, + Comma, + Field { + attrs: [ + Attribute { + pound_token: Pound, + style: AttrStyle::Outer, + bracket_token: Bracket, + meta: Meta::NameValue { + path: Path { + leading_colon: None, + segments: [ + PathSegment { + ident: Ident { + ident: "default_value", + span: #0 bytes(10157..10170), + }, + arguments: PathArguments::None, + }, + ], + }, + eq_token: Eq, + value: Expr::Lit { + attrs: [], + lit: Lit::Bool { + value: false, + }, + }, + }, + }, + ], + vis: Visibility::Public( + Pub, + ), + mutability: FieldMutability::None, + ident: Some( + Ident { + ident: "show_books_on_bookmark", + span: #0 bytes(10188..10210), + }, + ), + colon_token: Some( + Colon, + ), + ty: Type::Path { + qself: None, + path: Path { + leading_colon: None, + segments: [ + PathSegment { + ident: Ident { + ident: "bool", + span: #0 bytes(10212..10216), + }, + arguments: PathArguments::None, + }, + ], + }, + }, + }, + Comma, + ], + }, + semi_token: None, + }, +}