i_codegen_derive/
lib.rs

1#![allow(
2    clippy::module_name_repetitions,
3    clippy::needless_pass_by_value,
4    clippy::unseparated_literal_suffix
5)]
6
7extern crate proc_macro;
8
9use proc_macro::TokenStream;
10use syn::{parse_macro_input, DeriveInput, ItemFn};
11
12mod parse;
13
14// TODO: Support `#[codegen(crate = "wrapping_crate::derive_codegen")]`
15// https://github.com/dtolnay/linkme/blob/87e9f68b354421341eccb31c1f0dba0b63cc205d/impl/src/attr.rs#L4-L5
16/// Include this struct or enum in a retrievable metadata list in the `derive_codegen` crate.
17#[proc_macro_derive(Codegen, attributes(codegen, serde))]
18pub fn derive_codegen(input: TokenStream) -> TokenStream {
19    parse::derive(
20        parse_macro_input!(input as DeriveInput),
21        parse::LinkKind::External {
22            crate_name: "derive_codegen",
23        },
24    )
25    .unwrap_or_else(|err| err.to_compile_error())
26    .into()
27}
28
29/// Submit functions to your code generator
30///
31/// example:
32/// ```rs
33/// #[fn_codegen(tag = "my-tag")]
34/// fn my_function(item: i32) -> Result<(), String> {
35///   Err("Not implemented".to_string())
36/// }
37/// #[fn_codegen(tag = "my-tag")]
38/// fn my_function(
39///     #[codegen(myattr = "something")]
40///     item: i32
41/// ) -> Result<(), String> {
42///   Err("Not implemented".to_string())
43/// }
44/// ```
45#[proc_macro_attribute]
46pub fn fn_codegen(
47    // TODO: enable parsing this as part of the codegen attributes
48    _attribute: proc_macro::TokenStream,
49    item: proc_macro::TokenStream,
50) -> proc_macro::TokenStream {
51    let function = parse_macro_input!(item as ItemFn);
52    // Hmm: Could we have a general `#[codegen]` attr macro that auto-detects the kind of item and infers the derive stuff, etc?
53    // Would you need to discern when there are multiple `#[codegen]` things? What would happen if the codegen is on a field?
54    let generated = parse::item_fn(
55        function.clone(),
56        parse::LinkKind::External {
57            crate_name: "derive_codegen",
58        },
59    )
60    .unwrap_or_else(|err| err.to_compile_error());
61    // // check that the reference links
62    // output.extend(quote::quote! {
63    //     type _ = #ident;
64    // });
65    proc_macro2::TokenStream::from(quote::quote! {
66         #function
67
68         #generated
69    })
70    .into()
71}
72
73/// Necessary to attach attributes outside the context of
74/// a derivation.
75#[proc_macro_attribute]
76pub fn codegen(
77    _attributes: proc_macro::TokenStream,
78    item: proc_macro::TokenStream,
79) -> proc_macro::TokenStream {
80    return item;
81}
82
83#[doc(hidden)]
84#[proc_macro_derive(CodegenInternal, attributes(codegen, serde))]
85pub fn derive_codegen_internal(input: TokenStream) -> TokenStream {
86    parse::derive(
87        parse_macro_input!(input as DeriveInput),
88        parse::LinkKind::Internal,
89    )
90    .unwrap_or_else(|err| err.to_compile_error())
91    .into()
92}