Skip to content

feat: Implement JSValue::new_function #20

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Oct 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[workspace]
members = ["javascriptcore-sys"]
members = ["javascriptcore-sys", "javascriptcore-macros"]

[package]
name = "javascriptcore"
Expand All @@ -17,4 +17,5 @@ categories = ["api-bindings"]
exclude = ["javascript_core/**"]

[dependencies]
javascriptcore-macros = { path = "javascriptcore-macros", version = "0.0.1" }
javascriptcore-sys = { path = "javascriptcore-sys", version = "0.0.5" }
19 changes: 19 additions & 0 deletions javascriptcore-macros/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[package]
name = "javascriptcore-macros"
version = "0.0.1"
edition = "2021"
authors = ["Bruce Mitchener <[email protected]>", "Ivan Enderlin <[email protected]>"]
license = "MIT OR Apache-2.0"
description = "Procedural macros for the `javascriptcore` crate."
keywords = ["javascript", "jsc", "scripting"]
documentation = "https://docs.rs/javascriptcore-sys"
homepage = "https://github.com/endoli/javascriptcore.rs"
repository = "https://github.com/endoli/javascriptcore.rs"
categories = ["external-ffi-bindings"]

[lib]
proc-macro = true

[dependencies]
quote = "1.0.33"
syn = { version = "2.0.38", features = ["full"] }
71 changes: 71 additions & 0 deletions javascriptcore-macros/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
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_name = &function.sig.ident;

quote! {
unsafe extern "C" fn #function_name(
__raw_ctx: javascriptcore_sys::JSContextRef,
__raw_function: javascriptcore_sys::JSObjectRef,
__raw_this_object: javascriptcore_sys::JSObjectRef,
__raw_argument_count: usize,
__raw_arguments: *const javascriptcore_sys::JSValueRef,
__raw_exception: *mut javascriptcore_sys::JSValueRef,
) -> *const javascriptcore_sys::OpaqueJSValue {
use core::{mem, ptr, slice};
use javascriptcore::{JSContext, JSObject, JSValue};

let __ctx = JSContext::from_raw(__raw_ctx as *mut _);
let __function = JSObject::from_raw(__raw_ctx, __raw_function);
let __this_object = JSObject::from_raw(__raw_ctx, __raw_this_object);

let __function = if __raw_function.is_null() {
None
} else {
Some(&__function)
};

let __this_object = if __raw_this_object.is_null() {
None
} else {
Some(&__this_object)
};

let __arguments = if __raw_argument_count == 0 {
Vec::new()
} else {
unsafe { slice::from_raw_parts(__raw_arguments, __raw_argument_count) }
.iter()
.map(|value| JSValue::from_raw(__raw_ctx, *value))
.collect::<Vec<_>>()
};

#function

let func: fn(
&JSContext,
Option<&JSObject>,
Option<&JSObject>,
arguments: &[JSValue],
) -> Result<JSValue, JSException> = #function_name;
let result = func(&__ctx, __function, __this_object, __arguments.as_slice());

mem::forget(__ctx);

match result {
Ok(value) => value.into(),
Err(exception) => {
let raw_exception: javascriptcore_sys::JSValueRef = exception.into();
*__raw_exception = raw_exception as *mut _;

ptr::null()
}
}
}
}
.into()
}
6 changes: 3 additions & 3 deletions src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ pub fn evaluate_script<S: Into<JSString>, U: Into<JSString>>(
);

if result.is_null() {
Err(JSValue::new_inner(ctx.raw, exception).into())
Err(JSValue::from_raw(ctx.raw, exception).into())
} else {
Ok(JSValue::new_inner(ctx.raw, result))
Ok(JSValue::from_raw(ctx.raw, result))
}
}
}
Expand Down Expand Up @@ -103,7 +103,7 @@ pub fn check_script_syntax<S: Into<JSString>, U: Into<JSString>>(
if result {
Ok(())
} else {
Err(JSValue::new_inner(ctx.raw, exception).into())
Err(JSValue::from_raw(ctx.raw, exception).into())
}
}
}
Expand Down
41 changes: 23 additions & 18 deletions src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ use crate::{sys, JSClass, JSContext, JSContextGroup, JSException, JSObject, JSSt
use std::ptr;

impl JSContext {
/// Create a new [`Self`] from its raw pointer directly.
///
/// # Safety
///
/// Ensure `raw` is valid.
pub unsafe fn from_raw(raw: sys::JSGlobalContextRef) -> Self {
Self { raw }
}

/// Creates a global JavaScript execution context and populates it
/// with all the built-in JavaScript objects, such as `Object`,
/// `Function`, `String`, and `Array`.
Expand All @@ -20,7 +29,7 @@ impl JSContext {
/// However, you may not use values created in the context in other
/// contexts.
pub fn new() -> Self {
JSContext::default()
Self::default()
}

/// Creates a global JavaScript execution context and populates it
Expand All @@ -36,18 +45,18 @@ impl JSContext {
/// * `global_object_class`: The class to use when creating the global
/// object.
pub fn new_with_class(global_object_class: &JSClass) -> Self {
JSContext {
raw: unsafe { sys::JSGlobalContextCreate(global_object_class.raw) },
}
unsafe { Self::from_raw(sys::JSGlobalContextCreate(global_object_class.raw)) }
}

/// Gets the context group to which a JavaScript execution context belongs.
pub fn group(&self) -> JSContextGroup {
let g = unsafe { sys::JSContextGetGroup(self.raw) };
let group = unsafe { sys::JSContextGetGroup(self.raw) };

unsafe {
sys::JSContextGroupRetain(g);
sys::JSContextGroupRetain(group);
};
JSContextGroup { raw: g }

JSContextGroup { raw: group }
}

/// Gets a copy of the name of a context.
Expand All @@ -66,11 +75,12 @@ impl JSContext {
/// assert!(ctx.name().is_none());
/// ```
pub fn name(&self) -> Option<JSString> {
let r = unsafe { sys::JSGlobalContextCopyName(self.raw) };
if r.is_null() {
let result = unsafe { sys::JSGlobalContextCopyName(self.raw) };

if result.is_null() {
None
} else {
Some(JSString { raw: r })
Some(JSString { raw: result })
}
}

Expand Down Expand Up @@ -101,12 +111,9 @@ impl JSContext {
let global_object = unsafe { JSContextGetGlobalObject(self.raw) };

if global_object.is_null() {
Err(JSValue::new_inner(self.raw, global_object).into())
Err(unsafe { JSValue::from_raw(self.raw, global_object) }.into())
} else {
Ok(JSObject {
raw: global_object,
value: JSValue::new_inner(self.raw, global_object),
})
Ok(unsafe { JSObject::from_raw(self.raw, global_object) })
}
}
}
Expand All @@ -122,9 +129,7 @@ impl Default for JSContext {
/// However, you may not use values created in the context in other
/// contexts.
fn default() -> Self {
JSContext {
raw: unsafe { sys::JSGlobalContextCreate(ptr::null_mut()) },
}
unsafe { Self::from_raw(sys::JSGlobalContextCreate(ptr::null_mut())) }
}
}

Expand Down
15 changes: 8 additions & 7 deletions src/contextgroup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use std::ptr;
impl JSContextGroup {
/// Creates a JavaScript context group.
pub fn new() -> Self {
JSContextGroup::default()
Self::default()
}

/// Creates a global JavaScript execution context in this context
Expand All @@ -22,9 +22,7 @@ impl JSContextGroup {
///
/// The created global context retains this group.
pub fn new_context(&self) -> JSContext {
JSContext {
raw: unsafe { sys::JSGlobalContextCreateInGroup(self.raw, ptr::null_mut()) },
}
unsafe { JSContext::from_raw(sys::JSGlobalContextCreateInGroup(self.raw, ptr::null_mut())) }
}

/// Creates a global JavaScript execution context in this context
Expand All @@ -39,16 +37,19 @@ impl JSContextGroup {
/// * `global_object_class`: The class to use when creating the global
/// object.
pub fn new_context_with_class(&self, global_object_class: &JSClass) -> JSContext {
JSContext {
raw: unsafe { sys::JSGlobalContextCreateInGroup(self.raw, global_object_class.raw) },
unsafe {
JSContext::from_raw(sys::JSGlobalContextCreateInGroup(
self.raw,
global_object_class.raw,
))
}
}
}

impl Default for JSContextGroup {
/// Creates a JavaScript context group.
fn default() -> Self {
JSContextGroup {
Self {
raw: unsafe { sys::JSContextGroupCreate() },
}
}
Expand Down
8 changes: 7 additions & 1 deletion src/exception.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use crate::{JSException, JSString, JSValue};
use crate::{sys, JSException, JSString, JSValue};

impl JSException {
/// Return the underlying value backing the exception.
Expand All @@ -28,3 +28,9 @@ impl From<JSValue> for JSException {
Self { value }
}
}

impl From<JSException> for sys::JSValueRef {
fn from(value: JSException) -> Self {
value.value.raw
}
}
3 changes: 2 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
unused_qualifications
)]

extern crate javascriptcore_sys as sys;
pub use javascriptcore_macros::function_callback;
use javascriptcore_sys as sys;

mod base;
mod class;
Expand Down
28 changes: 20 additions & 8 deletions src/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,18 @@ use std::ops::Deref;
use std::ptr;

impl JSObject {
/// Create a new [`Self`] from its raw pointer directly.
///
/// # Safety
///
/// Ensure `raw` is valid.
pub unsafe fn from_raw(ctx: sys::JSContextRef, raw: sys::JSObjectRef) -> Self {
Self {
raw,
value: JSValue::from_raw(ctx, raw),
}
}

/// Gets an iterator over the names of an object's enumerable properties.
///
/// ```
Expand Down Expand Up @@ -80,7 +92,7 @@ impl JSObject {
sys::JSObjectGetProperty(self.value.ctx, self.raw, name.into().raw, &mut exception)
};

JSValue::new_inner(self.value.ctx, value)
unsafe { JSValue::from_raw(self.value.ctx, value) }
}

/// Gets a property from an object by numeric index.
Expand Down Expand Up @@ -129,7 +141,7 @@ impl JSObject {
sys::JSObjectGetPropertyAtIndex(self.value.ctx, self.raw, index, &mut exception)
};

JSValue::new_inner(self.value.ctx, value)
unsafe { JSValue::from_raw(self.value.ctx, value) }
}

/// Set a property onto an object.
Expand Down Expand Up @@ -167,7 +179,7 @@ impl JSObject {
}

if !exception.is_null() {
return Err(JSValue::new_inner(context, exception).into());
return Err(unsafe { JSValue::from_raw(context, exception) }.into());
}

Ok(())
Expand Down Expand Up @@ -202,7 +214,7 @@ impl JSObject {
}

if !exception.is_null() {
return Err(JSValue::new_inner(context, exception).into());
return Err(unsafe { JSValue::from_raw(context, exception) }.into());
}

Ok(())
Expand Down Expand Up @@ -240,7 +252,7 @@ impl JSObject {
};

if !exception.is_null() {
return Err(JSValue::new_inner(context, exception).into());
return Err(unsafe { JSValue::from_raw(context, exception) }.into());
}

if result.is_null() {
Expand All @@ -251,7 +263,7 @@ impl JSObject {
.into());
}

Ok(JSValue::new_inner(context, result))
Ok(unsafe { JSValue::from_raw(context, result) })
}

/// Call this object considering it is a valid function.
Expand Down Expand Up @@ -294,7 +306,7 @@ impl JSObject {
};

if !exception.is_null() {
return Err(JSValue::new_inner(context, exception).into());
return Err(unsafe { JSValue::from_raw(context, exception).into() });
}

if result.is_null() {
Expand All @@ -305,7 +317,7 @@ impl JSObject {
.into());
}

Ok(JSValue::new_inner(context, result))
Ok(unsafe { JSValue::from_raw(context, result) })
}
}

Expand Down
Loading