manifold3d_macros/
lib.rs

1use proc_macro::TokenStream;
2use quote::quote;
3use std::sync::atomic::AtomicU64;
4use std::sync::Mutex;
5use syn::ItemStruct;
6
7static UNIQUE_COUNTER: Mutex<AtomicU64> = Mutex::new(AtomicU64::new(0));
8
9#[proc_macro_attribute]
10pub fn manifold_warp(_attr: TokenStream, input: TokenStream) -> TokenStream {
11    let structt = syn::parse_macro_input!(input as ItemStruct);
12    let struct_ident = structt.ident.clone();
13    let struct_name = struct_ident.to_string();
14
15    let unique_id = match UNIQUE_COUNTER.lock() {
16        Ok(guard) => guard.fetch_add(1, std::sync::atomic::Ordering::SeqCst),
17        Err(e) => panic!("Could not lock unique counter: {}", e),
18    };
19
20    let extern_c_fn_ident = proc_macro2::Ident::new(
21        format!(
22            "manifold3d_manifold_warp_fn_{}_{}",
23            struct_name.to_ascii_lowercase(),
24            unique_id
25        )
26        .as_str(),
27        proc_macro2::Span::call_site(),
28    );
29
30    let output = quote!(
31        #structt
32
33        const _: () = {
34            use manifold3d::manifold::WarpVertex;
35
36            #[no_mangle]
37            #[doc(hidden)]
38            pub unsafe extern "C" fn #extern_c_fn_ident(
39                x: f64,
40                y: f64,
41                z: f64,
42                ctx: *mut ::std::os::raw::c_void
43            ) -> manifold3d::sys::ManifoldVec3 {
44                let warp = &*(ctx as *mut #struct_ident);
45                let result = warp.warp_vertex(manifold3d::types::Point3::new(x, y, z));
46                result.into()
47            }
48
49            #[automatically_derived]
50            impl manifold3d::manifold::ExternCWarpFn for #struct_ident {
51                fn extern_c_warp_fn(&self) -> unsafe extern "C" fn(
52                    f64,
53                    f64,
54                    f64,
55                    *mut std::os::raw::c_void
56                ) -> manifold3d::sys::ManifoldVec3 {
57                    #extern_c_fn_ident
58                }
59            }
60        };
61
62        #[automatically_derived]
63        impl manifold3d::manifold::Warp for #struct_ident {}
64    );
65    output.into()
66}
67
68#[proc_macro_attribute]
69pub fn manifold_manage_vertex_properties(_attr: TokenStream, input: TokenStream) -> TokenStream {
70    let structt = syn::parse_macro_input!(input as ItemStruct);
71    let struct_ident = structt.ident.clone();
72    let struct_name = struct_ident.to_string();
73
74    let unique_id = match UNIQUE_COUNTER.lock() {
75        Ok(guard) => guard.fetch_add(1, std::sync::atomic::Ordering::SeqCst),
76        Err(e) => panic!("Could not lock unique counter: {}", e),
77    };
78
79    let extern_c_fn_ident = proc_macro2::Ident::new(
80        format!(
81            "manifold3d_manifold_replace_vertex_properties_fn_{}_{}",
82            struct_name.to_ascii_lowercase(),
83            unique_id
84        )
85        .as_str(),
86        proc_macro2::Span::call_site(),
87    );
88
89    let output = quote!(
90        #structt
91
92        const _: () = {
93            use manifold3d::manifold::ReplaceVertexProperties;
94            #[no_mangle]
95            #[doc(hidden)]
96            pub unsafe extern "C" fn #extern_c_fn_ident(
97                new_prop: *mut f64,
98                position: manifold3d_sys::ManifoldVec3,
99                old_prop: *const f64,
100                ctx: *mut ::std::os::raw::c_void,
101            ) {
102                let c_ctx = &*(ctx as *const manifold3d::manifold::ReplaceVertexPropertiesCCtx);
103                let manage_vertex_properties =
104                    &*(c_ctx.manage_vertex_properties_ptr as *const #struct_ident);
105
106                // We cannot access the concrete type of CTX here, so we let the compiler infer the correct type
107                unsafe fn convert_ctx<'a, T>(ctx: *mut ::std::os::raw::c_void) -> &'a mut T {
108                    &mut *(ctx as *mut T)
109                }
110                let manage_vertex_properties_ctx = convert_ctx(c_ctx.ctx_ptr);
111
112                let old_properties = if old_prop.is_null() {
113                    &[0.0; 0]
114                } else {
115                    std::slice::from_raw_parts(old_prop, c_ctx.old_properties_per_vertex_count)
116                };
117
118                let mut new_properties = Vec::from_raw_parts(
119                    new_prop,
120                    c_ctx.new_properties_per_vertex_count,
121                    c_ctx.new_properties_per_vertex_count,
122                );
123
124                manage_vertex_properties.replace_vertex_properties(
125                    manage_vertex_properties_ctx,
126                    position.into(),
127                    old_properties,
128                    new_properties.as_mut_slice(),
129                );
130
131                // Managed by manifold
132                ::std::mem::forget(new_properties);
133            }
134
135            #[automatically_derived]
136            impl manifold3d::manifold::ExternCReplaceVertexPropertiesFn for MyPropertyReplacer {
137                fn extern_c_replace_vertex_properties_fn(
138                    &self,
139                ) -> unsafe extern "C" fn(
140                    *mut f64,
141                    manifold3d_sys::ManifoldVec3,
142                    *const f64,
143                    *mut ::std::os::raw::c_void,
144                ) -> () {
145                    #extern_c_fn_ident
146                }
147            }
148        };
149
150        #[automatically_derived]
151        impl manifold3d::manifold::ManageVertexProperties for MyPropertyReplacer {}
152    );
153    output.into()
154}