rschema_derive/
lib.rs

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, // ユニットバリアントは後で処理する。
157        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}