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
use proc_macro2::TokenStream;
use quote::{quote, quote_spanned};
use syn::spanned::Spanned;
use synstructure::{AddBounds, Structure};
macro_rules! derive_traits {
($($proc_name:ident: $trait_name:ident,)*) => {$(
fn $proc_name(s: Structure) -> TokenStream {
derive_trait(s, quote!(passive::$trait_name))
}
synstructure::decl_derive!([$trait_name] => $proc_name);
)*}
}
derive_traits! {
always_aligned: AlwaysAligned,
always_valid: AlwaysValid,
immutable: Immutable,
}
fn derive_trait(mut s: Structure, trait_path: TokenStream) -> TokenStream {
let impl_ = s
.add_bounds(AddBounds::Generics)
.unsafe_bound_impl(&trait_path, quote!());
let soundness_check = soundness_check(&s, trait_path);
quote! { #impl_ #soundness_check }
}
fn soundness_check(s: &Structure, trait_path: TokenStream) -> TokenStream {
let (impl_generics, _, where_clause) = s.ast().generics.split_for_impl();
let where_clause = where_clause.map_or_else(|| quote!(where), |clause| quote!(#clause));
let extra_predicate = s
.ast()
.generics
.type_params()
.map(|param| quote!(#param: #trait_path));
let check = s.variants().iter().flat_map(|v| v.bindings()).map(|b| {
let ty = &b.ast().ty;
let span = ty.span();
quote_spanned! { span => is::<#ty>() }
});
quote! {
const _: () = {
fn is<T: #trait_path>() {}
fn checks #impl_generics () #where_clause #(#extra_predicate),* {
#(#check;)*
}
};
}
}