1mod deparsable;
2mod helpers;
3mod parsable;
4
5use crate::{
6 deparsable::generate::generate_expression_deparsable,
7 parsable::generate::generate_expression_parsable,
8};
9use helpers::combine_generics;
10use parsable::attributes::{LocalContext, OuterAttributes};
11use proc_macro2::TokenStream;
12use quote::quote;
13use syn::{parse_macro_input, parse_quote, DeriveInput};
14
15#[proc_macro_derive(
16 Parsable,
17 attributes(parst, matches, assert_eq, assert_ne, with_context, with_field_context)
18)]
19pub fn derive_parsable(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
20 let derive_input = parse_macro_input!(input as DeriveInput);
21 proc_macro::TokenStream::from(process_input_parsable(&derive_input))
22}
23
24fn process_input_parsable(input: &DeriveInput) -> TokenStream {
25 let ident = &input.ident;
26 let generics = &input.generics;
27
28 let outer_attributes = OuterAttributes::from_attributes(&input.attrs);
29 let local_context = LocalContext::from(outer_attributes);
30
31 let expression = generate_expression_parsable(input, &local_context);
32
33 let mut combined_generics = combine_generics(generics, &local_context.new_generics());
34 let src_lifetime = local_context.src_lifetime;
35 let src_type = local_context.src_type;
36 let ctx_pat = local_context.ctx_pat;
37 let ctx_type = local_context.ctx_type;
38
39 let predicates = &mut combined_generics.make_where_clause().predicates;
40 if local_context.src_is_generic {
41 predicates.push(parse_quote! { #src_type: ?Sized });
42 }
43
44 let (combined_impl_generics, _, combined_where) = combined_generics.split_for_impl();
45
46 quote! {
47 impl #combined_impl_generics ::parst::Parsable<#src_lifetime, #src_type, #ctx_type> for #ident #generics #combined_where {
48 fn read(__source: &#src_lifetime #src_type, #ctx_pat: #ctx_type) -> ::parst::PResult<Self, #src_type> {
49 #expression
50 }
51 }
52 }
53}
54
55#[proc_macro_derive(Deparsable)]
56pub fn derive_deparsable(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
57 let derive_input = parse_macro_input!(input as DeriveInput);
58 proc_macro::TokenStream::from(process_input_deparsable(&derive_input))
59}
60
61fn process_input_deparsable(input: &DeriveInput) -> TokenStream {
62 let ident = &input.ident;
63 let generics = &input.generics;
64
65 let expression = generate_expression_deparsable(input);
66 quote! {
67 impl ::parst::Deparsable for #ident #generics
68 {
69 fn write(&self, mut __w: impl ::std::io::Write) -> ::std::io::Result<()> {
70 #![allow(non_snake_case)]
71 #expression
72 }
73 }
74 }
75}