proc_macro_roids/
fields_named_append.rs1use syn::{DeriveInput, Fields, FieldsNamed};
2
3use crate::DeriveInputStructExt;
4
5const ERR_MUST_BE_UNIT_OR_NAMED: &str = "Macro must be used on either a unit struct or a struct with named fields.\n\
6 This derive does not work on tuple structs.";
7
8pub trait FieldsNamedAppend {
10 fn append_named(&mut self, fields_named: FieldsNamed);
12}
13
14impl FieldsNamedAppend for DeriveInput {
15 fn append_named(&mut self, fields_named: FieldsNamed) {
16 self.fields_mut().append_named(fields_named);
17 self.data_struct_mut().semi_token = None;
18 }
19}
20
21impl FieldsNamedAppend for Fields {
22 fn append_named(&mut self, fields_named: FieldsNamed) {
23 match self {
24 Fields::Named(self_fields_named) => self_fields_named.append_named(fields_named),
25 Fields::Unit => *self = Fields::from(fields_named),
26 Fields::Unnamed(_) => panic!("{}", ERR_MUST_BE_UNIT_OR_NAMED),
27 }
28 }
29}
30
31impl FieldsNamedAppend for FieldsNamed {
32 fn append_named(&mut self, fields_named: FieldsNamed) {
33 self.named.extend(fields_named.named);
34 }
35}
36
37#[cfg(test)]
38mod tests {
39 use syn::{parse_quote, DeriveInput, Fields, FieldsNamed};
40
41 use super::FieldsNamedAppend;
42
43 #[test]
44 fn append_fields_named_to_fields_named() {
45 let mut fields: FieldsNamed = parse_quote!({ a: u32, b: i32 });
46 let fields_additional: FieldsNamed = parse_quote!({ c: i64, d: usize });
47 let fields_expected: FieldsNamed = parse_quote!({ a: u32, b: i32, c: i64, d: usize });
48
49 fields.append_named(fields_additional);
50
51 assert_eq!(fields_expected, fields);
52 }
53
54 #[test]
55 fn append_fields_named_to_fields_unit() {
56 let mut fields = Fields::Unit;
57 let fields_additional: FieldsNamed = parse_quote!({ c: i64, d: usize });
58 let fields_expected: Fields = Fields::Named(parse_quote!({ c: i64, d: usize }));
59
60 fields.append_named(fields_additional);
61
62 assert_eq!(fields_expected, fields);
63 }
64
65 #[test]
66 #[should_panic(
67 expected = "Macro must be used on either a unit struct or a struct with named fields.\n\
68 This derive does not work on tuple structs."
69 )]
70 fn append_fields_named_to_fields_unnamed_panics() {
71 let mut fields: Fields = Fields::Unnamed(parse_quote!((u32, i32)));
72 let fields_additional: FieldsNamed = parse_quote!({ c: i64, d: usize });
73
74 fields.append_named(fields_additional);
75 }
76
77 #[test]
78 fn append_fields_named_to_struct_named() {
79 let mut ast: DeriveInput = parse_quote! {
80 struct StructNamed { a: u32, b: i32 }
81 };
82
83 let fields_additional: FieldsNamed = parse_quote!({ c: i64, d: usize });
84 ast.append_named(fields_additional);
85
86 let ast_expected: DeriveInput = parse_quote! {
87 struct StructNamed { a: u32, b: i32, c: i64, d: usize }
88 };
89 assert_eq!(ast_expected, ast);
90 }
91
92 #[test]
93 fn append_fields_named_to_struct_unit() {
94 let mut ast: DeriveInput = parse_quote! {
95 struct StructUnit;
96 };
97
98 let fields_additional: FieldsNamed = parse_quote!({ c: i64, d: usize });
99 ast.append_named(fields_additional);
100
101 let ast_expected: DeriveInput = parse_quote! {
102 struct StructUnit { c: i64, d: usize }
103 };
104 assert_eq!(ast_expected, ast);
105 }
106}