1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
use inflector::Inflector; use proc_macro::TokenStream; use quote::{format_ident, quote}; use syn::{ braced, parse::{Parse, ParseStream, Result}, parse_macro_input, punctuated::Punctuated, Attribute, Ident, Token, Type, Visibility, }; struct Input { attrs: Vec<Attribute>, vis: Visibility, ident: Ident, tokens: Vec<Token>, } struct Token { attrs: Vec<Attribute>, ident: Ident, ty: Type, } impl Parse for Input { fn parse(input: ParseStream<'_>) -> Result<Self> { let attrs = input.call(Attribute::parse_outer)?; let vis = input.parse()?; input.parse::<Token![struct]>()?; let ident = input.parse()?; let content; braced!(content in input); let tokens = content.call(Punctuated::<_, Token![,]>::parse_terminated)?.into_iter().collect(); Ok(Self { attrs, vis, ident, tokens }) } } impl Parse for Token { fn parse(input: ParseStream<'_>) -> Result<Self> { let attrs = input.call(Attribute::parse_outer)?; let ident = input.parse()?; input.parse::<Token![:]>()?; let ty = input.parse()?; Ok(Self { attrs, ident, ty }) } } pub fn proc_macro(input: TokenStream) -> TokenStream { let Input { attrs, vis, ident, tokens } = parse_macro_input!(input); let wrapper = format_ident!("__{}_static_tokens", ident.to_string().to_snake_case()); let mut outer_tokens = Vec::new(); let mut def_tokens = Vec::new(); let mut ctor_tokens = Vec::new(); for Token { attrs, ident, ty } in tokens { let wrapper = format_ident!("__{}_nested_static_tokens", ident.to_string().to_snake_case()); let struct_ident = format_ident!("{}Token", ident.to_string().to_pascal_case()); let field_ident = format_ident!("{}", ident.to_string().to_snake_case()); outer_tokens.push(quote! { mod #wrapper { use super::*; #(#attrs)* pub struct #struct_ident(()); unsafe impl ::drone_core::token::Token for #struct_ident { #[inline] unsafe fn take() -> Self { #struct_ident(()) } } } #vis use #wrapper::#struct_ident; unsafe impl ::drone_core::token::StaticToken for #struct_ident { type Target = #ty; #[inline] fn get(&mut self) -> &mut Self::Target { unsafe { &mut #ident } } #[inline] fn into_static(self) -> &'static mut Self::Target { unsafe { &mut #ident } } } }); def_tokens.push(quote! { #[allow(missing_docs)] pub #field_ident: #struct_ident, }); ctor_tokens.push(quote! { #field_ident: ::drone_core::token::Token::take(), }); } let expanded = quote! { mod #wrapper { use super::*; #(#attrs)* pub struct #ident { #(#def_tokens)* __priv: (), } unsafe impl ::drone_core::token::Token for #ident { #[inline] unsafe fn take() -> Self { Self { #(#ctor_tokens)* __priv: (), } } } } #vis use #wrapper::#ident; #(#outer_tokens)* }; expanded.into() }