1mod attributes;
2mod context;
3mod fields;
4mod fields_gen;
5mod gen;
6mod variants;
7mod variants_gen;
8
9use attributes::{BuildableAttributes, TypeAttributes};
10use context::CodegenContext;
11use fields::FieldsSet;
12use fields_gen::gen_parse_struct;
13use proc_macro::TokenStream;
14use proc_macro2::TokenStream as TokenStream2;
15use quote::quote;
16use syn::spanned::Spanned;
17use variants::VariantsSet;
18use variants_gen::gen_parse_enum;
19
20type DeriveResult = Result<TokenStream2, syn::Error>;
21
22fn derive_struct<'a>(ctx: &mut CodegenContext<'a>, data: &'a syn::DataStruct) -> DeriveResult {
23 let fieldset = FieldsSet::from_fields(ctx, &data.fields)?;
24 let name = ctx.type_name;
25 let parse_tokens = gen_parse_struct(quote! { #name }, ctx, &fieldset, None);
26 Ok(parse_tokens)
27}
28
29fn derive_enum<'a>(ctx: &mut CodegenContext<'a>, data: &'a syn::DataEnum) -> DeriveResult {
30 let variantset = VariantsSet::from_variants(ctx, data.variants.iter())?;
31 let parse_tokens = gen_parse_enum(ctx, &variantset);
32 Ok(parse_tokens)
33}
34
35fn derive<'a>(ctx: &mut CodegenContext<'a>, input: &'a syn::DeriveInput) -> DeriveResult {
36 let type_attributes = TypeAttributes::from_attributes(input.attrs.iter())?;
37 ctx.context_type = type_attributes.context_type;
38
39 match &input.data {
40 syn::Data::Struct(data) => derive_struct(ctx, data),
41 syn::Data::Enum(data) => derive_enum(ctx, data),
42 syn::Data::Union(data) => Err(syn::Error::new(
43 data.union_token.span(),
44 "parsing unions is not supported",
45 )),
46 }
47}
48
49#[proc_macro_derive(Parsable, attributes(cmd))]
50pub fn derive_parseable(input: TokenStream) -> TokenStream {
51 let input = syn::parse_macro_input!(input as syn::DeriveInput);
52 let name = &input.ident;
53
54 let mut context = CodegenContext::from_derive_input(&input);
55 let result = derive(&mut context, &input);
56
57 match result {
58 Ok(parse_impl) => gen::implementation(name, &context, parse_impl).into(),
59 Err(error) => error.into_compile_error().into(),
60 }
61}