1#![recursion_limit = "128"]
20extern crate proc_macro;
23use proc_macro::TokenStream;
24use quote::quote;
25use syn::parse::Parser;
26use syn::{self, spanned::Spanned, AttributeArgs, ItemStruct};
27
28#[proc_macro_attribute]
30pub fn vptr(attr: TokenStream, item: TokenStream) -> TokenStream {
31 let attr = syn::parse_macro_input!(attr as AttributeArgs);
32 let item = syn::parse_macro_input!(item as ItemStruct);
33 match vptr_impl(attr, item) {
34 Ok(x) => x,
35 Err(e) => e.to_compile_error().into(),
36 }
37}
38
39fn vptr_impl(attr: AttributeArgs, item: ItemStruct) -> Result<TokenStream, syn::Error> {
40 let ItemStruct {
41 attrs,
42 vis,
43 struct_token,
44 ident,
45 generics,
46 fields,
47 semi_token,
48 } = item;
49
50 let attr = attr
51 .iter()
52 .map(|a| {
53 if let syn::NestedMeta::Meta(syn::Meta::Path(i)) = a {
54 Ok(i.clone())
55 } else if let syn::NestedMeta::Lit(syn::Lit::Str(lit_str)) = a {
56 lit_str.parse::<syn::Path>()
57 } else {
58 Err(syn::Error::new(
59 a.span(),
60 "attribute of vptr must be a trait",
61 ))
62 }
63 })
64 .collect::<Result<Vec<_>, _>>()?;
65
66 if let Some(tp) = generics.type_params().next() {
67 return Err(syn::Error::new(tp.span(), "vptr does not support generics"));
68 }
69
70 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
71
72 let (fields, attr_with_names) = if let syn::Fields::Named(mut n) = fields {
73 let attr_with_names: Vec<_> = attr
74 .iter()
75 .map(|t| {
76 let field_name = quote::format_ident!("vptr_{}", t.segments.last().unwrap().ident);
77 (t, quote! { #field_name })
78 })
79 .collect();
80 let parser = syn::Field::parse_named;
81 for (trait_, field_name) in &attr_with_names {
82 n.named
83 .push(parser.parse(
84 quote!(#field_name : vptr::VPtr<#ident #ty_generics, dyn #trait_>).into(),
85 )?);
86 }
87 (syn::Fields::Named(n), attr_with_names)
88 } else {
89 let mut n = if let syn::Fields::Unnamed(n) = fields {
90 n
91 } else {
92 syn::FieldsUnnamed {
93 paren_token: Default::default(),
94 unnamed: Default::default(),
95 }
96 };
97 let count = n.unnamed.len();
98 let parser = syn::Field::parse_unnamed;
99 for trait_ in &attr {
100 n.unnamed
101 .push(parser.parse(quote!(vptr::VPtr<#ident #ty_generics, dyn #trait_>).into())?);
102 }
103 let attr_with_names: Vec<_> = attr
104 .iter()
105 .enumerate()
106 .map(|(i, t)| {
107 let field_name = syn::Index::from(i + count);
108 (t, quote! { #field_name })
109 })
110 .collect();
111 (syn::Fields::Unnamed(n), attr_with_names)
112 };
113
114 let mut result = quote!(
115 #(#attrs)* #[allow(non_snake_case)] #vis #struct_token #ident #generics #fields #semi_token
116 );
117
118 for (trait_, field_name) in attr_with_names {
119 result = quote!(#result
120 unsafe impl #impl_generics vptr::HasVPtr<dyn #trait_> for #ident #ty_generics #where_clause {
121 fn init() -> &'static vptr::VTableData {
122 use vptr::internal::{TransmuterTO, TransmuterPtr};
123 static VTABLE : vptr::VTableData = vptr::VTableData{
124 offset: ::core::mem::offset_of!(#ident, #field_name) as isize,
125 vtable: unsafe {
126 let x: &'static #ident = TransmuterPtr::<#ident> { int: 0 }.ptr;
127 TransmuterTO::<dyn #trait_>{ ptr: x }.to.vtable
128 }
129 };
130 &VTABLE
131 }
132
133 fn get_vptr(&self) -> &vptr::VPtr<Self, dyn #trait_> { &self.#field_name }
134 fn get_vptr_mut(&mut self) -> &mut vptr::VPtr<Self, dyn #trait_> { &mut self.#field_name }
135 }
136 );
137 }
138 Ok(result.into())
140}