1extern crate proc_macro;
2
3use proc_macro2::{TokenStream, TokenTree};
4use quote::quote;
5use venial::{parse_declaration, Declaration, Error, StructFields};
6
7#[proc_macro_derive(ReprTransparent)]
8pub fn derive_repr_transparent(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
9 parse_declaration(input.into())
10 .and_then(derive)
11 .unwrap_or_else(|e| e.to_compile_error())
12 .into()
13}
14
15fn derive(decl: Declaration) -> Result<TokenStream, Error> {
16 let Some(repr_attribute) = decl.attributes().iter().find(|attr| {
17 attr.get_single_path_segment()
18 .map(|ident| ident == "repr")
19 .unwrap_or(false)
20 }) else {
21 return Err(Error::new_at_tokens(
22 decl,
23 "This derive only supports types with `#[repr(...)]`",
24 ));
25 };
26
27 if !matches!(
28 repr_attribute.get_value_tokens(),
29 [TokenTree::Ident(id)] if id == "transparent"
30 ) {
31 return Err(Error::new_at_tokens(
32 repr_attribute,
33 "`#[repr(transparent)]` is required to implement `ReprTransparent`",
34 ));
35 }
36
37 let (inner_type, inline_generic_args, name, generic_params, where_clause) = match &decl {
38 Declaration::Struct(decl) => {
39 let inner_type =
40 decl.field_types().into_iter().next().ok_or_else(|| {
41 Error::new_at_tokens(decl, "Struct must have at least one field")
42 })?;
43
44 (
45 inner_type,
46 decl.get_inline_generic_args(),
47 &decl.name,
48 &decl.generic_params,
49 &decl.where_clause,
50 )
51 }
52 Declaration::Enum(decl) => {
53 let (variant, _) = decl
54 .variants
55 .first()
56 .ok_or_else(|| Error::new_at_tokens(decl, "Enum must have one variant"))?;
57
58 let inner_type = match &variant.contents {
59 StructFields::Unit => {
60 return Err(Error::new_at_tokens(
61 variant,
62 "Enum variant must have at least one field",
63 ))
64 }
65 StructFields::Tuple(f) => f.fields.first().map(|f| &f.0.ty).ok_or_else(|| {
66 Error::new_at_tokens(variant, "Enum variant must have at least one field")
67 })?,
68 StructFields::Named(f) => f.fields.first().map(|f| &f.0.ty).ok_or_else(|| {
69 Error::new_at_tokens(variant, "Enum variant must have at least one field")
70 })?,
71 };
72
73 (
74 inner_type,
75 decl.get_inline_generic_args(),
76 &decl.name,
77 &decl.generic_params,
78 &decl.where_clause,
79 )
80 }
81 _ => return Err(Error::new("This derive only supports structs or enums")),
82 };
83
84 Ok(quote! {
86 unsafe impl #inline_generic_args bointer::ReprTransparent for #name #generic_params #where_clause {
87 type Inner = #inner_type;
88
89 #[inline(always)]
90 fn into_inner(self) -> Self::Inner {
91 unsafe { core::mem::transmute(self) }
93 }
94 }
95 })
96}