Skip to content

Commit d78e648

Browse files
committed
use with promises
1 parent a5529b4 commit d78e648

4 files changed

Lines changed: 42 additions & 42 deletions

File tree

r/adbcdrivermanager/R/async.R

Lines changed: 21 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -27,23 +27,35 @@ adbc_async_task_status <- function(task) {
2727
.Call(RAdbcAsyncTaskWaitFor, task, 0)
2828
}
2929

30-
adbc_async_task_set_callback <- function(task, callback, loop = later::current_loop()) {
30+
adbc_async_task_set_callback <- function(task, resolve, reject = NULL,
31+
loop = later::current_loop()) {
3132
# If the task is completed, run the callback (or else the callback
3233
# will not run)
3334
if (adbc_async_task_status(task) == "ready") {
34-
result <- adbc_async_task_result(task)
35-
callback(result)
35+
adbc_async_task_run_callback(task, resolve, reject)
3636
} else {
37-
.Call(RAdbcAsyncTaskSetCallback, task, callback, loop$id)
37+
.Call(RAdbcAsyncTaskSetCallback, task, resolve, reject, loop$id)
3838
}
3939

4040
invisible(task)
4141
}
4242

43-
adbc_async_task_run_callback <- function(task) {
44-
callback <- task$callback
45-
result <- adbc_async_task_result(task)
46-
callback(result)
43+
adbc_async_task_run_callback <- function(task, resolve = task$resolve,
44+
reject = task$reject) {
45+
tryCatch({
46+
result <- adbc_async_task_result(task)
47+
resolve(result)
48+
},
49+
error = function(e) {
50+
if (is.null(reject)) {
51+
stop(e)
52+
} else {
53+
reject(e)
54+
}
55+
}
56+
)
57+
58+
invisible(task)
4759
}
4860

4961
adbc_async_task_wait_non_cancellable <- function(task, resolution = 0.05) {
@@ -63,36 +75,10 @@ adbc_async_task_wait <- function(task, resolution = 0.05) {
6375
adbc_async_task_result(task)
6476
}
6577

66-
later_loop_schedule_task_callback <- function(task, resolve, reject,
67-
loop = later::current_loop(),
68-
delay = 0) {
69-
force(task)
70-
force(resolve)
71-
force(reject)
72-
73-
later::later(function() {
74-
status <- adbc_async_task_status(task)
75-
if (status == "timeout") {
76-
later_loop_schedule_task_callback(
77-
task,
78-
resolve,
79-
reject,
80-
loop = loop,
81-
delay = delay
82-
)
83-
} else {
84-
tryCatch(
85-
resolve(adbc_async_task_result(task)),
86-
error = function(e) reject(e)
87-
)
88-
}
89-
}, delay = delay, loop = loop)
90-
}
91-
9278
as.promise.adbc_async_task <- function(task) {
9379
force(task)
9480
promises::promise(function(resolve, reject) {
95-
later_loop_schedule_task_callback(task, resolve, reject)
81+
adbc_async_task_set_callback(task, resolve, reject)
9682
})
9783
}
9884

r/adbcdrivermanager/src/async.cc

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,8 @@ static void error_for_started_task(RAdbcAsyncTask* task) {
9999
}
100100

101101
extern "C" SEXP RAdbcAsyncTaskNew(SEXP error_xptr) {
102-
const char* names[] = {"error_xptr", "return_code", "user_data", "callback", ""};
102+
const char* names[] = {"error_xptr", "return_code", "user_data",
103+
"resolve", "reject", ""};
103104
SEXP task_prot = PROTECT(Rf_mkNamed(VECSXP, names));
104105

105106
SET_VECTOR_ELT(task_prot, 0, error_xptr);
@@ -125,13 +126,14 @@ extern "C" SEXP RAdbcAsyncTaskNew(SEXP error_xptr) {
125126
return task_xptr;
126127
}
127128

128-
extern "C" SEXP RAdbcAsyncTaskSetCallback(SEXP task_xptr, SEXP callback_sexp,
129-
SEXP loop_id_sexp) {
129+
extern "C" SEXP RAdbcAsyncTaskSetCallback(SEXP task_xptr, SEXP callback_resolve_sexp,
130+
SEXP callback_reject_sexp, SEXP loop_id_sexp) {
130131
auto task = adbc_from_xptr<RAdbcAsyncTask>(task_xptr);
131132
SEXP task_prot = R_ExternalPtrProtected(task_xptr);
132133
int loop_id = adbc_as_int(loop_id_sexp);
133134

134-
SET_VECTOR_ELT(task_prot, 3, callback_sexp);
135+
SET_VECTOR_ELT(task_prot, 3, callback_resolve_sexp);
136+
SET_VECTOR_ELT(task_prot, 4, callback_reject_sexp);
135137
task->SetCallback(task_xptr, loop_id);
136138
return R_NilValue;
137139
}

r/adbcdrivermanager/src/init.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121

2222
/* generated by tools/make-callentries.R */
2323
SEXP RAdbcAsyncTaskNew(SEXP error_xptr);
24-
SEXP RAdbcAsyncTaskSetCallback(SEXP task_xptr, SEXP callback_sexp, SEXP loop_id_sexp);
24+
SEXP RAdbcAsyncTaskSetCallback(SEXP task_xptr, SEXP callback_resolve_sexp,
25+
SEXP callback_reject_sexp, SEXP loop_id_sexp);
2526
SEXP RAdbcAsyncTaskData(SEXP task_xptr);
2627
SEXP RAdbcAsyncTaskWaitFor(SEXP task_xptr, SEXP duration_ms_sexp);
2728
SEXP RAdbcAsyncTaskLaunchSleep(SEXP task_xptr, SEXP duration_ms_sexp);
@@ -111,7 +112,7 @@ SEXP RAdbcXptrSetProtected(SEXP xptr, SEXP prot);
111112

112113
static const R_CallMethodDef CallEntries[] = {
113114
{"RAdbcAsyncTaskNew", (DL_FUNC)&RAdbcAsyncTaskNew, 1},
114-
{"RAdbcAsyncTaskSetCallback", (DL_FUNC)&RAdbcAsyncTaskSetCallback, 3},
115+
{"RAdbcAsyncTaskSetCallback", (DL_FUNC)&RAdbcAsyncTaskSetCallback, 4},
115116
{"RAdbcAsyncTaskData", (DL_FUNC)&RAdbcAsyncTaskData, 1},
116117
{"RAdbcAsyncTaskWaitFor", (DL_FUNC)&RAdbcAsyncTaskWaitFor, 2},
117118
{"RAdbcAsyncTaskLaunchSleep", (DL_FUNC)&RAdbcAsyncTaskLaunchSleep, 2},

r/adbcdrivermanager/tests/testthat/test-async.R

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ test_that("async tasks can be created and inspected", {
2222

2323
expect_identical(
2424
names(task),
25-
c("error_xptr", "return_code", "user_data", "callback")
25+
c("error_xptr", "return_code", "user_data", "resolve", "reject")
2626
)
2727

2828
expect_s3_class(task$error_xptr, "adbc_error")
@@ -90,6 +90,17 @@ test_that("async tasks can set an R callback", {
9090
adbc_async_task_set_callback(sleep_task, function(x) { async_called <<- TRUE })
9191
Sys.sleep(0.1)
9292
expect_true(async_called)
93+
94+
# Ensure this also works on error
95+
async_called <- FALSE
96+
sleep_task <- adbc_async_sleep(0, error_message = "some error")
97+
adbc_async_task_set_callback(
98+
sleep_task,
99+
resolve = function(x) NULL,
100+
reject = function(x) { async_called <<- TRUE }
101+
)
102+
Sys.sleep(0.1)
103+
expect_true(async_called)
93104
})
94105

95106
test_that("async task can be converted to a promise", {

0 commit comments

Comments
 (0)