rustmex_entrypoint/
lib.rs

1use proc_macro::{TokenStream};
2
3use quote::quote;
4use syn::ItemFn;
5
6#[proc_macro_attribute]
7pub fn entrypoint(_attr: TokenStream, mut item: TokenStream) -> TokenStream {
8	let input: ItemFn = syn::parse(item.clone()).unwrap();
9	let name = input.sig.ident;
10
11	let gen = quote! {
12		#[no_mangle]
13		pub extern "C" fn mexFunction(nlhs: ::std::os::raw::c_int, lhs: *mut *mut ::rustmex::mxArray,
14						nrhs: ::std::os::raw::c_int, rhs: *const *const ::rustmex::mxArray) {
15
16			// SAFETY: it is UB to unwind over FFI boundaries; we must
17			// therefore catch an unwinding panic here.
18			match std::panic::catch_unwind(|| {
19				let rhslice = unsafe { ::std::slice::from_raw_parts(rhs as *const &::rustmex::mxArray, nrhs as usize) };
20				let lhslice = unsafe { ::std::slice::from_raw_parts_mut(lhs as *mut Option<&mut ::rustmex::mxArray>, nlhs as usize) };
21
22				// SAFETY: Transmuting to an MxArray is safe, since both it and
23				// NonNull are repr(transparent).
24				//
25				// Also NOTE that transmute does nothing if Lhs is from before
26				// v0.1.3, since where then doing transmute<T, T>.
27				let lhslice_owned = unsafe { ::std::mem::transmute(lhslice) };
28				#name(lhslice_owned, rhslice)
29			}) {
30				Ok(Ok(_)) => return,
31				// SAFETY: We also can't trigger a Matlab exception
32				// (because that's apparently what it is) from within the
33				// catch_unwind closure, so we have to smuggle our error
34				// out too.
35				Ok(Err(e)) => ::rustmex::trigger_error!(e),
36				Err(_) => {
37					::rustmex::trigger_error!(::rustmex::message::AdHoc(
38						"rustmex:panic",
39						"The MEX function you called paniced. Consider restarting your interpreter with an appropriate value of RUST_BACKTRACE (setenv does not seem to work)"
40					));
41				}
42			}
43		}
44	};
45	let entrypoint: TokenStream = gen.into();
46	item.extend(entrypoint);
47	item
48}