diff --git a/oden-js/src/atom.rs b/oden-js/src/atom.rs index 620f836a..5da81924 100644 --- a/oden-js/src/atom.rs +++ b/oden-js/src/atom.rs @@ -1,65 +1,58 @@ use crate::{ContextRef, Runtime, ValueResult}; use oden_js_sys as sys; -use std::marker; use std::ops::Deref; -pub struct AtomRef<'r> { +pub struct AtomRef { pub(crate) atom: sys::JSAtom, - _marker: marker::PhantomData<&'r Runtime>, } -impl<'r> AtomRef<'r> { - pub(crate) fn from_raw(atom: sys::JSAtom, _ctx: &ContextRef<'r>) -> AtomRef<'r> { - AtomRef { - atom, - _marker: marker::PhantomData, - } +impl AtomRef { + pub(crate) fn from_raw(atom: sys::JSAtom, _ctx: &ContextRef) -> AtomRef { + AtomRef { atom } } - pub fn dup(&self, context: &ContextRef<'r>) -> Atom<'r> { + pub fn dup(&self, context: &ContextRef) -> Atom { unsafe { sys::JS_DupAtom(context.ctx, self.atom); } Atom::from_raw(self.atom, context) } - pub fn to_value(&self, context: &ContextRef<'r>) -> ValueResult<'r> { + pub fn to_value(&self, context: &ContextRef) -> ValueResult { context.check_exception(unsafe { sys::JS_AtomToValue(context.ctx, self.atom) }) } - pub fn to_string_value(&self, context: &ContextRef<'r>) -> ValueResult<'r> { + pub fn to_string_value(&self, context: &ContextRef) -> ValueResult { context.check_exception(unsafe { sys::JS_AtomToString(context.ctx, self.atom) }) } } -pub struct Atom<'r> { - atom: AtomRef<'r>, - rt: *mut sys::JSRuntime, - _phantom: marker::PhantomData<&'r Runtime>, +pub struct Atom { + atom: AtomRef, + rt: Runtime, } -impl<'r> Atom<'r> { - pub(crate) fn from_raw(atom: sys::JSAtom, ctx: &ContextRef<'r>) -> Self { +impl Atom { + pub(crate) fn from_raw(atom: sys::JSAtom, ctx: &ContextRef) -> Self { Atom { atom: AtomRef::from_raw(atom, ctx), - rt: unsafe { sys::JS_GetRuntime(ctx.ctx) }, - _phantom: marker::PhantomData, + rt: Runtime::from_raw(unsafe { sys::JS_GetRuntime(ctx.ctx) }), } } } -impl<'r> Deref for Atom<'r> { - type Target = AtomRef<'r>; +impl Deref for Atom { + type Target = AtomRef; fn deref(&self) -> &Self::Target { &self.atom } } -impl<'r> Drop for Atom<'r> { +impl Drop for Atom { fn drop(&mut self) { unsafe { - sys::JS_FreeAtomRT(self.rt, self.atom.atom); + sys::JS_FreeAtomRT(self.rt.rt, self.atom.atom); } } } diff --git a/oden-js/src/callback.rs b/oden-js/src/callback.rs index 2c94f321..e7bbd345 100644 --- a/oden-js/src/callback.rs +++ b/oden-js/src/callback.rs @@ -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 Callback for T where T: Fn(&ContextRef, &ValueRef, &[&ValueRef]) -> ValueResult {} -struct CallbackObject<'rt, T: Callback<'rt>> { +struct CallbackObject { 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 CallbackObject { + 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 Class for CallbackObject { 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( 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::::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( 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::(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(_closure: &F) -> sys::JSCFunctionData where - F: Callback<'rt>, + F: Callback, { Some(trampoline::) } /// 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(ctx: &ContextRef, func: F) -> sys::JSValue where - F: Callback<'rt>, + F: Callback, { let closure = func; let callback = get_trampoline(&closure); diff --git a/oden-js/src/class.rs b/oden-js/src/class.rs index fb1fa0c2..3aab112a 100644 --- a/oden-js/src/class.rs +++ b/oden-js/src/class.rs @@ -61,7 +61,7 @@ impl fmt::Debug for ClassID { pub trait Class: Sized { fn class_id() -> &'static ClassID; - fn into_value<'r>(self, context: &ContextRef<'r>) -> ValueResult<'r> { + fn into_value(self, context: &ContextRef) -> ValueResult { let class_id = Self::class_id(); // Check to see if the class is registered with the runtime. If not, @@ -122,7 +122,7 @@ pub trait Class: Sized { Ok(val) } - fn try_from_value_mut<'r>(value: &ValueRef<'r>) -> Result<'r, RefMut<'r, Self>> { + fn try_from_value_mut<'a>(value: &'a ValueRef) -> Result> { let class = Self::class_id(); // SAFETY: value.val is known to be valid, from the ValueRef. @@ -139,11 +139,11 @@ pub trait Class: Sized { .borrow_mut()) } - fn from_value_mut<'r>(value: &ValueRef<'r>) -> RefMut<'r, Self> { + fn from_value_mut<'a>(value: &'a ValueRef) -> RefMut<'a, Self> { Self::try_from_value_mut(value).expect("Wrong type for value") } - fn try_from_value<'r>(value: &ValueRef<'r>) -> Result<'r, Ref<'r, Self>> { + fn try_from_value<'a>(value: &'a ValueRef) -> Result> { let class = Self::class_id(); // SAFETY: value.val is known to be valid, from the ValueRef. @@ -160,7 +160,7 @@ pub trait Class: Sized { .borrow()) } - fn from_value<'r>(value: &ValueRef<'r>) -> Ref<'r, Self> { + fn from_value<'a>(value: &'a ValueRef) -> Ref<'a, Self> { match Self::try_from_value(value) { Ok(r) => r, Err(_) => panic!( @@ -171,7 +171,7 @@ pub trait Class: Sized { } } - fn prototype<'r>(context: &ContextRef<'r>) -> ValueResult<'r> { + fn prototype(context: &ContextRef) -> ValueResult { context.new_object() } @@ -192,7 +192,7 @@ pub trait Class: Sized { /// collector won't collect it. fn mark(&self, _mark: F) where - F: for<'r> Fn(&ValueRef<'r>) -> (), + F: Fn(&ValueRef) -> (), { // By default, nothing. } @@ -268,7 +268,7 @@ mod tests { #[test] fn round_trips() { let rt = Runtime::new(); - let ctx = Context::new(&rt); + let ctx = Context::new(rt); let x = X { x: 76 }; let val = x.into_value(&ctx).expect("Unable to create value!"); @@ -280,7 +280,7 @@ mod tests { #[test] fn double_create() { let rt = Runtime::new(); - let ctx = Context::new(&rt); + let ctx = Context::new(rt); let x = X { x: 76 }; let _v1 = x.into_value(&ctx).expect("Unable to create value!"); @@ -292,7 +292,7 @@ mod tests { #[test] fn bad_class_id() { let rt = Runtime::new(); - let ctx = Context::new(&rt); + let ctx = Context::new(rt); let y = Y { y: 110 }; let val = y.into_value(&ctx).expect("Unable to create value!"); diff --git a/oden-js/src/context.rs b/oden-js/src/context.rs index 954e29bf..00aa6247 100644 --- a/oden-js/src/context.rs +++ b/oden-js/src/context.rs @@ -5,7 +5,6 @@ use crate::{ use bitflags::bitflags; use oden_js_sys as sys; use std::ffi::CString; -use std::marker; use std::ops::{Deref, DerefMut}; /// Different ways to evaluate JavaScript. See the various `eval` methods on @@ -43,17 +42,13 @@ bitflags! { } #[derive(Debug)] -pub struct ContextRef<'rt> { +pub struct ContextRef { pub(crate) ctx: *mut sys::JSContext, - _marker: marker::PhantomData<&'rt Runtime>, } -impl<'rt> ContextRef<'rt> { +impl ContextRef { pub(crate) fn from_raw(ctx: *mut sys::JSContext) -> Self { - ContextRef { - ctx, - _marker: marker::PhantomData, - } + ContextRef { ctx } } pub fn is_registered_class(&self, id: &ClassID) -> bool { @@ -118,7 +113,7 @@ impl<'rt> ContextRef<'rt> { filename: &str, eval_type: EvalType, flags: EvalFlags, - ) -> ValueResult<'rt> { + ) -> ValueResult { let c_input = match CString::new(input) { Ok(cs) => Ok(cs), Err(_) => Err(Error::UnexpectedNul), @@ -146,7 +141,7 @@ impl<'rt> ContextRef<'rt> { } /// Construct a new string atom. - pub fn new_atom(&self, value: &str) -> Result<'rt, Atom<'rt>> { + pub fn new_atom(&self, value: &str) -> Result { let c_value = match CString::new(value) { Ok(cs) => Ok(cs), Err(_) => Err(Error::UnexpectedNul), @@ -161,12 +156,12 @@ impl<'rt> ContextRef<'rt> { } /// Construct a new value of type object. - pub fn new_object(&self) -> ValueResult<'rt> { + pub fn new_object(&self) -> ValueResult { self.check_exception(unsafe { sys::JS_NewObject(self.ctx) }) } /// Construct a new value from a boolean. - pub fn new_bool(&self, value: T) -> ValueResult<'rt> + pub fn new_bool(&self, value: T) -> ValueResult where T: Into, { @@ -174,14 +169,14 @@ impl<'rt> ContextRef<'rt> { } /// Construct a new value that wraps a strongly-typed closure. - pub fn new_fn(&self, func: impl RustFunction<'rt, F>) -> ValueResult<'rt> { + pub fn new_fn(&self, func: impl RustFunction) -> ValueResult { self.new_dynamic_fn(|c, _, a| func.call(c, a)) } /// Construct a new value that wraps a dynamically-typed closure. - pub fn new_dynamic_fn(&self, func: F) -> ValueResult<'rt> + pub fn new_dynamic_fn(&self, func: F) -> ValueResult where - F: Fn(&ContextRef<'rt>, &ValueRef<'rt>, &[&ValueRef<'rt>]) -> ValueResult<'rt>, + F: Fn(&ContextRef, &ValueRef, &[&ValueRef]) -> ValueResult, { // Constructing a new function is complicated enough that it needs to // be out of line. @@ -189,7 +184,7 @@ impl<'rt> ContextRef<'rt> { } /// Construct a new value from an int32. - pub fn new_i32(&self, value: T) -> ValueResult<'rt> + pub fn new_i32(&self, value: T) -> ValueResult where T: Into, { @@ -200,7 +195,7 @@ impl<'rt> ContextRef<'rt> { /// /// This returns a value of type Int32 if the value fits into an int32, /// otherwise it returns a value of type Float64. - pub fn new_u32(&self, value: T) -> ValueResult<'rt> + pub fn new_u32(&self, value: T) -> ValueResult where T: Into, { @@ -208,7 +203,7 @@ impl<'rt> ContextRef<'rt> { } /// Construct a new value from a float64. - pub fn new_f64(&self, value: T) -> ValueResult<'rt> + pub fn new_f64(&self, value: T) -> ValueResult where T: Into, { @@ -216,7 +211,7 @@ impl<'rt> ContextRef<'rt> { } /// Construct a new BigInt from an i64 - pub fn new_i64(&self, value: T) -> ValueResult<'rt> + pub fn new_i64(&self, value: T) -> ValueResult where T: Into, { @@ -224,7 +219,7 @@ impl<'rt> ContextRef<'rt> { } /// Construct a new BigInt from an u64 - pub fn new_u64(&self, value: T) -> ValueResult<'rt> + pub fn new_u64(&self, value: T) -> ValueResult where T: Into, { @@ -232,12 +227,12 @@ impl<'rt> ContextRef<'rt> { } /// Construct a new array value. - pub fn new_array(&self) -> ValueResult<'rt> { + pub fn new_array(&self) -> ValueResult { self.check_exception(unsafe { sys::JS_NewArray(self.ctx) }) } /// Construct a new value from a string. - pub fn new_string(&self, value: &str) -> ValueResult<'rt> { + pub fn new_string(&self, value: &str) -> ValueResult { let c_value = match CString::new(value) { Ok(cs) => Ok(cs), Err(_) => Err(Error::UnexpectedNul), @@ -249,7 +244,7 @@ impl<'rt> ContextRef<'rt> { } /// Get the null value. - pub fn null(&self) -> Value<'rt> { + pub fn null(&self) -> Value { let v = sys::JSValue { u: sys::JSValueUnion { ptr: std::ptr::null_mut(), @@ -260,7 +255,7 @@ impl<'rt> ContextRef<'rt> { } /// Get the undefined value. - pub fn undefined(&self) -> Value<'rt> { + pub fn undefined(&self) -> Value { let v = sys::JSValue { u: sys::JSValueUnion { ptr: std::ptr::null_mut(), @@ -271,14 +266,14 @@ impl<'rt> ContextRef<'rt> { } /// Fetch the global object for the context. - pub fn global_object(&self) -> ValueResult<'rt> { + pub fn global_object(&self) -> ValueResult { self.check_exception(unsafe { sys::JS_GetGlobalObject(self.ctx) }) } /// Check the value to see if it is the special marker for an exception, /// and if so grab the exception from the context and return it in an /// error value. Otherwise, just return success with the value, wrapped. - pub(crate) fn check_exception(&self, val: sys::JSValue) -> ValueResult<'rt> { + pub(crate) fn check_exception(&self, val: sys::JSValue) -> ValueResult { if unsafe { sys::JS_ValueGetTag(val) } == sys::JS_TAG_EXCEPTION { Err(Error::Exception(self.exception())) } else { @@ -290,17 +285,18 @@ impl<'rt> ContextRef<'rt> { /// public because anything that might raise an exception should be /// returning a Result<> instead, to separate the exception flow from the /// value flow. - pub(crate) fn exception(&self) -> Value<'rt> { + pub(crate) fn exception(&self) -> Value { Value::from_raw(unsafe { sys::JS_GetException(self.ctx) }, self) } } #[derive(Debug)] -pub struct Context<'rt> { - value: ContextRef<'rt>, +pub struct Context { + value: ContextRef, + runtime: Runtime, } -impl<'rt> Context<'rt> { +impl Context { /// Construct a new JavaScript context with many of the useful instrinisc /// functions defined. Objects created by this context can be shared /// across contexts belonging to the same runtime. @@ -321,9 +317,9 @@ impl<'rt> Context<'rt> { /// /// If you don't want those objects, call `new_raw`, and then add the /// intrinsics that you want. - pub fn new(runtime: &Runtime) -> Context { + pub fn new(runtime: Runtime) -> Context { let value = unsafe { ContextRef::from_raw(sys::JS_NewContext(runtime.rt)) }; - Context { value } + Context { value, runtime } } /// Construct a new JavaScript context without any intrinsic @@ -332,27 +328,32 @@ impl<'rt> Context<'rt> { /// /// You will probably want to call one or more of the `add_intrinsic_` /// functions to add useful types to the runtime. - pub fn new_raw(runtime: &Runtime) -> Context { + pub fn new_raw(runtime: Runtime) -> Context { let value = unsafe { ContextRef::from_raw(sys::JS_NewContextRaw(runtime.rt)) }; - Context { value } + Context { value, runtime } + } + + /// Get the runtime underlying this context. + pub fn runtime(&self) -> &Runtime { + &self.runtime } } -impl<'rt> Deref for Context<'rt> { - type Target = ContextRef<'rt>; +impl Deref for Context { + type Target = ContextRef; fn deref(&self) -> &Self::Target { &self.value } } -impl<'rt> DerefMut for Context<'rt> { +impl DerefMut for Context { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.value } } -impl<'rt> Drop for Context<'rt> { +impl Drop for Context { fn drop(&mut self) { unsafe { sys::JS_FreeContext(self.value.ctx); @@ -368,7 +369,7 @@ mod tests { #[test] fn basic_evaluation() { let rt = Runtime::new(); - let ctx = Context::new(&rt); + let ctx = Context::new(rt); let val = ctx .eval("1+1", "script", EvalType::Global, EvalFlags::NONE) @@ -380,7 +381,7 @@ mod tests { #[test] fn eval_compiled() { let rt = Runtime::new(); - let ctx = Context::new(&rt); + let ctx = Context::new(rt); let compiled = ctx .eval("1 + 1", "script", EvalType::Global, EvalFlags::COMPILE_ONLY) @@ -395,7 +396,7 @@ mod tests { #[test] fn global_object() { let rt = Runtime::new(); - let ctx = Context::new(&rt); + let ctx = Context::new(rt); let mut go = ctx.global_object().unwrap(); assert_eq!(ValueType::Object, go.value_type()); @@ -409,18 +410,14 @@ mod tests { assert_eq!(String::from("15"), result.to_string(&ctx).unwrap()); } - fn cb<'c>( - ctx: &ContextRef<'c>, - _this: &ValueRef<'c>, - args: &[&ValueRef<'c>], - ) -> ValueResult<'c> { + fn cb(ctx: &ContextRef, _this: &ValueRef, args: &[&ValueRef]) -> ValueResult { Ok(args[1].dup(ctx)) } #[test] fn new_objects() { let rt = Runtime::new(); - let ctx = Context::new(&rt); + let ctx = Context::new(rt); let mut go = ctx.global_object().unwrap(); @@ -461,7 +458,7 @@ mod tests { #[test] fn real_closures() { let rt = Runtime::new(); - let ctx = Context::new(&rt); + let ctx = Context::new(rt); let return_value = ctx.new_string("unsafe").unwrap(); { diff --git a/oden-js/src/conversion/from.rs b/oden-js/src/conversion/from.rs index bcd72057..4d12e776 100644 --- a/oden-js/src/conversion/from.rs +++ b/oden-js/src/conversion/from.rs @@ -2,12 +2,12 @@ use crate::{ContextRef, Error, Result, ValueRef}; use std::num::TryFromIntError; pub trait TryFromValue: Sized { - fn try_from_value<'r>(value: &ValueRef<'r>, ctx: &ContextRef<'r>) -> Result<'r, Self>; + fn try_from_value(value: &ValueRef, ctx: &ContextRef) -> Result; } impl TryFromValue for u8 { #[inline] - fn try_from_value<'r>(value: &ValueRef<'r>, ctx: &ContextRef<'r>) -> Result<'r, Self> { + fn try_from_value(value: &ValueRef, ctx: &ContextRef) -> Result { let v = value.to_u32(&ctx)?; v.try_into() .map_err(|e: TryFromIntError| Error::ConversionError(e.to_string())) @@ -16,7 +16,7 @@ impl TryFromValue for u8 { impl TryFromValue for u16 { #[inline] - fn try_from_value<'r>(value: &ValueRef<'r>, ctx: &ContextRef<'r>) -> Result<'r, Self> { + fn try_from_value(value: &ValueRef, ctx: &ContextRef) -> Result { let v = value.to_u32(&ctx)?; v.try_into() .map_err(|e: TryFromIntError| Error::ConversionError(e.to_string())) @@ -25,21 +25,21 @@ impl TryFromValue for u16 { impl TryFromValue for u32 { #[inline] - fn try_from_value<'r>(value: &ValueRef<'r>, ctx: &ContextRef<'r>) -> Result<'r, Self> { + fn try_from_value(value: &ValueRef, ctx: &ContextRef) -> Result { value.to_u32(&ctx) } } // impl<'c,'d> TryFrom<&'c ValueRef<'d>> for u64 { // #[inline] -// fn try_from_value<'r>(value: &ValueRef<'r>, ctx:&ContextRef<'r>) -> Result<'r, Self> { +// fn try_from_value(value: &ValueRef, ctx:&ContextRef) -> Result< Self> { // value.to_u64() // } // } impl TryFromValue for i8 { #[inline] - fn try_from_value<'r>(value: &ValueRef<'r>, ctx: &ContextRef<'r>) -> Result<'r, Self> { + fn try_from_value(value: &ValueRef, ctx: &ContextRef) -> Result { let v = value.to_i32(&ctx)?; v.try_into() .map_err(|e: TryFromIntError| Error::ConversionError(e.to_string())) @@ -48,7 +48,7 @@ impl TryFromValue for i8 { impl TryFromValue for i16 { #[inline] - fn try_from_value<'r>(value: &ValueRef<'r>, ctx: &ContextRef<'r>) -> Result<'r, Self> { + fn try_from_value(value: &ValueRef, ctx: &ContextRef) -> Result { let v = value.to_i32(&ctx)?; v.try_into() .map_err(|e: TryFromIntError| Error::ConversionError(e.to_string())) @@ -57,21 +57,21 @@ impl TryFromValue for i16 { impl TryFromValue for i32 { #[inline] - fn try_from_value<'r>(value: &ValueRef<'r>, ctx: &ContextRef<'r>) -> Result<'r, Self> { + fn try_from_value(value: &ValueRef, ctx: &ContextRef) -> Result { value.to_i32(&ctx) } } impl TryFromValue for i64 { #[inline] - fn try_from_value<'r>(value: &ValueRef<'r>, ctx: &ContextRef<'r>) -> Result<'r, Self> { + fn try_from_value(value: &ValueRef, ctx: &ContextRef) -> Result { value.to_i64(&ctx) } } impl TryFromValue for f32 { #[inline] - fn try_from_value<'r>(value: &ValueRef<'r>, ctx: &ContextRef<'r>) -> Result<'r, Self> { + fn try_from_value(value: &ValueRef, ctx: &ContextRef) -> Result { let v = value.to_float64(&ctx)?; Ok(v as f32) } @@ -79,21 +79,21 @@ impl TryFromValue for f32 { impl TryFromValue for f64 { #[inline] - fn try_from_value<'r>(value: &ValueRef<'r>, ctx: &ContextRef<'r>) -> Result<'r, Self> { + fn try_from_value(value: &ValueRef, ctx: &ContextRef) -> Result { value.to_float64(&ctx) } } impl TryFromValue for bool { #[inline] - fn try_from_value<'r>(value: &ValueRef<'r>, _ctx: &ContextRef<'r>) -> Result<'r, Self> { + fn try_from_value(value: &ValueRef, _ctx: &ContextRef) -> Result { value.to_bool() } } impl TryFromValue for String { #[inline] - fn try_from_value<'r>(value: &ValueRef<'r>, ctx: &ContextRef<'r>) -> Result<'r, Self> { + fn try_from_value(value: &ValueRef, ctx: &ContextRef) -> Result { value.to_string(&ctx) } } @@ -101,7 +101,7 @@ impl TryFromValue for String { // impl<'c, T: Class> TryFrom<&'c ValueRef<'_>> for T { // // #[inline] -// fn try_from_value<'r>(value: &ValueRef<'r>, ctx:&ContextRef<'r>) -> Result<'r, Self> { +// fn try_from_value(value: &ValueRef, ctx:&ContextRef) -> Result< Self> { // T::from_value(value) // } // } diff --git a/oden-js/src/conversion/function.rs b/oden-js/src/conversion/function.rs index 2945dcbe..8f5148d2 100644 --- a/oden-js/src/conversion/function.rs +++ b/oden-js/src/conversion/function.rs @@ -2,20 +2,18 @@ use super::{TryFromValue, TryIntoValue}; use crate::{ContextRef, Error, ValueRef, ValueResult}; use std::marker::PhantomData; -pub trait IntoRustFunctionResult<'r> { - fn into_res(self, ctx: &ContextRef<'r>) -> ValueResult<'r>; +pub trait IntoRustFunctionResult { + fn into_res(self, ctx: &ContextRef) -> ValueResult; } -impl<'r, T: TryIntoValue<'r>> IntoRustFunctionResult<'r> for T { - fn into_res(self, ctx: &ContextRef<'r>) -> ValueResult<'r> { +impl IntoRustFunctionResult for T { + fn into_res(self, ctx: &ContextRef) -> ValueResult { self.try_into_value(ctx) } } -impl<'r, T: TryIntoValue<'r>, E: std::fmt::Display> IntoRustFunctionResult<'r> - for core::result::Result -{ - fn into_res(self, ctx: &ContextRef<'r>) -> ValueResult<'r> { +impl IntoRustFunctionResult for core::result::Result { + fn into_res(self, ctx: &ContextRef) -> ValueResult { match self { Ok(v) => v.try_into_value(ctx), Err(e) => Err(Error::RustFunctionError(e.to_string())), @@ -23,21 +21,21 @@ impl<'r, T: TryIntoValue<'r>, E: std::fmt::Display> IntoRustFunctionResult<'r> } } -pub trait RustFunction<'r, F> { +pub trait RustFunction { fn argument_count() -> usize; - fn call(&self, context: &ContextRef<'r>, args: &[&ValueRef<'r>]) -> ValueResult<'r>; + fn call(&self, context: &ContextRef, args: &[&ValueRef]) -> ValueResult; } -impl<'r, R, F> RustFunction<'r, PhantomData<(&R, &F)>> for F +impl RustFunction> for F where - R: IntoRustFunctionResult<'r>, - F: Fn(&ContextRef<'r>) -> R + Sized, + R: IntoRustFunctionResult, + F: Fn(&ContextRef) -> R + Sized, { fn argument_count() -> usize { 0 } - fn call(&self, context: &ContextRef<'r>, args: &[&ValueRef<'r>]) -> ValueResult<'r> { + fn call(&self, context: &ContextRef, args: &[&ValueRef]) -> ValueResult { if args.len() != 0 { return Err(Error::ArgumentCountMismatch { expected: Self::argument_count(), @@ -50,17 +48,17 @@ where } } -impl<'r, R, A, F> RustFunction<'r, PhantomData<(&R, &A, &F)>> for F +impl RustFunction> for F where - R: IntoRustFunctionResult<'r>, + R: IntoRustFunctionResult, A: TryFromValue, - F: Fn(&ContextRef<'r>, A) -> R + Sized, + F: Fn(&ContextRef, A) -> R + Sized, { fn argument_count() -> usize { 1 } - fn call(&self, context: &ContextRef<'r>, args: &[&ValueRef<'r>]) -> ValueResult<'r> { + fn call(&self, context: &ContextRef, args: &[&ValueRef]) -> ValueResult { if args.len() != Self::argument_count() { return Err(Error::ArgumentCountMismatch { expected: Self::argument_count(), @@ -74,18 +72,18 @@ where } } -impl<'r, R, A, B, F> RustFunction<'r, PhantomData<(&R, &A, &B, &F)>> for F +impl RustFunction> for F where - R: IntoRustFunctionResult<'r>, + R: IntoRustFunctionResult, A: TryFromValue, B: TryFromValue, - F: Fn(&ContextRef<'r>, A, B) -> R + Sized, + F: Fn(&ContextRef, A, B) -> R + Sized, { fn argument_count() -> usize { 2 } - fn call(&self, context: &ContextRef<'r>, args: &[&ValueRef<'r>]) -> ValueResult<'r> { + fn call(&self, context: &ContextRef, args: &[&ValueRef]) -> ValueResult { if args.len() != Self::argument_count() { return Err(Error::ArgumentCountMismatch { expected: Self::argument_count(), @@ -100,19 +98,19 @@ where } } -impl<'r, R, A, B, C, F> RustFunction<'r, PhantomData<(&R, &A, &B, &C, &F)>> for F +impl RustFunction> for F where - R: IntoRustFunctionResult<'r>, + R: IntoRustFunctionResult, A: TryFromValue, B: TryFromValue, C: TryFromValue, - F: Fn(&ContextRef<'r>, A, B, C) -> R + Sized, + F: Fn(&ContextRef, A, B, C) -> R + Sized, { fn argument_count() -> usize { 3 } - fn call(&self, context: &ContextRef<'r>, args: &[&ValueRef<'r>]) -> ValueResult<'r> { + fn call(&self, context: &ContextRef, args: &[&ValueRef]) -> ValueResult { if args.len() != Self::argument_count() { return Err(Error::ArgumentCountMismatch { expected: Self::argument_count(), @@ -128,20 +126,20 @@ where } } -impl<'r, R, A, B, C, D, F> RustFunction<'r, PhantomData<(&R, &A, &B, &C, &D, &F)>> for F +impl RustFunction> for F where - R: IntoRustFunctionResult<'r>, + R: IntoRustFunctionResult, A: TryFromValue, B: TryFromValue, C: TryFromValue, D: TryFromValue, - F: Fn(&ContextRef<'r>, A, B, C, D) -> R + Sized, + F: Fn(&ContextRef, A, B, C, D) -> R + Sized, { fn argument_count() -> usize { 4 } - fn call(&self, context: &ContextRef<'r>, args: &[&ValueRef<'r>]) -> ValueResult<'r> { + fn call(&self, context: &ContextRef, args: &[&ValueRef]) -> ValueResult { if args.len() != Self::argument_count() { return Err(Error::ArgumentCountMismatch { expected: Self::argument_count(), @@ -158,21 +156,21 @@ where } } -impl<'r, R, A, B, C, D, E, F> RustFunction<'r, PhantomData<(&R, &A, &B, &C, &D, &E, &F)>> for F +impl RustFunction> for F where - R: IntoRustFunctionResult<'r>, + R: IntoRustFunctionResult, A: TryFromValue, B: TryFromValue, C: TryFromValue, D: TryFromValue, E: TryFromValue, - F: Fn(&ContextRef<'r>, A, B, C, D, E) -> R + Sized, + F: Fn(&ContextRef, A, B, C, D, E) -> R + Sized, { fn argument_count() -> usize { 5 } - fn call(&self, context: &ContextRef<'r>, args: &[&ValueRef<'r>]) -> ValueResult<'r> { + fn call(&self, context: &ContextRef, args: &[&ValueRef]) -> ValueResult { if args.len() != Self::argument_count() { return Err(Error::ArgumentCountMismatch { expected: Self::argument_count(), diff --git a/oden-js/src/conversion/into.rs b/oden-js/src/conversion/into.rs index 05893a9b..c57e4671 100644 --- a/oden-js/src/conversion/into.rs +++ b/oden-js/src/conversion/into.rs @@ -1,110 +1,110 @@ use crate::{Class, ContextRef, Error, Value, ValueRef, ValueResult}; -pub trait TryIntoValue<'r> { - fn try_into_value(self, ctx: &ContextRef<'r>) -> ValueResult<'r>; +pub trait TryIntoValue { + fn try_into_value(self, ctx: &ContextRef) -> ValueResult; } -impl<'r> TryIntoValue<'r> for u8 { +impl TryIntoValue for u8 { #[inline] - fn try_into_value(self, ctx: &ContextRef<'r>) -> ValueResult<'r> { + fn try_into_value(self, ctx: &ContextRef) -> ValueResult { ctx.new_u64(self) } } -impl<'r> TryIntoValue<'r> for u16 { +impl TryIntoValue for u16 { #[inline] - fn try_into_value(self, ctx: &ContextRef<'r>) -> ValueResult<'r> { + fn try_into_value(self, ctx: &ContextRef) -> ValueResult { ctx.new_u64(self) } } -impl<'r> TryIntoValue<'r> for u32 { +impl TryIntoValue for u32 { #[inline] - fn try_into_value(self, ctx: &ContextRef<'r>) -> ValueResult<'r> { + fn try_into_value(self, ctx: &ContextRef) -> ValueResult { ctx.new_u64(self) } } -impl<'r> TryIntoValue<'r> for u64 { +impl TryIntoValue for u64 { #[inline] - fn try_into_value(self, ctx: &ContextRef<'r>) -> ValueResult<'r> { + fn try_into_value(self, ctx: &ContextRef) -> ValueResult { ctx.new_u64(self) } } -impl<'r> TryIntoValue<'r> for i8 { +impl TryIntoValue for i8 { #[inline] - fn try_into_value(self, ctx: &ContextRef<'r>) -> ValueResult<'r> { + fn try_into_value(self, ctx: &ContextRef) -> ValueResult { ctx.new_i32(self) } } -impl<'r> TryIntoValue<'r> for i16 { +impl TryIntoValue for i16 { #[inline] - fn try_into_value(self, ctx: &ContextRef<'r>) -> ValueResult<'r> { + fn try_into_value(self, ctx: &ContextRef) -> ValueResult { ctx.new_i32(self) } } -impl<'r> TryIntoValue<'r> for i32 { +impl TryIntoValue for i32 { #[inline] - fn try_into_value(self, ctx: &ContextRef<'r>) -> ValueResult<'r> { + fn try_into_value(self, ctx: &ContextRef) -> ValueResult { ctx.new_i32(self) } } -impl<'r> TryIntoValue<'r> for i64 { +impl TryIntoValue for i64 { #[inline] - fn try_into_value(self, ctx: &ContextRef<'r>) -> ValueResult<'r> { + fn try_into_value(self, ctx: &ContextRef) -> ValueResult { ctx.new_i64(self) } } -impl<'r> TryIntoValue<'r> for f32 { +impl TryIntoValue for f32 { #[inline] - fn try_into_value(self, ctx: &ContextRef<'r>) -> ValueResult<'r> { + fn try_into_value(self, ctx: &ContextRef) -> ValueResult { ctx.new_f64(self) } } -impl<'r> TryIntoValue<'r> for f64 { +impl TryIntoValue for f64 { #[inline] - fn try_into_value(self, ctx: &ContextRef<'r>) -> ValueResult<'r> { + fn try_into_value(self, ctx: &ContextRef) -> ValueResult { ctx.new_f64(self) } } -impl<'r> TryIntoValue<'r> for bool { +impl TryIntoValue for bool { #[inline] - fn try_into_value(self, ctx: &ContextRef<'r>) -> ValueResult<'r> { + fn try_into_value(self, ctx: &ContextRef) -> ValueResult { ctx.new_bool(self) } } -impl<'r> TryIntoValue<'r> for &str { +impl TryIntoValue for &str { #[inline] - fn try_into_value(self, ctx: &ContextRef<'r>) -> ValueResult<'r> { + fn try_into_value(self, ctx: &ContextRef) -> ValueResult { ctx.new_string(self) } } -impl<'r> TryIntoValue<'r> for &ValueRef<'r> { +impl TryIntoValue for &ValueRef { #[inline] - fn try_into_value(self, ctx: &ContextRef<'r>) -> ValueResult<'r> { + fn try_into_value(self, ctx: &ContextRef) -> ValueResult { Ok(self.dup(ctx)) } } -impl<'r> TryIntoValue<'r> for Value<'r> { +impl TryIntoValue for Value { #[inline] - fn try_into_value(self, ctx: &ContextRef<'r>) -> ValueResult<'r> { + fn try_into_value(self, ctx: &ContextRef) -> ValueResult { Ok(self.dup(ctx)) } } -impl<'r> TryIntoValue<'r> for Error<'r> { +impl TryIntoValue for Error { #[inline] - fn try_into_value(self, ctx: &ContextRef<'r>) -> ValueResult<'r> { + fn try_into_value(self, ctx: &ContextRef) -> ValueResult { match self { Error::TooManyClasses => Err(Error::TooManyClasses), Error::WrongClass(c) => Err(Error::WrongClass(c)), @@ -121,9 +121,9 @@ impl<'r> TryIntoValue<'r> for Error<'r> { } } -impl<'r, T: Class> TryIntoValue<'r> for T { +impl TryIntoValue for T { #[inline] - fn try_into_value(self, ctx: &ContextRef<'r>) -> ValueResult<'r> { + fn try_into_value(self, ctx: &ContextRef) -> ValueResult { self.into_value(ctx) } } diff --git a/oden-js/src/lib.rs b/oden-js/src/lib.rs index eeb83f3b..95ee5547 100644 --- a/oden-js/src/lib.rs +++ b/oden-js/src/lib.rs @@ -16,7 +16,7 @@ pub use runtime::Runtime; pub use value::{Value, ValueRef, ValueType}; #[derive(Error, Debug)] -pub enum Error<'ctx> { +pub enum Error { #[error("too many classes have been registered")] TooManyClasses, #[error("the specified value is not an instance of the class {0}")] @@ -37,7 +37,7 @@ pub enum Error<'ctx> { #[error("an error occurred calling a rust function: {0}")] RustFunctionError(String), #[error("an exception was thrown during evaluation")] - Exception(Value<'ctx>), + Exception(Value), } -pub type Result<'ctx, T> = core::result::Result>; -pub type ValueResult<'ctx> = core::result::Result, Error<'ctx>>; +pub type Result = core::result::Result; +pub type ValueResult = core::result::Result; diff --git a/oden-js/src/runtime.rs b/oden-js/src/runtime.rs index b321eae3..ca21535b 100644 --- a/oden-js/src/runtime.rs +++ b/oden-js/src/runtime.rs @@ -1,4 +1,9 @@ use oden_js_sys as sys; +use std::cell::RefCell; + +struct PrivateState { + refs: u64, +} #[derive(Debug)] pub struct Runtime { @@ -7,7 +12,23 @@ pub struct Runtime { impl Runtime { pub fn new() -> Runtime { - let rt = unsafe { sys::JS_NewRuntime() }; + let state = Box::new(RefCell::new(PrivateState { refs: 1 })); + let rt = unsafe { + let rt = sys::JS_NewRuntime(); + sys::JS_SetRuntimeOpaque(rt, Box::into_raw(state) as *mut _); + rt + }; + Runtime { rt } + } + + pub(crate) fn from_raw(rt: *mut sys::JSRuntime) -> Self { + let mut state = unsafe { + let ptr = sys::JS_GetRuntimeOpaque(rt) as *const RefCell; + ptr.as_ref() + .expect("We already know this runtime is one of ours!") + .borrow_mut() + }; + state.refs += 1; Runtime { rt } } @@ -37,11 +58,36 @@ impl Runtime { } } +impl Clone for Runtime { + fn clone(&self) -> Self { + Runtime::from_raw(self.rt) + } +} + impl Drop for Runtime { fn drop(&mut self) { - unsafe { - sys::JS_RunGC(self.rt); - sys::JS_FreeRuntime(self.rt); + let should_free = { + let mut state = unsafe { + let ptr = sys::JS_GetRuntimeOpaque(self.rt) as *const RefCell; + ptr.as_ref() + .expect("We already know this runtime is one of ours!") + .borrow_mut() + }; + state.refs -= 1; + state.refs == 0 + }; + + if should_free { + unsafe { + let opaque = sys::JS_GetRuntimeOpaque(self.rt); + sys::JS_RunGC(self.rt); + sys::JS_FreeRuntime(self.rt); + + if !opaque.is_null() { + // Just let the system drop it here. + let _ = Box::from_raw(opaque as *mut RefCell); + } + } } } } diff --git a/oden-js/src/value.rs b/oden-js/src/value.rs index 628f588a..90257483 100644 --- a/oden-js/src/value.rs +++ b/oden-js/src/value.rs @@ -2,7 +2,6 @@ use crate::{AtomRef, ContextRef, Error, Result, Runtime, RustFunction}; use oden_js_sys as sys; use std::ffi::CStr; use std::fmt; -use std::marker; use std::ops::{Deref, DerefMut}; #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -52,29 +51,13 @@ impl From for ValueType { /// you will want to create and manipulate `Value`, but you will occasionally /// receive `ValueRef` in calls that originate from JavaScript /// code. (`ValueRef` is to `Value` as `str` is to `String`, if that helps.) -pub struct ValueRef<'r> { +pub struct ValueRef { pub(crate) val: sys::JSValue, - _phantom: marker::PhantomData<&'r Runtime>, } -// pub type Callback<'r, 'ctx> = fn( -// ctx: &'ctx Context<'r>, -// this_val: &ValueRef<'r, 'ctx>, -// argc: usize, -// argvc: &[&ValueRef<'r, 'ctx>], -// ) -> Value<'r, 'ctx>; - -impl<'r> ValueRef<'r> { - /// Wrap a value in a specific context. - /// - /// **WARNING**: The specified value *must* be associated with at least - /// the runtime of the specified context, if not the context itself. This - /// function makes no attempt to validate this. - pub fn from_raw(val: sys::JSValue, _ctx: &ContextRef<'r>) -> Self { - ValueRef { - val, - _phantom: marker::PhantomData, - } +impl ValueRef { + pub fn from_raw(val: sys::JSValue) -> Self { + ValueRef { val } } /// Get the type of JavaScript value that this is. @@ -137,7 +120,7 @@ impl<'r> ValueRef<'r> { self.value_type() == ValueType::Int } - pub fn to_i32(&self, ctx: &ContextRef<'r>) -> Result<'r, i32> { + pub fn to_i32(&self, ctx: &ContextRef) -> Result { unsafe { let mut res: i32 = 0; let ret = sys::JS_ToInt32(ctx.ctx, &mut res, self.val); @@ -149,7 +132,7 @@ impl<'r> ValueRef<'r> { } } - pub fn to_u32(&self, ctx: &ContextRef<'r>) -> Result<'r, u32> { + pub fn to_u32(&self, ctx: &ContextRef) -> Result { unsafe { let mut res: u32 = 0; let ret = sys::JS_ToUint32(ctx.ctx, &mut res, self.val); @@ -161,7 +144,7 @@ impl<'r> ValueRef<'r> { } } - pub fn to_i64(&self, ctx: &ContextRef<'r>) -> Result<'r, i64> { + pub fn to_i64(&self, ctx: &ContextRef) -> Result { unsafe { let mut res: i64 = 0; let ret = sys::JS_ToInt64(ctx.ctx, &mut res, self.val); @@ -180,7 +163,7 @@ impl<'r> ValueRef<'r> { self.value_type() == ValueType::Bool } - pub fn to_bool(&self) -> Result<'r, bool> { + pub fn to_bool(&self) -> Result { if self.value_type() == ValueType::Bool { Ok(unsafe { self.val.u.int32 } > 0) } else { @@ -201,7 +184,7 @@ impl<'r> ValueRef<'r> { self.value_type() == ValueType::Float64 } - pub fn to_float64(&self, ctx: &ContextRef<'r>) -> Result<'r, f64> { + pub fn to_float64(&self, ctx: &ContextRef) -> Result { unsafe { let mut res: f64 = 0.0; let ret = sys::JS_ToFloat64(ctx.ctx, &mut res, self.val); @@ -216,7 +199,7 @@ impl<'r> ValueRef<'r> { /// Take a reference to this value so that it outlives this current reference. /// /// (This is a very cheap operation: at most it increments a reference count.) - pub fn dup(&self, ctx: &ContextRef<'r>) -> Value<'r> { + pub fn dup(&self, ctx: &ContextRef) -> Value { unsafe { sys::JS_DupValue(ctx.ctx, self.val); } @@ -229,7 +212,7 @@ impl<'r> ValueRef<'r> { /// /// JavsScript exceptions are are returned as values where `value_type` /// is `ValueType::Exception`. - pub fn eval_function(&self, ctx: &ContextRef<'r>) -> Result<'r, Value<'r>> { + pub fn eval_function(&self, ctx: &ContextRef) -> Result { match self.value_type() { ValueType::Module | ValueType::FunctionBytecode => (), found => { @@ -249,25 +232,16 @@ impl<'r> ValueRef<'r> { Ok(Value::from_raw(result, ctx)) } - pub fn get_property(&self, ctx: &ContextRef<'r>, prop: &str) -> Result<'r, Value<'r>> { + pub fn get_property(&self, ctx: &ContextRef, prop: &str) -> Result { let atom = ctx.new_atom(prop)?; self.get_property_atom(ctx, &atom) } - pub fn get_property_atom( - &self, - ctx: &ContextRef<'r>, - prop: &AtomRef<'r>, - ) -> Result<'r, Value<'r>> { + pub fn get_property_atom(&self, ctx: &ContextRef, prop: &AtomRef) -> Result { ctx.check_exception(unsafe { sys::JS_GetProperty(ctx.ctx, self.val, prop.atom) }) } - pub fn set_property( - &mut self, - ctx: &ContextRef<'r>, - prop: &str, - val: &ValueRef, - ) -> Result<'r, ()> { + pub fn set_property(&mut self, ctx: &ContextRef, prop: &str, val: &ValueRef) -> Result<()> { // TODO: Consume API let atom = ctx.new_atom(prop)?; self.set_property_atom(ctx, &atom, val) @@ -275,10 +249,10 @@ impl<'r> ValueRef<'r> { pub fn set_property_atom( &mut self, - ctx: &ContextRef<'r>, - prop: &AtomRef<'r>, + ctx: &ContextRef, + prop: &AtomRef, val: &ValueRef, - ) -> Result<'r, ()> { + ) -> Result<()> { unsafe { sys::JS_DupValue(ctx.ctx, val.val); let result = sys::JS_SetProperty(ctx.ctx, self.val, prop.atom, val.val); @@ -292,29 +266,24 @@ impl<'r> ValueRef<'r> { pub fn set_fn( &mut self, - ctx: &ContextRef<'r>, + ctx: &ContextRef, prop: &str, - func: impl RustFunction<'r, F>, - ) -> Result<'r, ()> { - let vr: Value<'r> = ctx.new_fn(func)?; + func: impl RustFunction, + ) -> Result<()> { + let vr: Value = ctx.new_fn(func)?; self.set_property(ctx, prop, &vr) } - pub fn set_dynamic_method( - &mut self, - ctx: &ContextRef<'r>, - prop: &str, - func: F, - ) -> Result<'r, ()> + pub fn set_dynamic_method(&mut self, ctx: &ContextRef, prop: &str, func: F) -> Result<()> where - F: Fn(&ContextRef<'r>, &ValueRef<'r>, &[&ValueRef<'r>]) -> Result<'r, Value<'r>>, + F: Fn(&ContextRef, &ValueRef, &[&ValueRef]) -> Result, { - let vr: Value<'r> = ctx.new_dynamic_fn(func)?; + let vr: Value = ctx.new_dynamic_fn(func)?; self.set_property(ctx, prop, &vr) } /// Convert this value into a string representation of the same value. - pub fn to_string(&self, ctx: &ContextRef<'r>) -> Result<'r, String> { + pub fn to_string(&self, ctx: &ContextRef) -> Result { // SAFETY: ctx's life is bound by the lifetime of our Context, and // sys::JS_ToCStringLen2 will return non-null, unless we're out of // memory. @@ -342,7 +311,7 @@ impl<'r> ValueRef<'r> { } } -impl<'ctx> fmt::Debug for ValueRef<'ctx> { +impl<'ctx> fmt::Debug for ValueRef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Value") .field("v", &self.val) @@ -352,50 +321,48 @@ impl<'ctx> fmt::Debug for ValueRef<'ctx> { /// An owned Value from JavaScript. Unlike ValueRef, this type stands in for /// values that you construct in Rust code; otherwise they are identical. -pub struct Value<'r> { - value: ValueRef<'r>, - rt: *mut sys::JSRuntime, - _phantom: marker::PhantomData<&'r Runtime>, +pub struct Value { + value: ValueRef, + rt: Runtime, } -impl<'r> Value<'r> { +impl Value { /// Take ownership of a value in a specific context. /// /// **WARNING**: The specified value *must* be associated with at least /// the runtime of the specified context, if not the context itself. This /// function makes no attempt to validate this. - pub(crate) fn from_raw(val: sys::JSValue, ctx: &ContextRef<'r>) -> Self { + pub(crate) fn from_raw(val: sys::JSValue, ctx: &ContextRef) -> Self { Value { - value: ValueRef::from_raw(val, ctx), - rt: unsafe { sys::JS_GetRuntime(ctx.ctx) }, - _phantom: marker::PhantomData, + value: ValueRef::from_raw(val), + rt: Runtime::from_raw(unsafe { sys::JS_GetRuntime(ctx.ctx) }), } } } -impl<'r> Deref for Value<'r> { - type Target = ValueRef<'r>; +impl Deref for Value { + type Target = ValueRef; fn deref(&self) -> &Self::Target { &self.value } } -impl<'r> DerefMut for Value<'r> { +impl DerefMut for Value { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.value } } -impl<'r> Drop for Value<'r> { +impl Drop for Value { fn drop(&mut self) { unsafe { - sys::JS_FreeValueRT(self.rt, self.val); + sys::JS_FreeValueRT(self.rt.rt, self.val); } } } -impl<'r> fmt::Debug for Value<'r> { +impl fmt::Debug for Value { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.value.fmt(f) } @@ -409,7 +376,7 @@ mod tests { #[test] fn value_type() { let rt = Runtime::new(); - let mut ctx = Context::new(&rt); + let mut ctx = Context::new(rt); ctx.add_intrinsic_bigfloat(); ctx.add_intrinsic_bigdecimal(); @@ -436,36 +403,3 @@ mod tests { } } } - -/// NOTE: We can happily create and return values, like this: -/// ``` -/// use oden_js::*; -/// fn my_test<'a>(ctx: &'a Context<'a>) -> Value<'a> { -/// ctx.new_i32(123).unwrap() -/// } -/// ``` -/// -/// But our lifetime bounds on values keep them from outliving their runtimes: -/// -/// ```compile_fail -/// use oden_js::*; -/// fn my_test<'r>() -> oden_js::Value<'r> { -/// let rt = Runtime::new(); -/// let ctx = Context::new(&rt); -/// -/// ctx.new_i32(123).unwrap() -/// } -/// ``` -/// -/// Contexts are fundamentally transient, though: -/// -/// ``` -/// use oden_js::*; -/// fn my_test<'r>(runtime: &'r Runtime) -> sheetland_js::Value<'r> { -/// let ctx = Context::new(runtime); -/// -/// ctx.new_i32(123).unwrap() -/// } -/// ``` -#[cfg(doctest)] -pub struct ValuesObeyLifetimes {}