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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
use proc_macro2::{Ident, TokenStream};
use quote::quote;
use syn::{DeriveInput, Result};
use syn_serde::json;
pub(crate) struct Substrate {
struct_name: Ident,
fields: syn::Fields,
}
impl Substrate {
/// Generate the token stream which provide expose for Substrate
pub fn to_token_stream(&self) -> Result<TokenStream> {
let Substrate {
struct_name,
fields,
} = self;
let mut field_idents = Vec::new();
let mut field_tys = Vec::new();
for field in fields.iter() {
field_idents.push(field.ident.clone());
field_tys.push(field.ty.clone());
}
let active_site = json::to_string(fields);
let substrate_impl_inner = {
#[cfg(feature = "unsafe")]
{
quote! {
#[automatically_derived]
impl #struct_name {
#[allow(clippy::too_many_arguments)]
/// Support `decouple` of Complex with private fields, a new function generated by Substrate macro
pub fn __substrate_new(
#( #field_idents: #field_tys, )*
) -> #struct_name {
unsafe {
use std::mem::MaybeUninit;
let mut substrate = MaybeUninit::<#struct_name>::uninit();
#( std::ptr::write(
std::ptr::addr_of_mut!((*substrate.as_mut_ptr()).#field_idents),
#field_idents,
); )*
substrate.assume_init()
}
}
#[allow(clippy::too_many_arguments)]
/// Support `bind` of Catalyst with private fields, an unpack function generated by Substrate macro
pub fn __substrate_unpack(
self
) -> (
#( #field_tys, )*
) {
let substrate = std::mem::ManuallyDrop::new(self);
unsafe {
(
#( std::ptr::read(&substrate.#field_idents), )*
)
}
}
}
}
}
#[cfg(not(feature = "unsafe"))]
{
quote! {
#[automatically_derived]
impl #struct_name {
#[allow(clippy::too_many_arguments)]
/// Support `decouple` of Complex with private fields, a new function generated by Substrate macro
pub fn __substrate_new(
#( #field_idents: #field_tys, )*
) -> #struct_name {
#struct_name {
#( #field_idents, )*
}
}
#[allow(clippy::too_many_arguments)]
/// Support `bind` of Catalyst with private fields, an unpack function generated by Substrate macro
pub fn __substrate_unpack(
self
) -> (
#( #field_tys, )*
) {
(
#( self.#field_idents, )*
)
}
}
}
}
};
Ok(quote! {
#[automatically_derived]
impl struct_patch::traits::Substrate for #struct_name {
fn expose_content() -> &'static str {
#active_site
}
fn expose() {
println!("cargo:rustc-env={}={}", stringify!(#struct_name), Self::expose_content());
}
}
#substrate_impl_inner
})
}
/// Parse the substrate struct
pub fn from_ast(DeriveInput { ident, data, .. }: syn::DeriveInput) -> Result<Substrate> {
let fields = if let syn::Data::Struct(syn::DataStruct { fields, .. }) = data {
fields
} else {
return Err(syn::Error::new(
ident.span(),
"Substrate derive only use for struct",
));
};
Ok(Substrate {
struct_name: ident,
fields,
})
}
}