1use proc_macro::TokenStream;
2use quote::ToTokens;
3use syn::{
4 DeriveInput,
5 parse_macro_input,
6};
7
8mod ast;
9mod attribute;
10mod case;
11mod data;
12mod tokens;
13
14use ast::{
15 Container,
16 Definitions,
17};
18use attribute::{
19 ContainerAttribute,
20 EnumAttribute,
21 StructAttribute,
22 TupleStructAttribute,
23};
24use case::Case;
25use data::{
26 Data,
27 Field,
28 Variant,
29};
30use tokens::*;
31
32type FuncBodies<'a> = (FnTypeBody<'a>, FnDefsMapBody);
33
34pub(crate) fn is_falsy(b: &Option<bool>) -> bool {
35 *b != Some(true)
36}
37
38#[proc_macro_derive(Schematic, attributes(rschema))]
39pub fn derive_schematic(input: TokenStream) -> TokenStream {
40 let input = parse_macro_input!(input as DeriveInput);
41 expand_derive_schematic(input)
42 .unwrap_or_else(|e| e.write_errors().into() )
43}
44
45fn expand_derive_schematic(
46 input: syn::DeriveInput,
47) -> darling::Result<TokenStream> {
48 let container = Container::from_ast(&input)?;
49
50 let impl_body = impl_body(&container);
51
52 let impl_block = ImplSchematic {
53 container: &container,
54 body: impl_body,
55 };
56
57 Ok(impl_block.to_token_stream().into())
58}
59
60fn impl_body<'a>(container: &'a Container) -> ImplSchematicBody<'a> {
61 let (
62 fn_type_body,
63 fn_defs_map_body,
64 ) = match container.data {
65 Data::Struct(ref fields) => {
66 func_bodies_for_struct(&container.attr, fields)
67 },
68 Data::UnitStruct => {
69 func_bodies_for_unit_struct()
70 },
71 Data::NewTypeStruct(ref field) => {
72 func_bodies_for_newtype_struct(&container.attr, field)
73 },
74 Data::TupleStruct(ref fields) => {
75 func_bodies_for_tuple_struct(&container.attr, fields)
76 },
77 Data::Enum(ref variants) => {
78 func_bodies_for_enum(container, variants)
79 },
80 };
81
82 let fn_type = FnType::new(fn_type_body);
83 let fn_defs_map = FnDefsMap::new(fn_defs_map_body);
84
85 ImplSchematicBody {
86 fn_type,
87 fn_defs_map,
88 }
89}
90
91fn func_bodies_for_struct<'a>(
92 attr: &'a (impl ContainerAttribute + StructAttribute),
93 fields: &'a [Field],
94) -> FuncBodies<'a> {
95 let mut fn_type_body = FnTypeBody::for_struct(attr, fields);
96 let fn_defs_map_body = FnDefsMapBody::with_fields(
97 attr,
98 &mut fn_type_body,
99 fields,
100 );
101
102 (
103 fn_type_body,
104 fn_defs_map_body,
105 )
106}
107
108fn func_bodies_for_unit_struct<'a>(
109) -> FuncBodies<'a> {
110 (
111 FnTypeBody::UnitStruct,
112 FnDefsMapBody::empty(),
113 )
114}
115
116fn func_bodies_for_newtype_struct<'a>(
117 attr: &'a impl ContainerAttribute,
118 field: &'a Field,
119) -> FuncBodies<'a> {
120 let mut fn_type_body = FnTypeBody::for_newtype(field);
121 let fn_defs_map_body = FnDefsMapBody::new(
122 attr,
123 &mut fn_type_body,
124 );
125
126 (
127 fn_type_body,
128 fn_defs_map_body,
129 )
130}
131
132fn func_bodies_for_tuple_struct<'a>(
133 attr: &'a (impl ContainerAttribute + TupleStructAttribute),
134 fields: &'a [Field],
135) -> FuncBodies<'a> {
136 let mut fn_type_body = FnTypeBody::for_tuple(attr, fields);
137 let fn_defs_map_body = FnDefsMapBody::with_fields(
138 attr,
139 &mut fn_type_body,
140 fields,
141 );
142
143 (
144 fn_type_body,
145 fn_defs_map_body,
146 )
147}
148
149fn func_bodies_from_vairant<'a>(
150 variant: &'a Variant
151) -> Option<FuncBodies<'a>> {
152 match variant.data {
153 Data::Struct(ref fields) => {
154 Some(func_bodies_for_struct(&variant.attr, fields))
155 },
156 Data::UnitStruct => None, Data::NewTypeStruct(ref field) => {
158 Some(func_bodies_for_newtype_struct(&variant.attr, field))
159 },
160 Data::TupleStruct(ref fields) => {
161 Some(func_bodies_for_tuple_struct(&variant.attr, fields))
162 },
163 Data::Enum(_) => {
164 unreachable!("There is no enum-type variant.");
165 },
166 }
167}
168
169fn func_bodies_for_enum<'a>(
170 container: &'a Container,
171 variants: &'a [Variant],
172) -> FuncBodies<'a> {
173 let (types, defs_maps) = variants
174 .iter()
175 .filter_map(func_bodies_from_vairant)
176 .unzip();
177
178 let mut fn_type_body = FnTypeBody::for_enum(
179 &container.attr,
180 &variants,
181 types,
182 );
183 let fn_defs_map_body = FnDefsMapBody::with_defs_maps(
184 &container.attr,
185 &mut fn_type_body,
186 defs_maps,
187 );
188
189 (
190 fn_type_body,
191 fn_defs_map_body,
192 )
193}