parst_derive/
lib.rs

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}