use proc_macro::TokenStream;
use quote::quote;
#[proc_macro_attribute]
pub fn function_callback(_attributes: TokenStream, item: TokenStream) -> TokenStream {
let function = syn::parse::<syn::ItemFn>(item)
.expect("#[function_callback] must apply on a valid function");
let function_visibility = &function.vis;
let function_name = &function.sig.ident;
let function_generics = &function.sig.generics.params;
let function_where_clause = &function.sig.generics.where_clause;
quote! {
#function_visibility unsafe extern "C" fn #function_name < #function_generics > (
raw_ctx: javascriptcore::sys::JSContextRef,
function: javascriptcore::sys::JSObjectRef,
this_object: javascriptcore::sys::JSObjectRef,
argument_count: usize,
arguments: *const javascriptcore::sys::JSValueRef,
exception: *mut javascriptcore::sys::JSValueRef,
) -> *const javascriptcore::sys::OpaqueJSValue
#function_where_clause
{
use ::core::{mem::ManuallyDrop, option::Option, ops::Not, ptr, result::Result, slice};
use ::std::vec::Vec;
use javascriptcore::{sys::JSValueRef, JSContext, JSObject, JSValue};
assert!(raw_ctx.is_null().not(), "`JSContextRef` is null");
let ctx = ManuallyDrop::new(JSContext::from_raw(raw_ctx as *mut _));
let function = JSObject::from_raw(raw_ctx, function);
let this_object = JSObject::from_raw(raw_ctx, this_object);
let function = if function.is_null() {
None
} else {
Some(&function)
};
let this_object = if this_object.is_null() {
None
} else {
Some(&this_object)
};
let arguments = if argument_count == 0 || arguments.is_null() {
Vec::new()
} else {
unsafe { slice::from_raw_parts(arguments, argument_count) }
.iter()
.map(|value| JSValue::from_raw(raw_ctx, *value))
.collect::<Vec<_>>()
};
let func: fn(
&JSContext,
Option<&JSObject>,
Option<&JSObject>,
&[JSValue],
) -> Result<JSValue, JSException> = {
#function
#function_name ::< #function_generics >
};
let result = func(&ctx, function, this_object, arguments.as_slice());
match result {
Ok(value) => {
*exception = ptr::null_mut();
value.into()
}
Err(exc) => {
*exception = JSValueRef::from(exc) as *mut _;
ptr::null()
}
}
}
}
.into()
}
#[proc_macro_attribute]
pub fn constructor_callback(_attributes: TokenStream, item: TokenStream) -> TokenStream {
let constructor = syn::parse::<syn::ItemFn>(item)
.expect("#[constructor_callback] must apply on a valid function");
let constructor_visibility = &constructor.vis;
let constructor_name = &constructor.sig.ident;
let constructor_generics = &constructor.sig.generics.params;
let constructor_where_clause = &constructor.sig.generics.where_clause;
quote! {
#constructor_visibility unsafe extern "C" fn #constructor_name < #constructor_generics >(
raw_ctx: javascriptcore::sys::JSContextRef,
constructor: javascriptcore::sys::JSObjectRef,
argument_count: usize,
arguments: *const javascriptcore::sys::JSValueRef,
exception: *mut javascriptcore::sys::JSValueRef,
) -> *mut javascriptcore::sys::OpaqueJSValue
#constructor_where_clause
{
use ::core::{mem::ManuallyDrop, option::Option, ops::Not, ptr, result::Result, slice};
use ::std::vec::Vec;
use javascriptcore::{sys::JSValueRef, JSContext, JSObject, JSValue};
assert!(raw_ctx.is_null().not(), "`JSContextRef` is null");
let ctx = ManuallyDrop::new(JSContext::from_raw(raw_ctx as *mut _));
let constructor = JSObject::from_raw(raw_ctx, constructor);
let arguments = if argument_count == 0 || arguments.is_null() {
Vec::new()
} else {
unsafe { slice::from_raw_parts(arguments, argument_count) }
.iter()
.map(|value| JSValue::from_raw(raw_ctx, *value))
.collect::<Vec<_>>()
};
let ctor: fn(
&JSContext,
&JSObject,
&[JSValue],
) -> Result<JSValue, JSException> = {
#constructor
#constructor_name ::< #constructor_generics >
};
let result = ctor(&ctx, &constructor, arguments.as_slice());
match result {
Ok(value) => {
*exception = ptr::null_mut();
value.into()
}
Err(exc) => {
*exception = JSValueRef::from(exc) as *mut _;
ptr::null_mut()
}
}
}
}
.into()
}