@@ -290,11 +290,17 @@ fn generate_accessor_methods(
290290 ) ) ;
291291 } ;
292292
293- if attrs. nested || attrs. flatten || is_nested_struct ( & field. ty ) {
293+ let is_structural = match attrs. nesting {
294+ Nesting :: Flatten | Nesting :: Nested => true ,
295+ Nesting :: Object => false ,
296+ Nesting :: Auto => is_nested_struct ( & field. ty ) ,
297+ } ;
298+
299+ if is_structural {
294300 return Ok ( None ) ;
295301 }
296302
297- let category = resolve_field_category ( attrs, container_attrs) ? ;
303+ let category = resolve_field_category ( attrs, container_attrs) ;
298304 let key_name = attrs
299305 . rename
300306 . clone ( )
@@ -324,27 +330,15 @@ fn generate_accessor_methods(
324330 format ! ( "{category}.{key_name}" )
325331 } ;
326332
327- let snapshot_method = if cfg_attrs. is_empty ( ) {
328- quote ! {
329- pub fn #getter_name( & self ) -> & #field_type {
330- & self . #field_name
331- }
332-
333- pub fn #setter_name( & mut self , value: #field_type) {
334- self . #field_name = value;
335- }
333+ let snapshot_method = quote ! {
334+ #( #cfg_attrs) *
335+ pub fn #getter_name( & self ) -> & #field_type {
336+ & self . #field_name
336337 }
337- } else {
338- quote ! {
339- #( #cfg_attrs) *
340- pub fn #getter_name( & self ) -> & #field_type {
341- & self . #field_name
342- }
343338
344- #( #cfg_attrs) *
345- pub fn #setter_name( & mut self , value: #field_type) {
346- self . #field_name = value;
347- }
339+ #( #cfg_attrs) *
340+ pub fn #setter_name( & mut self , value: #field_type) {
341+ self . #field_name = value;
348342 }
349343 } ;
350344
@@ -355,41 +349,22 @@ fn generate_accessor_methods(
355349 return Ok ( Some ( ( snapshot_method, quote ! { } , quote ! { } ) ) ) ;
356350 }
357351
358- let manager_trait_method = if cfg_attrs. is_empty ( ) {
359- quote ! {
360- fn #getter_name( & self ) -> rcman:: Result <#field_type>;
361- fn #setter_name( & self , value: #field_type) -> rcman:: Result <( ) >;
362- }
363- } else {
364- quote ! {
365- #( #cfg_attrs) *
366- fn #getter_name( & self ) -> rcman:: Result <#field_type>;
367- #( #cfg_attrs) *
368- fn #setter_name( & self , value: #field_type) -> rcman:: Result <( ) >;
369- }
352+ let manager_trait_method = quote ! {
353+ #( #cfg_attrs) *
354+ fn #getter_name( & self ) -> rcman:: Result <#field_type>;
355+ #( #cfg_attrs) *
356+ fn #setter_name( & self , value: #field_type) -> rcman:: Result <( ) >;
370357 } ;
371358
372- let manager_impl_method = if cfg_attrs. is_empty ( ) {
373- quote ! {
374- fn #getter_name( & self ) -> rcman:: Result <#field_type> {
375- self . get:: <#field_type>( #full_key)
376- }
377-
378- fn #setter_name( & self , value: #field_type) -> rcman:: Result <( ) > {
379- self . save_setting( #category, #key_name, & rcman:: serde_json:: json!( value) )
380- }
359+ let manager_impl_method = quote ! {
360+ #( #cfg_attrs) *
361+ fn #getter_name( & self ) -> rcman:: Result <#field_type> {
362+ self . get:: <#field_type>( #full_key)
381363 }
382- } else {
383- quote ! {
384- #( #cfg_attrs) *
385- fn #getter_name( & self ) -> rcman:: Result <#field_type> {
386- self . get:: <#field_type>( #full_key)
387- }
388364
389- #( #cfg_attrs) *
390- fn #setter_name( & self , value: #field_type) -> rcman:: Result <( ) > {
391- self . save_setting( #category, #key_name, & rcman:: serde_json:: json!( value) )
392- }
365+ #( #cfg_attrs) *
366+ fn #setter_name( & self , value: #field_type) -> rcman:: Result <( ) > {
367+ self . save_setting( #category, #key_name, & rcman:: serde_json:: json!( value) )
393368 }
394369 } ;
395370
@@ -458,8 +433,14 @@ fn process_field(
458433
459434 // Check if this is a nested struct.
460435 // We auto-detect simple structs, but allow explicit `nested`, `flatten` or explicit `object` override.
461- if !attrs. object && ( attrs. flatten || attrs. nested || is_nested_struct ( field_type) ) {
462- let prefix = if attrs. flatten {
436+ let is_structural = match attrs. nesting {
437+ Nesting :: Flatten | Nesting :: Nested => true ,
438+ Nesting :: Object => false ,
439+ Nesting :: Auto => is_nested_struct ( field_type) ,
440+ } ;
441+
442+ if is_structural {
443+ let prefix = if attrs. nesting == Nesting :: Flatten {
463444 None
464445 } else {
465446 Some ( field_name. to_string ( ) )
@@ -477,7 +458,7 @@ fn process_field(
477458
478459 validate_field_type_constraints ( field, type_info, attrs) ?;
479460
480- let category_str = resolve_field_category ( attrs, container_attrs) ? ;
461+ let category_str = resolve_field_category ( attrs, container_attrs) ;
481462 let final_field_name = attrs
482463 . rename
483464 . clone ( )
@@ -634,16 +615,13 @@ fn validate_field_type_constraints(
634615 Ok ( ( ) )
635616}
636617
637- fn resolve_field_category (
638- attrs : & FieldAttrs ,
639- container_attrs : & ContainerAttrs ,
640- ) -> Result < String , syn:: Error > {
641- Ok ( attrs
618+ fn resolve_field_category ( attrs : & FieldAttrs , container_attrs : & ContainerAttrs ) -> String {
619+ attrs
642620 . category
643621 . as_ref ( )
644622 . or ( container_attrs. category . as_ref ( ) )
645623 . cloned ( )
646- . unwrap_or_default ( ) )
624+ . unwrap_or_default ( )
647625}
648626
649627fn generate_field_constructor (
@@ -728,19 +706,17 @@ fn parse_field_attrs(attrs: &[Attribute]) -> Result<FieldAttrs, syn::Error> {
728706 match meta {
729707 Meta :: Path ( path) => {
730708 if path. is_ident ( "flatten" ) {
731- result. flatten = true ;
709+ result. nesting = Nesting :: Flatten ;
732710 } else if path. is_ident ( "skip" ) {
733711 result. skip = true ;
734712 }
735713 }
736714 Meta :: NameValue ( nv) => {
737715 if nv. path . is_ident ( "rename" ) && result. rename . is_none ( ) {
738- if let Ok ( s) = parse_lit_str ( & nv. value , "rename" ) {
739- result. rename = Some ( s) ;
740- }
716+ result. rename = parse_lit_str ( & nv. value , "rename" ) . ok ( ) ;
741717 }
742718 }
743- _ => { }
719+ Meta :: List ( _ ) => { }
744720 }
745721 }
746722 }
@@ -758,11 +734,11 @@ fn parse_single_field_attr(meta: Meta, result: &mut FieldAttrs) -> Result<(), sy
758734 } else if path. is_ident ( "skip" ) {
759735 result. skip = true ;
760736 } else if path. is_ident ( "nested" ) {
761- result. nested = true ;
737+ result. nesting = Nesting :: Nested ;
762738 } else if path. is_ident ( "object" ) {
763- result. object = true ;
739+ result. nesting = Nesting :: Object ;
764740 } else if path. is_ident ( "flatten" ) {
765- result. flatten = true ;
741+ result. nesting = Nesting :: Flatten ;
766742 }
767743 }
768744 Meta :: NameValue ( nv) => {
@@ -829,6 +805,15 @@ struct ContainerAttrs {
829805 category : Option < String > ,
830806}
831807
808+ #[ derive( Default , Debug , Clone , Copy , PartialEq , Eq ) ]
809+ enum Nesting {
810+ #[ default]
811+ Auto ,
812+ Flatten ,
813+ Nested ,
814+ Object ,
815+ }
816+
832817/// Field-level attributes from #[setting(...)]
833818#[ derive( Default ) ]
834819struct FieldAttrs {
@@ -841,9 +826,7 @@ struct FieldAttrs {
841826 reserved : Vec < String > ,
842827 secret : bool ,
843828 skip : bool ,
844- flatten : bool ,
845- nested : bool , // Explicit marker for nested structs
846- object : bool , // Explicit marker to treat as a single object (disables auto-nesting)
829+ nesting : Nesting ,
847830 rename : Option < String > ,
848831 // Dynamic metadata: any key=value that isn't a known constraint
849832 metadata_str : Vec < ( String , String ) > ,
@@ -932,9 +915,8 @@ fn parse_metadata_value(
932915 Ok ( ( ) )
933916 }
934917 Lit :: Int ( i) => {
935- if let Ok ( val) = i. base10_parse :: < i64 > ( ) {
936- #[ allow( clippy:: cast_precision_loss) ]
937- result. metadata_num . push ( ( key, val as f64 ) ) ;
918+ if let Ok ( val) = i. base10_parse :: < f64 > ( ) {
919+ result. metadata_num . push ( ( key, val) ) ;
938920 }
939921 Ok ( ( ) )
940922 }
0 commit comments