1use proc_macro::TokenStream;
12use quote::quote;
13use syn::{parse_macro_input, DeriveInput, ItemFn, ItemStruct, ItemTrait};
14
15#[proc_macro_attribute]
29pub fn patch_trait(_attr: TokenStream, item: TokenStream) -> TokenStream {
30 let input = parse_macro_input!(item as ItemTrait);
31 let trait_name = &input.ident;
32 let vis = &input.vis;
33 let trait_items = &input.items;
34 let generics = &input.generics;
35 let where_clause = &input.generics.where_clause;
36
37 let expanded = quote! {
38 #vis trait #trait_name #generics #where_clause {
39 #(#trait_items)*
40 }
41
42 impl #trait_name {
44 pub const fn __dynpatch_trait_version() -> (u32, u32, u32) {
45 (0, 1, 0)
46 }
47
48 pub const fn __dynpatch_trait_name() -> &'static str {
49 stringify!(#trait_name)
50 }
51 }
52 };
53
54 TokenStream::from(expanded)
55}
56
57#[proc_macro_attribute]
70pub fn patchable(_attr: TokenStream, item: TokenStream) -> TokenStream {
71 let input = parse_macro_input!(item as ItemFn);
72 let fn_name = &input.sig.ident;
73 let vis = &input.vis;
74 let inputs = &input.sig.inputs;
75 let output = &input.sig.output;
76 let block = &input.block;
77 let attrs = &input.attrs;
78
79 let expanded = quote! {
82 #(#attrs)*
83 #vis fn #fn_name(#inputs) #output {
84 #block
86 }
87
88 const _: () = {
90 #[used]
91 #[cfg_attr(target_os = "linux", link_section = ".dynpatch")]
92 #[cfg_attr(target_os = "macos", link_section = "__DATA,__dynpatch")]
93 #[cfg_attr(target_os = "windows", link_section = ".dynpatch")]
94 static __DYNPATCH_METADATA: &str = concat!(
95 "patchable:",
96 stringify!(#fn_name)
97 );
98 };
99 };
100
101 TokenStream::from(expanded)
102}
103
104#[proc_macro_attribute]
121pub fn patch_impl(_attr: TokenStream, item: TokenStream) -> TokenStream {
122 let input = parse_macro_input!(item as ItemStruct);
123 let struct_name = &input.ident;
124 let vis = &input.vis;
125 let fields = &input.fields;
126
127 let expanded = quote! {
128 #vis struct #struct_name #fields
129
130 #[no_mangle]
132 pub extern "C" fn __dynpatch_metadata() -> dynpatch_interface::PatchMetadata {
133 dynpatch_interface::PatchMetadata::new(
134 stringify!(#struct_name).to_string(),
135 dynpatch_interface::Version::new(0, 1, 0),
136 dynpatch_interface::Version::new(0, 1, 0),
137 dynpatch_interface::compute_type_hash(
138 stringify!(#struct_name),
139 core::mem::size_of::<#struct_name>(),
140 core::mem::align_of::<#struct_name>(),
141 ),
142 )
143 }
144
145 #[no_mangle]
147 pub extern "C" fn __dynpatch_create() -> Box<#struct_name> {
148 Box::new(#struct_name::default())
149 }
150 };
151
152 TokenStream::from(expanded)
153}
154
155#[proc_macro_attribute]
167pub fn patch_entry(_attr: TokenStream, item: TokenStream) -> TokenStream {
168 let input = parse_macro_input!(item as ItemFn);
169 let fn_name = &input.sig.ident;
170 let vis = &input.vis;
171 let block = &input.block;
172
173 let expanded = quote! {
174 #vis fn #fn_name() -> Result<(), String> {
175 #block
176 }
177
178 #[no_mangle]
179 pub extern "C" fn __dynpatch_entry() -> i32 {
180 match #fn_name() {
181 Ok(()) => 0,
182 Err(_) => -1,
183 }
184 }
185 };
186
187 TokenStream::from(expanded)
188}
189
190#[proc_macro_derive(HotConfig)]
202pub fn derive_hot_config(input: TokenStream) -> TokenStream {
203 let input = parse_macro_input!(input as DeriveInput);
204 let name = &input.ident;
205
206 let expanded = quote! {
207 impl #name {
208 pub fn __dynpatch_type_hash() -> u64 {
209 dynpatch_interface::compute_type_hash(
210 stringify!(#name),
211 core::mem::size_of::<#name>(),
212 core::mem::align_of::<#name>(),
213 )
214 }
215 }
216 };
217
218 TokenStream::from(expanded)
219}