Compare commits
2 Commits
main
...
kv/task-re
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6e89485b8e | ||
|
|
8943d4621f |
@ -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!() }
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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();
|
||||
}
|
||||
})
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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)?;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user