1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
extern crate proc_macro;
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, spanned::Spanned, Data, DeriveInput, WherePredicate};
#[proc_macro_derive(Stowable)]
pub fn derive_stowable(item: TokenStream) -> TokenStream {
let mut input = parse_macro_input!(item as DeriveInput);
let ident = &input.ident;
let stowable = quote! { ::stowaway::Stowable };
let field_type =
match input.data {
Data::Struct(ref struct_data) => {
match struct_data.fields {
syn::Fields::Named(ref fields) => match fields.named.first() {
None => None,
Some(..) if fields.named.len() > 1 => return syn::Error::new(
fields.span(),
"derive(Stowable) can only be used on empty or single-field structs",
)
.to_compile_error()
.into(),
Some(field) => Some(&field.ty),
},
syn::Fields::Unnamed(ref fields) => match fields.unnamed.first() {
None => None,
Some(..) if fields.unnamed.len() > 1 => return syn::Error::new(
fields.span(),
"derive(Stowable) can only be used on empty or single-field structs",
)
.to_compile_error()
.into(),
Some(field) => Some(&field.ty),
},
syn::Fields::Unit => None,
}
}
Data::Enum(enum_data) => {
return syn::Error::new(
enum_data.enum_token.span(),
"derive(Stowable) is not currently supported for enums",
)
.to_compile_error()
.into()
}
Data::Union(union_data) => {
return syn::Error::new(
union_data.union_token.span(),
"derive(Stowable) is not currently supported for unions",
)
.to_compile_error()
.into();
}
};
if let Some(field_type) = field_type {
let where_clause = input.generics.make_where_clause();
let binding = quote! { #field_type: #stowable };
let binding = TokenStream::from(binding);
let binding = parse_macro_input!(binding as WherePredicate);
where_clause.predicates.push(binding);
}
let (impl_clause, ty_clause, where_clause) = input.generics.split_for_impl();
let definition = quote! {
unsafe impl #impl_clause #stowable for #ident #ty_clause #where_clause {}
};
definition.into()
}