ion_proc/function/
mod.rs

1/*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 */
6
7use proc_macro2::TokenStream;
8use quote::quote;
9use syn::punctuated::Punctuated;
10use syn::{Abi, Block, Error, FnArg, Generics, ItemFn, Result, parse_quote, parse2};
11
12use crate::attribute::krate::crate_from_attributes;
13use crate::function::wrapper::impl_wrapper_fn;
14use crate::utils::new_token;
15
16pub(crate) mod inner;
17pub(crate) mod parameter;
18pub(crate) mod wrapper;
19
20// TODO: Partially Remove Error Handling in Infallible Functions
21pub(crate) fn impl_js_fn(mut function: ItemFn) -> Result<ItemFn> {
22	let ion = &crate_from_attributes(&mut function.attrs);
23
24	let ident = &function.sig.ident;
25	let (wrapper, _) = impl_wrapper_fn(ion, function.clone(), None, false, &ident.to_string())?;
26
27	check_abi(&mut function)?;
28	set_signature(&mut function);
29
30	function.attrs.clear();
31	function.block = impl_fn_body(ion, &wrapper)?;
32
33	Ok(function)
34}
35
36pub(crate) fn check_abi(function: &mut ItemFn) -> Result<()> {
37	match &function.sig.abi {
38		None => function.sig.abi = Some(parse_quote!(extern "C")),
39		Some(Abi { name: None, .. }) => {}
40		Some(Abi { name: Some(abi), .. }) if abi.value() == "C" => {}
41		Some(Abi { name: Some(non_c_abi), .. }) => return Err(Error::new_spanned(non_c_abi, "Expected C ABI")),
42	}
43	Ok(())
44}
45
46pub(crate) fn set_signature(function: &mut ItemFn) {
47	function.sig.unsafety = Some(new_token![unsafe]);
48	function.sig.generics = Generics::default();
49	function.sig.inputs = Punctuated::from_iter::<[FnArg; 3]>([
50		parse_quote!(cx: *mut ::mozjs::jsapi::JSContext),
51		parse_quote!(argc: ::core::primitive::u32),
52		parse_quote!(vp: *mut ::mozjs::jsval::JSVal),
53	]);
54	function.sig.output = parse_quote!(-> ::core::primitive::bool);
55}
56
57pub(crate) fn impl_fn_body(ion: &TokenStream, wrapper: &ItemFn) -> Result<Box<Block>> {
58	parse2(quote!({
59		#wrapper
60
61		let cx = &#ion::Context::new_unchecked(cx);
62		let args = &mut #ion::Arguments::new(cx, argc, vp);
63
64		let result = ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(|| wrapper(cx, args)));
65		#ion::function::__handle_native_function_result(cx, result)
66	}))
67}