Compare commits

...

2 Commits

Author SHA1 Message Date
K.J. Valencik
6e89485b8e
Remove ok wrapped JsUndefined 2020-06-19 14:11:05 -04:00
K.J. Valencik
8943d4621f
(wip) TaskBuilder 2020-06-15 11:19:04 -04:00
9 changed files with 117 additions and 23 deletions

View File

@ -3,5 +3,5 @@ use std::os::raw::c_void;
pub unsafe extern "C" fn schedule(_task: *mut c_void,
_perform: unsafe extern fn(*mut c_void) -> *mut c_void,
_complete: unsafe extern fn(*mut c_void, *mut c_void, &mut Local),
_complete: unsafe extern fn(*mut c_void, &mut Local),
_callback: Local) { unimplemented!() }

View File

@ -130,7 +130,7 @@ extern "C" {
bool Neon_Mem_SameHandle(v8::Local<v8::Value> v1, v8::Local<v8::Value> v2);
typedef void* (*Neon_TaskPerformCallback)(void *);
typedef void (*Neon_TaskCompleteCallback)(void *, void *, v8::Local<v8::Value> *out);
typedef void (*Neon_TaskCompleteCallback)(void *, v8::Local<v8::Value> *out);
void Neon_Task_Schedule(void *task, Neon_TaskPerformCallback perform, Neon_TaskCompleteCallback complete, v8::Local<v8::Function> callback);

View File

@ -62,7 +62,7 @@ public:
v8::Local<v8::Value> completion;
complete_(rust_task_, result_, &completion);
complete_(result_, &completion);
if (trycatch.HasCaught()) {
argv[0] = trycatch.Exception();

View File

@ -195,7 +195,7 @@ extern "C" {
pub fn Neon_Task_Schedule(task: *mut c_void,
perform: unsafe extern fn(*mut c_void) -> *mut c_void,
complete: unsafe extern fn(*mut c_void, *mut c_void, &mut Local),
complete: unsafe extern fn(*mut c_void, &mut Local),
callback: Local);
pub fn Neon_EventHandler_New(isolate: Isolate, this: Local, callback: Local) -> *mut c_void;

View File

@ -19,6 +19,7 @@ use types::error::JsError;
use object::{Object, This};
use object::class::Class;
use result::{NeonResult, JsResult, Throw};
use task::TaskBuilder;
use self::internal::{ContextInternal, Scope, ScopeMetadata};
#[repr(C)]
@ -335,6 +336,15 @@ pub trait Context<'a>: ContextInternal<'a> {
let err = JsError::range_error(self, msg)?;
self.throw(err)
}
fn task<Perform, Complete, Output>(&mut self, perform: Perform) -> TaskBuilder<Self, Perform>
where
Perform: FnOnce() -> Complete + Send + 'static,
Complete: FnOnce(TaskContext) -> JsResult<Output> + Send + 'static,
Output: Value,
{
TaskBuilder::new(self, perform)
}
}
/// A view of the JS engine in the context of top-level initialization of a Neon module.

View File

@ -1,13 +1,12 @@
//! Asynchronous background _tasks_ that run in the Node thread pool.
use std::marker::{Send, Sized};
use std::mem;
use std::os::raw::c_void;
use types::{Value, JsFunction};
use result::JsResult;
use handle::{Handle, Managed};
use context::TaskContext;
use context::{Context, TaskContext};
use neon_runtime;
use neon_runtime::raw;
@ -36,30 +35,88 @@ pub trait Task: Send + Sized + 'static {
/// function callback(err, value) {}
/// ```
fn schedule(self, callback: Handle<JsFunction>) {
let boxed_self = Box::new(self);
let self_raw = Box::into_raw(boxed_self);
let callback_raw = callback.to_raw();
unsafe {
neon_runtime::task::schedule(mem::transmute(self_raw),
perform_task::<Self>,
complete_task::<Self>,
callback_raw);
schedule(move || {
let result = self.perform();
move |cx| self.complete(cx, result)
}, callback);
}
}
pub struct TaskBuilder<'c, C, Perform> {
// Placeholder for future methods and N-API implementation
_context: &'c mut C,
perform: Perform,
}
impl<'c, C, Perform> TaskBuilder<'c, C, Perform> {
pub(crate) fn new(context: &'c mut C, perform: Perform) -> Self {
TaskBuilder {
_context: context,
perform,
}
}
}
unsafe extern "C" fn perform_task<T: Task>(task: *mut c_void) -> *mut c_void {
let task: Box<T> = Box::from_raw(mem::transmute(task));
let result = task.perform();
Box::into_raw(task);
mem::transmute(Box::into_raw(Box::new(result)))
impl<'a, 'c, C, Perform, Complete, Output> TaskBuilder<'c, C, Perform>
where
C: Context<'a>,
Perform: FnOnce() -> Complete + Send + 'static,
Complete: FnOnce(TaskContext) -> JsResult<Output> + Send + 'static,
Output: Value,
{
pub fn schedule(self, callback: Handle<JsFunction>) {
let Self { perform, .. } = self;
schedule(perform, callback);
}
}
unsafe extern "C" fn complete_task<T: Task>(task: *mut c_void, result: *mut c_void, out: &mut raw::Local) {
let result: Result<T::Output, T::Error> = *Box::from_raw(mem::transmute(result));
let task: Box<T> = Box::from_raw(mem::transmute(task));
fn schedule<Perform, Complete, Output>(
perform: Perform,
callback: Handle<JsFunction>,
)
where
Perform: FnOnce() -> Complete + Send + 'static,
Complete: FnOnce(TaskContext) -> JsResult<Output> + Send + 'static,
Output: Value,
{
let data = Box::into_raw(Box::new(perform));
unsafe {
neon_runtime::task::schedule(
data as *mut _,
perform_task::<Perform, Complete>,
complete_task::<Complete, Output>,
callback.to_raw(),
);
}
}
unsafe extern "C" fn perform_task<Perform, Output>(
perform: *mut c_void,
) -> *mut c_void
where
Perform: FnOnce() -> Output,
{
let perform = Box::from_raw(perform as *mut Perform);
let result = perform();
Box::into_raw(Box::new(result)) as *mut _
}
unsafe extern "C" fn complete_task<Complete, Output>(
complete: *mut c_void,
out: &mut raw::Local,
)
where
Complete: FnOnce(TaskContext) -> JsResult<Output>,
Output: Value,
{
let complete = *Box::from_raw(complete as *mut Complete);
TaskContext::with(|cx| {
if let Ok(result) = task.complete(cx, result) {
if let Ok(result) = complete(cx) {
*out = result.to_raw();
}
})

View File

@ -14,6 +14,18 @@ describe('Task', function() {
});
});
it('completes a successful closure task', function (done) {
addon.perform_closure_task(41, (err, n) => {
if (err) {
done(err);
} else if (n === 42) {
done();
} else {
done(new Error("not 42 but: " + n));
}
});
});
it('completes a failing task', function (done) {
addon.perform_failing_task((err, n) => {
if (err) {

View File

@ -22,6 +22,20 @@ pub fn perform_async_task(mut cx: FunctionContext) -> JsResult<JsUndefined> {
Ok(cx.undefined())
}
pub fn perform_closure_task(mut cx: FunctionContext) -> JsResult<JsUndefined> {
let n = cx.argument::<JsNumber>(0)?.value();
let cb = cx.argument::<JsFunction>(1)?;
cx.task(move || {
let result = n + 1.0;
move |mut cx| Ok(cx.number(result))
})
.schedule(cb);
Ok(cx.undefined())
}
struct FailureTask;
impl Task for FailureTask {

View File

@ -66,6 +66,7 @@ register_module!(mut cx, {
cx.export_function("check_string_and_number", check_string_and_number)?;
cx.export_function("perform_async_task", perform_async_task)?;
cx.export_function("perform_closure_task", perform_closure_task)?;
cx.export_function("perform_failing_task", perform_failing_task)?;
cx.export_function("panic", panic)?;