default_boxed_derive/
lib.rs1extern crate proc_macro;
2
3use proc_macro2::{Span, TokenStream};
4use quote::{quote, quote_spanned, ToTokens};
5use syn::punctuated::Punctuated;
6use syn::spanned::Spanned;
7use syn::token::Comma;
8use syn::{parse_quote, Data, DeriveInput, Fields, Ident, Index, Type};
9
10#[proc_macro_derive(DefaultBoxed)]
11pub fn derive_default_boxed(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
12 derive(syn::parse_macro_input!(input)).into()
13}
14
15fn derive(mut input: DeriveInput) -> TokenStream {
16 let name = &input.ident;
17 let data = match input.data {
18 Data::Struct(data) => data,
19 _ => {
20 return quote_spanned! { input.span() =>
21 compile_error!("only structs are supported");
22 };
23 }
24 };
25
26 let fields = match data.fields {
28 Fields::Named(fields) => fields.named.into_iter(),
29 Fields::Unnamed(fields) => fields.unnamed.into_iter(),
30 Fields::Unit => Punctuated::<_, Comma>::new().into_iter(),
31 };
32 let write_default: TokenStream = fields
33 .enumerate()
34 .map(|(i, field)| {
35 let name = field.ident.map_or_else(
36 || Index::from(i).to_token_stream(),
37 |ident| ident.to_token_stream(),
38 );
39 write_to_uninit("e!((*ptr).#name), &field.ty, 0)
40 })
41 .collect();
42
43 if !input.generics.params.is_empty() {
44 let mut where_clause = input.generics.where_clause.take();
45 let predicates = &mut where_clause.get_or_insert(parse_quote!(where)).predicates;
46 for param in input.generics.type_params() {
47 let ident = ¶m.ident;
48 predicates.push(parse_quote!(#ident: ::default_boxed::DefaultBoxed));
49 }
50 input.generics.where_clause = where_clause;
51 }
52
53 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
54 quote! {
55 unsafe impl#impl_generics default_boxed::DefaultBoxed for #name#ty_generics
56 #where_clause
57 {
58 unsafe fn default_in_place(ptr: *mut Self) {
59 #write_default
60 }
61 }
62 }
63}
64
65fn write_to_uninit(var: &TokenStream, ty: &Type, array_depth: usize) -> TokenStream {
66 match ty {
67 Type::Array(arr) => {
68 let array_depth = array_depth + 1;
69 let i = format!("i{array_depth}");
70 let i = Ident::new(&i, Span::call_site());
71 let len = &arr.len;
72 let inner = write_to_uninit("e!(#var[#i]), &arr.elem, array_depth);
73 quote! {
74 for #i in 0..#len {
75 #inner
76 }
77 }
78 }
79 Type::Tuple(tuple) => tuple
80 .elems
81 .iter()
82 .enumerate()
83 .map(|(i, elem)| {
84 let idx = Index::from(i);
85 write_to_uninit("e!(#var.#idx), elem, array_depth)
86 })
87 .collect(),
88 ty => {
89 let call = quote_spanned! { ty.span() =>
90 <#ty as ::default_boxed::DefaultBoxed>::default_in_place
91 };
92 quote! { #call(::core::ptr::addr_of_mut!(#var)); }
93 }
94 }
95}