1#![allow(warnings)]
2extern crate proc_macro;
3
4use if_chain::*;
5use proc_macro::TokenStream;
6use proc_macro2::TokenStream as TokenStream2;
7use quote::*;
8use std::cmp::Ord;
9use std::cmp::{max, min};
10use syn;
11use syn::visit::Visit;
12use syn::{parse_macro_input, parse_quote};
13use syn::{Attribute, Lit, Meta, NestedMeta, Visibility};
14
15#[proc_macro_derive(StableABI)]
16pub fn stable_abi(input: TokenStream) -> TokenStream {
17 use syn::DeriveInput;
18 let DeriveInput {
19 ident,
20 generics,
21 ..
22 } = parse_macro_input!(input as DeriveInput);
23
24 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
25 (quote! {
26 unsafe impl #impl_generics typic::stability::TransmutableFrom
27 for #ident #ty_generics #where_clause
28 {
29 type Type = Self;
30 }
31
32 unsafe impl #impl_generics typic::stability::TransmutableInto
33 for #ident #ty_generics #where_clause
34 {
35 type Type = Self;
36 }
37
38 }).into()
39}
40
41#[proc_macro_attribute]
42pub fn typicrepr(_args: TokenStream, input: TokenStream) -> TokenStream {
43 repr(_args, input)
44}
45
46fn impl_struct(definition: syn::ItemStruct) -> TokenStream {
47 let name = &definition.ident;
48 let attrs = &definition.attrs;
49 let generics = &definition.generics;
50
51 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
52
53 let all_public = definition.fields.iter().all(|field| {
54 if let Visibility::Public(_) = field.vis {
55 true
56 } else {
57 false
58 }
59 });
60
61 let mut repr = Repr::default();
62 attrs
63 .into_iter()
64 .for_each(|attr| repr.visit_attribute(attr));
65
66 if let Some(Method::Transparent) = repr.method {
67 return (quote! {
68 #definition
69
70 impl #impl_generics typic::internal::Type
71 for #name #ty_generics #where_clause
72 {
73 #[doc(hidden)]
74 type ReprAlign =
75 <#name #ty_generics as typic::internal::Type>::ReprAlign;
76
77 #[doc(hidden)]
78 type ReprPacked =
79 <#name #ty_generics as typic::internal::Type>::ReprPacked;
80
81 #[doc(hidden)]
82 type HighLevel =
83 <#name #ty_generics as typic::internal::Type>::HighLevel;
84 }
85 })
86 .into();
87 }
88
89 let repr_align = repr
90 .align
91 .map(|n| format_ident!("U{}", n))
92 .unwrap_or(format_ident!("MinAlign"));
93
94 let repr_packed = repr
95 .packed
96 .map(|n| format_ident!("U{}", n))
97 .unwrap_or(format_ident!("MaxAlign"));
98
99 if let None = repr.method {
101 return (quote! {
102 #definition
103
104 impl #impl_generics typic::internal::Type
105 for #name #ty_generics #where_clause
106 {
107 #[doc(hidden)] type ReprAlign = typic::internal::#repr_align;
108 #[doc(hidden)] type ReprPacked = typic::internal::#repr_packed;
109 #[doc(hidden)] type HighLevel = Self;
110 }
111 })
112 .into();
113 }
114
115 assert_eq!(repr.method, Some(Method::C));
117
118 let fields = definition
119 .fields
120 .iter()
121 .rfold(
122 quote! {typic::internal::PNil},
123 |rest, field| {
124 let vis = if let Visibility::Public(_) = field.vis {
125 format_ident!("Public")
126 } else {
127 format_ident!("Private")
128 };
129 let field = field.ty.clone();
130 quote! {
131 typic::internal::PCons<
132 typic::internal::Field<
133 typic::internal::field::#vis ,
134 #field>,
135 #rest>
136 }
137 },
138 );
139
140 (quote! {
141 #definition
142
143 impl #impl_generics typic::internal::Type
144 for #name #ty_generics #where_clause
145 {
146 #[doc(hidden)] type ReprAlign = typic::internal::#repr_align;
147 #[doc(hidden)] type ReprPacked = typic::internal::#repr_packed;
148 #[doc(hidden)] type HighLevel = #fields;
149 }
150 })
151 .into()
152}
153
154#[proc_macro_attribute]
155pub fn repr(args: TokenStream, input: TokenStream) -> TokenStream {
156 let args: TokenStream2 = args.into();
157 let input: TokenStream2 = input.into();
158 let definition: syn::Item = parse_quote!(#[repr(#args)] #input);
159
160 match definition {
161 syn::Item::Struct(definition) => impl_struct(definition),
162 _ => unimplemented!(),
163 }
164}
165
166#[derive(Debug, Eq, PartialEq, Clone, Copy)]
167enum Method {
168 C,
169 Packed,
170 Transparent,
171}
172
173#[derive(Debug, Eq, PartialEq, Clone, Copy)]
174enum Size {
175 I8,
176 I16,
177 I32,
178 I64,
179 I128,
180 ISize,
181 U8,
182 U16,
183 U32,
184 U64,
185 U128,
186 USize,
187}
188
189#[derive(Default, Debug, Eq, PartialEq, Clone, Copy)]
190struct Repr {
191 method: Option<Method>,
192 align: Option<u32>,
193 packed: Option<u32>,
194 size: Option<Size>,
195}
196
197impl<'ast> Visit<'ast> for Repr {
198 fn visit_attribute(&mut self, attr: &'ast Attribute) {
199 if_chain! {
200 if let Ok(Meta::List(meta_list)) = attr.parse_meta();
201 if let Some(ident) = meta_list.path.get_ident();
202 if ident.to_string() == "repr";
203 then {
204 for meta in meta_list.nested {
205 match meta {
206 NestedMeta::Meta(Meta::Path(path)) => {
207 let ident = (if let Some(ident) = path.get_ident() {
208 ident.to_string()
209 } else {
210 continue;
211 });
212
213 match &ident[..] {
214 "C" =>
215 self.method = Some(Method::C),
216 "transparent" =>
217 self.method = Some(Method::Transparent),
218
219 "packed" =>
220 self.packed = self.packed.min(Some(1)),
221
222 "i8" => self.size = Some(Size::I8),
223 "i16" => self.size = Some(Size::I16),
224 "i32" => self.size = Some(Size::I32),
225 "i64" => self.size = Some(Size::I64),
226 "i132" => self.size = Some(Size::I128),
227 "isize" => self.size = Some(Size::ISize),
228 "u8" => self.size = Some(Size::U8),
229 "u16" => self.size = Some(Size::U16),
230 "u32" => self.size = Some(Size::U32),
231 "u64" => self.size = Some(Size::U64),
232 "u132" => self.size = Some(Size::U128),
233 "usize" => self.size = Some(Size::USize),
234 _ => {},
235 }
236 },
237 NestedMeta::Meta(Meta::List(meta_list)) => {
238 if_chain! {
239 if let Some(ident) = meta_list.path.get_ident();
240 if meta_list.nested.len() == 1;
241 if let Some(n) = meta_list.nested.first();
242 if let NestedMeta::Lit(Lit::Int(n)) = n;
243 let ident = ident.to_string();
244 if let Ok(n) = n.base10_parse::<u32>();
245 then {
246 match &ident[..] {
247 "align" => {
248 self.align = self.align.max(Some(n));
249 },
250 "packed" => {
251 self.packed = self.packed.min(Some(n));
252 }
253 _ => {}
254 }
255 }
256 }
257 }
258 _ => {},
259 }
260 }
261 }
262 }
263 }
264}