1#![feature(proc_macro_diagnostic)]
2#![feature(const_trait_impl)]
3#![feature(decl_macro)]
4
5use proc_macro::{TokenStream};
6use quote::{format_ident, ToTokens};
7use syn::{GenericParam, ItemStruct, GenericArgument, Member, Index, ItemImpl};
8use quote::{quote};
9use syn::punctuated::Punctuated;
10use syn::token::{Comma};
11
12#[proc_macro_attribute]
83pub fn dst(_attr:TokenStream, input:TokenStream) -> TokenStream{
84 let item_struct:ItemStruct = syn::parse(input.clone()).unwrap();
85 let struct_name = item_struct.ident.clone();
86 let mut struct_generics_param = item_struct.generics.params.clone();
87 let struct_where_clause = item_struct.generics.where_clause.clone();
88 let dst_type = item_struct.fields.iter().last().unwrap().ty.clone();
89 let field_num = item_struct.fields.iter().len();
90 let dst_field:Member = item_struct.fields.iter().last().unwrap().ident
91 .clone().map_or(Member::Unnamed(Index::from(field_num)),|i|{
92 Member::Named(i)
93 });
94
95 if !struct_generics_param.trailing_punct()&&!struct_generics_param.is_empty(){
96 struct_generics_param.push_punct(Comma::default());
97 }
98
99 let struct_generics_arg = struct_generics_param
100 .iter()
101 .fold(Punctuated::<GenericArgument, Comma>::new(),|mut last,i|{
102 let push = match i.clone(){
103 GenericParam::Type(t)=>{
104 let t = t.ident;
105 GenericArgument::Type(syn::parse(quote!(#t).into()).unwrap())
106 },
107 GenericParam::Const(t)=>{
108 let t = t.ident;
109 GenericArgument::Const(syn::parse(quote!(#t).into()).unwrap())
110 },
111 GenericParam::Lifetime(t)=>GenericArgument::Lifetime(t.lifetime),
112 };
113 last.push(push);
114 last.push_punct(Comma::default());
115 last
116 });
117
118 let mut new_struct = quote!(#[repr(C)]);
119 new_struct.extend(item_struct.into_token_stream());
120 let new_struct:ItemStruct = syn::parse(new_struct.into()).unwrap();
121
122 let mut fst_struct = new_struct.clone();
123 let fst_ident = format_ident!("{}Fst",struct_name);
124 fst_struct.ident = fst_ident.clone();
125 fst_struct.fields.iter_mut()
126 .last().unwrap().ty = syn::parse(quote!(core::marker::PhantomData< #dst_type >).into()).unwrap();
127
128 let mut init_struct = new_struct.clone();
129 let init_ident = format_ident!("{}Init",struct_name.to_string());
130 init_struct.ident = init_ident.clone();
131 init_struct.generics.params
132 .push(GenericParam::Type(syn::parse(quote!(INIT:dst_init::EmplaceInitializer<Output=#dst_type>).into()).unwrap()));
133 init_struct.fields.iter_mut()
134 .last().unwrap().ty = syn::parse(quote!(INIT).into()).unwrap();
135
136 let init_ident = init_struct.ident.clone();
137 let impl_emplace:ItemImpl = syn::parse(quote!(
138 impl<#struct_generics_param INIT:dst_init::EmplaceInitializer<Output=#dst_type>> dst_init::EmplaceInitializer for #init_ident<#struct_generics_arg INIT>
139 #struct_where_clause
140 {
141 type Output = #struct_name<#struct_generics_arg>;
142 #[inline(always)]
143 fn layout(&mut self) -> core::alloc::Layout{
144 use core::alloc::Layout;
145 let layout = Layout::new::<#fst_ident<#struct_generics_arg>>();
146 layout
147 .extend(self.#dst_field.layout())
148 .unwrap()
149 .0
150 .pad_to_align()
151 }
152
153 #[inline(always)]
154 fn emplace(mut self, ptr: core::ptr::NonNull<u8>) -> core::ptr::NonNull<Self::Output>{unsafe{
155 use core::ptr;
156 use core::ptr::NonNull;
157 use core::alloc::Layout;
158 use core::mem;
159 use dst_init::EmplaceInitializer;
160
161 let fst_layout = Layout::new::<#fst_ident<#struct_generics_arg>>();
162 let dst_layout = self.#dst_field.layout();
163 let dst = ptr
164 .as_ptr()
165 .add(mem::size_of::<#fst_ident<#struct_generics_arg>>())
166 .add(fst_layout.padding_needed_for(dst_layout.align()));
167 let fst = ptr::read(&self as *const Self as *const _);
168 let dst_init = ptr::read(&self.#dst_field as *const INIT);
169 mem::forget(self);
170 ptr.as_ptr().cast::<#fst_ident<#struct_generics_arg>>().write(fst);
171 let (_, meta) = dst_init
172 .emplace(NonNull::new(dst.cast()).unwrap())
173 .to_raw_parts();
174 mem::transmute(NonNull::<#dst_type>::from_raw_parts(ptr, meta))
175 }}
176 }
177 ).into()).unwrap();
178
179 let impl_init:ItemImpl = syn::parse(quote!(
180 impl<#struct_generics_param DstInit:dst_init::EmplaceInitializer<Output=#dst_type>> dst_init::Initializer<DstInit> for #struct_name<#struct_generics_arg>
181 #struct_where_clause
182 {
183 type Init = #init_ident<#struct_generics_arg DstInit>;
184 }
185 ).into()).unwrap();
186
187 let mut output = new_struct.into_token_stream();
188 output.extend(fst_struct.into_token_stream());
189 output.extend(init_struct.into_token_stream());
190 output.extend(impl_emplace.into_token_stream());
191 output.extend(impl_init.into_token_stream());
192
193 output.into()
194}