[oden] The big lifetime removal
It turns out that rust can't really reason about the relationship between the runtime lifetime and the context lifetime in a way that is actually usable. This removes the lifetime stuff in favor of reference counting the runtime itself, via a block that we embed in the pointer. This, I think, it the least worst option here.
This commit is contained in:
parent
898b1fe129
commit
9f808cea31
10 changed files with 269 additions and 312 deletions
|
|
@ -1,42 +1,31 @@
|
|||
use crate::{Class, ClassID, ContextRef, Error, Runtime, ValueRef, ValueResult};
|
||||
use crate::{Class, ClassID, ContextRef, Error, ValueRef, ValueResult};
|
||||
use oden_js_sys as sys;
|
||||
use std::ffi::{c_int, CString};
|
||||
use std::marker;
|
||||
use std::panic::catch_unwind;
|
||||
|
||||
pub trait Callback<'rt>:
|
||||
Fn(&ContextRef<'rt>, &ValueRef<'rt>, &[&ValueRef<'rt>]) -> ValueResult<'rt>
|
||||
{
|
||||
}
|
||||
pub trait Callback: Fn(&ContextRef, &ValueRef, &[&ValueRef]) -> ValueResult {}
|
||||
|
||||
impl<'rt, T> Callback<'rt> for T where
|
||||
T: Fn(&ContextRef<'rt>, &ValueRef<'rt>, &[&ValueRef<'rt>]) -> ValueResult<'rt>
|
||||
{
|
||||
}
|
||||
impl<T> Callback for T where T: Fn(&ContextRef, &ValueRef, &[&ValueRef]) -> ValueResult {}
|
||||
|
||||
struct CallbackObject<'rt, T: Callback<'rt>> {
|
||||
struct CallbackObject<T: Callback> {
|
||||
callback: T,
|
||||
_phantom: marker::PhantomData<&'rt Runtime>,
|
||||
}
|
||||
|
||||
impl<'rt, T: Callback<'rt>> CallbackObject<'rt, T> {
|
||||
fn new(callback: T, context: &ContextRef<'rt>) -> ValueResult<'rt> {
|
||||
let obj = CallbackObject {
|
||||
callback,
|
||||
_phantom: marker::PhantomData,
|
||||
};
|
||||
impl<T: Callback> CallbackObject<T> {
|
||||
fn new(callback: T, context: &ContextRef) -> ValueResult {
|
||||
let obj = CallbackObject { callback };
|
||||
obj.into_value(context)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'rt, T: Callback<'rt>> Class for CallbackObject<'rt, T> {
|
||||
impl<T: Callback> Class for CallbackObject<T> {
|
||||
fn class_id() -> &'static ClassID {
|
||||
static ID: ClassID = ClassID::new("CallbackObject");
|
||||
&ID
|
||||
}
|
||||
}
|
||||
|
||||
fn throw_string<'rt>(context: &ContextRef<'rt>, message: String) -> sys::JSValue {
|
||||
fn throw_string(context: &ContextRef, message: String) -> sys::JSValue {
|
||||
let ctx = context.ctx;
|
||||
match context.new_string(&message) {
|
||||
Ok(e) => unsafe {
|
||||
|
|
@ -70,7 +59,7 @@ fn throw_string<'rt>(context: &ContextRef<'rt>, message: String) -> sys::JSValue
|
|||
}
|
||||
}
|
||||
|
||||
fn callback_impl<'rt, F>(
|
||||
fn callback_impl<F>(
|
||||
ctx: *mut sys::JSContext,
|
||||
_this: sys::JSValue,
|
||||
argc: c_int,
|
||||
|
|
@ -79,15 +68,15 @@ fn callback_impl<'rt, F>(
|
|||
data: *mut sys::JSValue,
|
||||
) -> sys::JSValue
|
||||
where
|
||||
F: Callback<'rt>,
|
||||
F: Callback,
|
||||
{
|
||||
let context: ContextRef<'_> = ContextRef::from_raw(ctx);
|
||||
let this: ValueRef = ValueRef::from_raw(_this, &context);
|
||||
let context: ContextRef = ContextRef::from_raw(ctx);
|
||||
let this: ValueRef = ValueRef::from_raw(_this);
|
||||
|
||||
let mut actual_args = Vec::new();
|
||||
unsafe {
|
||||
for arg in std::slice::from_raw_parts(argv, argc.try_into().unwrap()) {
|
||||
actual_args.push(ValueRef::from_raw(*arg, &context));
|
||||
actual_args.push(ValueRef::from_raw(*arg));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -97,7 +86,7 @@ where
|
|||
}
|
||||
|
||||
// Grab the callback that we stashed in the value.
|
||||
let data_ref = unsafe { ValueRef::from_raw(*data, &context) };
|
||||
let data_ref = unsafe { ValueRef::from_raw(*data) };
|
||||
let result = match CallbackObject::<F>::try_from_value(&data_ref) {
|
||||
Ok(closure) => (closure.callback)(&context, &this, &args),
|
||||
Err(e) => Err(e),
|
||||
|
|
@ -125,7 +114,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn trampoline<'rt, F>(
|
||||
unsafe extern "C" fn trampoline<F>(
|
||||
ctx: *mut sys::JSContext,
|
||||
_this: sys::JSValue,
|
||||
argc: c_int,
|
||||
|
|
@ -134,9 +123,9 @@ unsafe extern "C" fn trampoline<'rt, F>(
|
|||
data: *mut sys::JSValue,
|
||||
) -> sys::JSValue
|
||||
where
|
||||
F: Callback<'rt>,
|
||||
F: Callback,
|
||||
{
|
||||
match catch_unwind(|| callback_impl::<'rt, F>(ctx, _this, argc, argv, _magic, data)) {
|
||||
match catch_unwind(|| callback_impl::<F>(ctx, _this, argc, argv, _magic, data)) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
let message = if let Some(e) = e.downcast_ref::<&'static str>() {
|
||||
|
|
@ -145,7 +134,7 @@ where
|
|||
format!("Unknown error")
|
||||
};
|
||||
|
||||
let context: ContextRef<'_> = ContextRef::from_raw(ctx);
|
||||
let context: ContextRef = ContextRef::from_raw(ctx);
|
||||
throw_string(&context, message)
|
||||
}
|
||||
}
|
||||
|
|
@ -155,17 +144,17 @@ where
|
|||
/// function here to intuit the type of the closure, otherwise otherwise
|
||||
/// there's nothing we can put in the `<>` for `trampoline`. This also
|
||||
/// ensures that the rust compiler actually generates the trampoline.
|
||||
fn get_trampoline<'rt, F>(_closure: &F) -> sys::JSCFunctionData
|
||||
fn get_trampoline<F>(_closure: &F) -> sys::JSCFunctionData
|
||||
where
|
||||
F: Callback<'rt>,
|
||||
F: Callback,
|
||||
{
|
||||
Some(trampoline::<F>)
|
||||
}
|
||||
|
||||
/// Construct a new value that wraps a closure.
|
||||
pub(crate) fn new_fn<'rt, F>(ctx: &ContextRef<'rt>, func: F) -> sys::JSValue
|
||||
pub(crate) fn new_fn<F>(ctx: &ContextRef, func: F) -> sys::JSValue
|
||||
where
|
||||
F: Callback<'rt>,
|
||||
F: Callback,
|
||||
{
|
||||
let closure = func;
|
||||
let callback = get_trampoline(&closure);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue