barse_derive_impl/
lib.rs

1//! Implementation of procedural macros for barse.
2
3#![warn(
4    clippy::all,
5    clippy::pedantic,
6    clippy::perf,
7    clippy::style,
8    clippy::disallowed_types,
9    clippy::indexing_slicing,
10    clippy::clone_on_ref_ptr,
11    clippy::create_dir,
12    clippy::default_numeric_fallback,
13    clippy::empty_drop,
14    clippy::empty_structs_with_brackets,
15    clippy::unwrap_used,
16    clippy::expect_used,
17    clippy::float_equality_without_abs,
18    clippy::float_cmp,
19    clippy::float_cmp_const,
20    clippy::format_push_string,
21    clippy::get_unwrap,
22    clippy::if_then_some_else_none,
23    clippy::impl_trait_in_params,
24    clippy::mixed_read_write_in_expression,
25    clippy::mod_module_files,
26    clippy::multiple_unsafe_ops_per_block,
27    clippy::undocumented_unsafe_blocks,
28    clippy::partial_pub_fields,
29    clippy::panic,
30    clippy::semicolon_if_nothing_returned,
31    clippy::semicolon_inside_block,
32    clippy::str_to_string,
33    clippy::todo,
34    clippy::try_err,
35    clippy::unneeded_field_pattern,
36    clippy::unseparated_literal_suffix,
37    clippy::fallible_impl_from,
38    clippy::future_not_send,
39    clippy::option_if_let_else,
40    clippy::or_fun_call,
41    clippy::path_buf_push_overwrite,
42    clippy::redundant_pub_crate,
43    clippy::redundant_allocation,
44    clippy::significant_drop_tightening,
45    clippy::useless_let_if_seq,
46    rustdoc::all,
47    missing_copy_implementations,
48    missing_debug_implementations,
49    missing_docs
50)]
51
52use std::fmt;
53
54use proc_macro2::{Ident, TokenStream};
55use quote::{format_ident, quote, quote_spanned};
56use syn::{spanned::Spanned, FnArg, ItemFn, Type, TypeReference};
57
58mod condition;
59mod from_byte_reader;
60mod size_query;
61mod vec_len_query;
62
63/// Derive a `FromByteReader` implementation.
64#[must_use]
65pub fn derive_from_byte_reader(item: TokenStream) -> TokenStream {
66    let ast = parse_as!(item as syn::DeriveInput);
67    from_byte_reader::impl_trait(&ast).unwrap_or_else(syn::Error::into_compile_error)
68}
69
70/// Create a `ByteSizeQuery` implementor from a function.
71#[must_use]
72pub fn byte_size_query(attr: TokenStream, item: TokenStream) -> TokenStream {
73    let name = parse_as!(attr as Ident);
74    let body = parse_as!(item as ItemFn);
75
76    let gen_trait = simplify_result(size_query::generate_impl(&name, &body));
77
78    quote! {
79        #body
80        #gen_trait
81    }
82}
83
84/// Create a Condition implementor from a function.
85#[must_use]
86pub fn condition(attr: TokenStream, item: TokenStream) -> TokenStream {
87    let name = parse_as!(attr as Ident);
88    let body = parse_as!(item as ItemFn);
89
90    let gen_trait = simplify_result(condition::generate_impl(&name, &body));
91
92    quote! {
93        #body
94        #gen_trait
95    }
96}
97
98/// Create a `VecLenQuery` implementor from a function.
99#[must_use]
100pub fn vec_len_query(attr: TokenStream, item: TokenStream) -> TokenStream {
101    let name = parse_as!(attr as Ident);
102    let body = parse_as!(item as ItemFn);
103
104    let gen_trait = simplify_result(vec_len_query::generate_impl(&name, &body));
105
106    quote! {
107        #body
108        #gen_trait
109    }
110}
111
112fn simplify_result<T>(res: Result<T, T>) -> T {
113    match res {
114        Ok(t) | Err(t) => t,
115    }
116}
117
118fn dyn_mangle(ident: &Ident) -> Ident {
119    format_ident!("__dyn_barse_derive_i{ident}")
120}
121
122fn dyn_mangle_display<D>(disp: D) -> Ident
123where
124    D: fmt::Display,
125{
126    format_ident!("__dyn_disp_barse_derive_i{disp}")
127}
128
129fn static_mangle(ident: &str) -> Ident {
130    format_ident!("__static_barse_derive_i{ident}")
131}
132
133fn fn_name_and_type(body: &ItemFn) -> Result<(&Ident, &Type), proc_macro2::TokenStream> {
134    let fn_name = &body.sig.ident;
135
136    if !body.sig.generics.params.is_empty() {
137        let span = body.sig.generics.span();
138        return Err(quote_spanned! {
139            span=> compile_error!("annotated function can not have generic params or lifetimes")
140        });
141    }
142
143    if body.sig.inputs.len() != 1 {
144        let span = body.sig.inputs.span();
145        return Err(quote_spanned! {
146            span=> compile_error!("annotated function should have one and only have one parameter")
147        });
148    }
149
150    let Some(FnArg::Typed(flag_param)) = &body.sig.inputs.first() else {
151        let span = body.sig.inputs.span();
152        return Err(quote_spanned!{
153            span=> compile_error!("annotated function should have a non-self parameter")
154        });
155    };
156
157    let Type::Reference(TypeReference {
158        lifetime: None,
159        mutability: None,
160        elem: ty,
161        ..
162    }) = &*flag_param.ty else {
163        let span = flag_param.span();
164        return Err(quote_spanned!{
165            span=> compile_error!("annotaded function should have it's param be a immutable reference with no specified lifetime")
166        });
167    };
168
169    Ok((fn_name, ty))
170}
171
172macro_rules! parse_as {
173    ($e:path as $ty:ty) => {
174        match syn::parse2::<$ty>($e) {
175            Err(err) => return err.into_compile_error(),
176            Ok(val) => val,
177        }
178    };
179}
180use parse_as;