Skip to content

Commit

Permalink
Overhaul promises
Browse files Browse the repository at this point in the history
  • Loading branch information
DelSkayn committed Apr 20, 2024
1 parent 6ec023a commit e54406d
Show file tree
Hide file tree
Showing 16 changed files with 319 additions and 307 deletions.
2 changes: 1 addition & 1 deletion core/src/allocator/rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ unsafe impl Allocator for RustAllocator {
header.size = size;
}

unsafe { ptr.add(HEADER_SIZE) }
unsafe { dbg!(ptr.add(HEADER_SIZE)) }
}

#[allow(clippy::not_unsafe_ptr_arg_deref)]
Expand Down
74 changes: 57 additions & 17 deletions core/src/context/ctx.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::{
ffi::{CStr, CString},
fs, mem,
fs,
mem::{self, MaybeUninit},
path::Path,
ptr::NonNull,
};
Expand All @@ -12,7 +13,7 @@ use std::future::Future;
use crate::AsyncContext;
use crate::{
markers::Invariant, qjs, runtime::raw::Opaque, Context, Error, FromJs, Function, IntoJs,
Module, Object, Result, String, Value,
Module, Object, Promise, Result, String, Value,
};

/// Eval options.
Expand Down Expand Up @@ -127,6 +128,7 @@ impl<'js> Ctx<'js> {
file_name.as_ptr(),
flag,
);
dbg!(qjs::JS_VALUE_GET_PTR(val));
self.handle_exception(val)
}

Expand Down Expand Up @@ -344,24 +346,35 @@ impl<'js> Ctx<'js> {
}
}

// Creates promise and resolving functions.
pub fn promise(&self) -> Result<(Object<'js>, Function<'js>, Function<'js>)> {
/// Creates javascipt promise along with its reject and resolve functions.
pub fn promise(&self) -> Result<(Promise<'js>, Function<'js>, Function<'js>)> {
let mut funcs = mem::MaybeUninit::<(qjs::JSValue, qjs::JSValue)>::uninit();

Ok(unsafe {
let promise = self.handle_exception(qjs::JS_NewPromiseCapability(
self.ctx.as_ptr(),
funcs.as_mut_ptr() as _,
))?;
let (then, catch) = funcs.assume_init();
let (resolve, reject) = funcs.assume_init();
(
Object::from_js_value(self.clone(), promise),
Function::from_js_value(self.clone(), then),
Function::from_js_value(self.clone(), catch),
Promise::from_js_value(self.clone(), promise),
Function::from_js_value(self.clone(), resolve),
Function::from_js_value(self.clone(), reject),
)
})
}

/// Executes a quickjs job.
///
/// Returns wether a job was actually executed.
/// If this function returned false, no job was pending.
pub fn execute_pending_job(&self) -> bool {
let mut ptr = MaybeUninit::<*mut qjs::JSContext>::uninit();
let rt = unsafe { qjs::JS_GetRuntime(self.ctx.as_ptr()) };
let res = unsafe { qjs::JS_ExecutePendingJob(rt, ptr.as_mut_ptr()) };
res != 0
}

pub(crate) unsafe fn get_opaque(&self) -> *mut Opaque<'js> {
let rt = qjs::JS_GetRuntime(self.ctx.as_ptr());
qjs::JS_GetRuntimeOpaque(rt).cast::<Opaque>()
Expand Down Expand Up @@ -407,18 +420,20 @@ impl<'js> Ctx<'js> {
self.ctx
}

/// Frees modules which aren't evaluated.
///
/// When a module is compiled and the compilation results in an error the module can already
/// have resolved several modules. Originally QuickJS freed all these module when compiling
/// (but not when a it was dynamically imported), this library patched that behavior out
/// because it proved to be hard to make safe. This function will free those modules.
///
/// # Safety
/// Caller must ensure that this method is not called from a module being evaluated.
/*
// Frees modules which aren't evaluated.
//
// When a module is compiled and the compilation results in an error the module can already
// have resolved several modules. Originally QuickJS freed all these module when compiling
// (but not when a it was dynamically imported), this library patched that behavior out
// because it proved to be hard to make safe. This function will free those modules.
//
// # Safety
// Caller must ensure that this method is not called from a module being evaluated.
pub unsafe fn free_unevaluated_modules(&self) {
qjs::JS_FreeUnevaluatedModules(self.ctx.as_ptr())
}
*/
}

#[cfg(test)]
Expand All @@ -440,6 +455,19 @@ mod test {
});
}

#[test]
fn compile_minimal_test() {
use crate::{Context, Runtime};

let runtime = Runtime::new().unwrap();
let ctx = Context::full(&runtime).unwrap();
ctx.with(|ctx| {
let module = ctx.compile("test", "export let foo = 1 + 1;").unwrap();
let v: i32 = module.get("foo").unwrap();
assert_eq!(v, 2)
})
}

#[test]
fn eval() {
use crate::{Context, Runtime};
Expand All @@ -464,6 +492,18 @@ mod test {
})
}

#[test]
fn eval_minimal_test() {
use crate::{Context, Runtime};

let runtime = Runtime::new().unwrap();
let ctx = Context::full(&runtime).unwrap();
ctx.with(|ctx| {
let res: i32 = ctx.eval(" 1 + 1 ").unwrap();
assert_eq!(2, res);
})
}

#[test]
#[should_panic(expected = "'foo' is not defined")]
fn eval_with_sloppy_code() {
Expand Down
10 changes: 3 additions & 7 deletions core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ mod persistent;
mod value;
pub use persistent::{Outlive, Persistent};
pub use value::{
array, atom, convert, function, module, object, Array, Atom, BigInt, Coerced, Exception,
Filter, FromAtom, FromIteratorJs, FromJs, Function, IntoAtom, IntoJs, IteratorJs, Module, Null,
Object, String, Symbol, Type, Undefined, Value,
array, atom, convert, function, module, object, promise, Array, Atom, BigInt, Coerced,
Exception, Filter, FromAtom, FromIteratorJs, FromJs, Function, IntoAtom, IntoJs, IteratorJs,
Module, Null, Object, Promise, String, Symbol, Type, Undefined, Value,
};

pub mod class;
Expand All @@ -73,10 +73,6 @@ pub use value::{ArrayBuffer, TypedArray};

pub(crate) use std::{result::Result as StdResult, string::String as StdString};

#[cfg(feature = "futures")]
#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "futures")))]
pub mod promise;

#[cfg(feature = "allocator")]
#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "allocator")))]
pub mod allocator;
Expand Down
Loading

0 comments on commit e54406d

Please sign in to comment.