javascriptcore_macros/
lib.rs1use proc_macro::TokenStream;
2use quote::quote;
3
4#[proc_macro_attribute]
21pub fn function_callback(_attributes: TokenStream, item: TokenStream) -> TokenStream {
22 let function = syn::parse::<syn::ItemFn>(item)
23 .expect("#[function_callback] must apply on a valid function");
24 let function_visibility = &function.vis;
25 let function_name = &function.sig.ident;
26 let function_generics = &function.sig.generics.params;
27 let function_where_clause = &function.sig.generics.where_clause;
28
29 quote! {
30 #function_visibility unsafe extern "C" fn #function_name < #function_generics > (
31 raw_ctx: javascriptcore::sys::JSContextRef,
32 function: javascriptcore::sys::JSObjectRef,
33 this_object: javascriptcore::sys::JSObjectRef,
34 argument_count: usize,
35 arguments: *const javascriptcore::sys::JSValueRef,
36 exception: *mut javascriptcore::sys::JSValueRef,
37 ) -> *const javascriptcore::sys::OpaqueJSValue
38 #function_where_clause
39 {
40 use ::core::{mem::ManuallyDrop, option::Option, ops::Not, ptr, result::Result, slice};
41 use ::std::vec::Vec;
42 use javascriptcore::{sys::JSValueRef, JSContext, JSObject, JSValue};
43
44 assert!(raw_ctx.is_null().not(), "`JSContextRef` is null");
46
47 let ctx = ManuallyDrop::new(JSContext::from_raw(raw_ctx as *mut _));
52 let function = JSObject::from_raw(raw_ctx, function);
53 let this_object = JSObject::from_raw(raw_ctx, this_object);
54
55 let function = if function.is_null() {
56 None
57 } else {
58 Some(&function)
59 };
60
61 let this_object = if this_object.is_null() {
62 None
63 } else {
64 Some(&this_object)
65 };
66
67 let arguments = if argument_count == 0 || arguments.is_null() {
68 Vec::new()
69 } else {
70 unsafe { slice::from_raw_parts(arguments, argument_count) }
71 .iter()
72 .map(|value| JSValue::from_raw(raw_ctx, *value))
73 .collect::<Vec<_>>()
74 };
75
76 let func: fn(
80 &JSContext,
81 Option<&JSObject>,
82 Option<&JSObject>,
83 &[JSValue],
84 ) -> Result<JSValue, JSException> = {
85 #function
86
87 #function_name ::< #function_generics >
88 };
89
90 let result = func(&ctx, function, this_object, arguments.as_slice());
92
93 match result {
95 Ok(value) => {
96 *exception = ptr::null_mut();
98
99 value.into()
101 }
102 Err(exc) => {
103 *exception = JSValueRef::from(exc) as *mut _;
105
106 ptr::null()
108 }
109 }
110 }
111 }
112 .into()
113}
114
115#[proc_macro_attribute]
132pub fn constructor_callback(_attributes: TokenStream, item: TokenStream) -> TokenStream {
133 let constructor = syn::parse::<syn::ItemFn>(item)
134 .expect("#[constructor_callback] must apply on a valid function");
135 let constructor_visibility = &constructor.vis;
136 let constructor_name = &constructor.sig.ident;
137 let constructor_generics = &constructor.sig.generics.params;
138 let constructor_where_clause = &constructor.sig.generics.where_clause;
139
140 quote! {
141 #constructor_visibility unsafe extern "C" fn #constructor_name < #constructor_generics >(
142 raw_ctx: javascriptcore::sys::JSContextRef,
143 constructor: javascriptcore::sys::JSObjectRef,
144 argument_count: usize,
145 arguments: *const javascriptcore::sys::JSValueRef,
146 exception: *mut javascriptcore::sys::JSValueRef,
147 ) -> *mut javascriptcore::sys::OpaqueJSValue
148 #constructor_where_clause
149 {
150 use ::core::{mem::ManuallyDrop, option::Option, ops::Not, ptr, result::Result, slice};
151 use ::std::vec::Vec;
152 use javascriptcore::{sys::JSValueRef, JSContext, JSObject, JSValue};
153
154 assert!(raw_ctx.is_null().not(), "`JSContextRef` is null");
156
157 let ctx = ManuallyDrop::new(JSContext::from_raw(raw_ctx as *mut _));
162 let constructor = JSObject::from_raw(raw_ctx, constructor);
163
164 let arguments = if argument_count == 0 || arguments.is_null() {
165 Vec::new()
166 } else {
167 unsafe { slice::from_raw_parts(arguments, argument_count) }
168 .iter()
169 .map(|value| JSValue::from_raw(raw_ctx, *value))
170 .collect::<Vec<_>>()
171 };
172
173 let ctor: fn(
177 &JSContext,
178 &JSObject,
179 &[JSValue],
180 ) -> Result<JSValue, JSException> = {
181 #constructor
182
183 #constructor_name ::< #constructor_generics >
184 };
185
186 let result = ctor(&ctx, &constructor, arguments.as_slice());
188
189 match result {
191 Ok(value) => {
192 *exception = ptr::null_mut();
194
195 value.into()
197 }
198 Err(exc) => {
199 *exception = JSValueRef::from(exc) as *mut _;
201
202 ptr::null_mut()
204 }
205 }
206 }
207 }
208 .into()
209}