Skip to content

Commit 56c88a8

Browse files
authored
Support async methods in object wrap (#1013)
```rust impl TestObjectWrap { #[async_method] async fn with_async_fn(&self) { // ... } } ```
1 parent 18d4ed3 commit 56c88a8

File tree

8 files changed

+77
-16
lines changed

8 files changed

+77
-16
lines changed

core/00_infra.js

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -190,8 +190,9 @@
190190
};
191191
}
192192

193-
function setUpAsyncStub(opName, originalOp) {
193+
function setUpAsyncStub(opName, originalOp, maybeProto) {
194194
let fn;
195+
195196
// The body of this switch statement can be generated using the script above.
196197
switch (originalOp.length - 1) {
197198
/* BEGIN TEMPLATE setUpAsyncStub */
@@ -200,7 +201,8 @@
200201
fn = function async_op_0() {
201202
const id = nextPromiseId;
202203
try {
203-
const maybeResult = originalOp(id);
204+
// deno-fmt-ignore
205+
const maybeResult = originalOp.call(this, id);
204206
if (maybeResult !== undefined) {
205207
return PromiseResolve(maybeResult);
206208
}
@@ -219,7 +221,8 @@
219221
fn = function async_op_1(a) {
220222
const id = nextPromiseId;
221223
try {
222-
const maybeResult = originalOp(id, a);
224+
// deno-fmt-ignore
225+
const maybeResult = originalOp.call(this, id, a);
223226
if (maybeResult !== undefined) {
224227
return PromiseResolve(maybeResult);
225228
}
@@ -238,7 +241,8 @@
238241
fn = function async_op_2(a, b) {
239242
const id = nextPromiseId;
240243
try {
241-
const maybeResult = originalOp(id, a, b);
244+
// deno-fmt-ignore
245+
const maybeResult = originalOp.call(this, id, a, b);
242246
if (maybeResult !== undefined) {
243247
return PromiseResolve(maybeResult);
244248
}
@@ -257,7 +261,8 @@
257261
fn = function async_op_3(a, b, c) {
258262
const id = nextPromiseId;
259263
try {
260-
const maybeResult = originalOp(id, a, b, c);
264+
// deno-fmt-ignore
265+
const maybeResult = originalOp.call(this, id, a, b, c);
261266
if (maybeResult !== undefined) {
262267
return PromiseResolve(maybeResult);
263268
}
@@ -276,7 +281,8 @@
276281
fn = function async_op_4(a, b, c, d) {
277282
const id = nextPromiseId;
278283
try {
279-
const maybeResult = originalOp(id, a, b, c, d);
284+
// deno-fmt-ignore
285+
const maybeResult = originalOp.call(this, id, a, b, c, d);
280286
if (maybeResult !== undefined) {
281287
return PromiseResolve(maybeResult);
282288
}
@@ -295,7 +301,8 @@
295301
fn = function async_op_5(a, b, c, d, e) {
296302
const id = nextPromiseId;
297303
try {
298-
const maybeResult = originalOp(id, a, b, c, d, e);
304+
// deno-fmt-ignore
305+
const maybeResult = originalOp.call(this, id, a, b, c, d, e);
299306
if (maybeResult !== undefined) {
300307
return PromiseResolve(maybeResult);
301308
}
@@ -314,7 +321,8 @@
314321
fn = function async_op_6(a, b, c, d, e, f) {
315322
const id = nextPromiseId;
316323
try {
317-
const maybeResult = originalOp(id, a, b, c, d, e, f);
324+
// deno-fmt-ignore
325+
const maybeResult = originalOp.call(this, id, a, b, c, d, e, f);
318326
if (maybeResult !== undefined) {
319327
return PromiseResolve(maybeResult);
320328
}
@@ -333,7 +341,8 @@
333341
fn = function async_op_7(a, b, c, d, e, f, g) {
334342
const id = nextPromiseId;
335343
try {
336-
const maybeResult = originalOp(id, a, b, c, d, e, f, g);
344+
// deno-fmt-ignore
345+
const maybeResult = originalOp.call(this, id, a, b, c, d, e, f, g);
337346
if (maybeResult !== undefined) {
338347
return PromiseResolve(maybeResult);
339348
}
@@ -352,7 +361,8 @@
352361
fn = function async_op_8(a, b, c, d, e, f, g, h) {
353362
const id = nextPromiseId;
354363
try {
355-
const maybeResult = originalOp(id, a, b, c, d, e, f, g, h);
364+
// deno-fmt-ignore
365+
const maybeResult = originalOp.call(this, id, a, b, c, d, e, f, g, h);
356366
if (maybeResult !== undefined) {
357367
return PromiseResolve(maybeResult);
358368
}
@@ -371,7 +381,8 @@
371381
fn = function async_op_9(a, b, c, d, e, f, g, h, i) {
372382
const id = nextPromiseId;
373383
try {
374-
const maybeResult = originalOp(id, a, b, c, d, e, f, g, h, i);
384+
// deno-fmt-ignore
385+
const maybeResult = originalOp.call(this, id, a, b, c, d, e, f, g, h, i);
375386
if (maybeResult !== undefined) {
376387
return PromiseResolve(maybeResult);
377388
}
@@ -400,6 +411,16 @@
400411
configurable: false,
401412
writable: false,
402413
});
414+
415+
if (maybeProto) {
416+
ObjectDefineProperty(fn, "prototype", {
417+
value: maybeProto.prototype,
418+
configurable: false,
419+
writable: false,
420+
});
421+
maybeProto.prototype[opName] = fn;
422+
}
423+
403424
return fn;
404425
}
405426

core/rebuild_async_stubs.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ const doNotModify =
88
function __TEMPLATE__(__ARGS_PARAM__) {
99
const id = nextPromiseId;
1010
try {
11-
const maybeResult = __OP__(__ARGS__);
11+
// deno-fmt-ignore
12+
const maybeResult = __OP__.call(this, __ARGS__);
1213
if (maybeResult !== undefined) {
1314
return PromiseResolve(maybeResult);
1415
}

core/runtime/bindings.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,14 @@ pub(crate) fn initialize_deno_core_ops_bindings<'s>(
374374
let accessor_store = create_accessor_store(method_ctxs);
375375

376376
for method in method_ctxs.iter() {
377-
op_ctx_template_or_accessor(&accessor_store, scope, prototype, method);
377+
op_ctx_template_or_accessor(
378+
&accessor_store,
379+
set_up_async_stub_fn,
380+
scope,
381+
prototype,
382+
tmpl,
383+
method,
384+
);
378385
}
379386

380387
index += decl.methods.len();
@@ -419,13 +426,31 @@ pub(crate) fn initialize_deno_core_ops_bindings<'s>(
419426

420427
fn op_ctx_template_or_accessor<'s>(
421428
accessor_store: &AccessorStore,
429+
set_up_async_stub_fn: v8::Local<v8::Function>,
422430
scope: &mut v8::HandleScope<'s>,
423431
tmpl: v8::Local<'s, v8::ObjectTemplate>,
432+
constructor: v8::Local<'s, v8::FunctionTemplate>,
424433
op_ctx: &OpCtx,
425434
) {
426435
if !op_ctx.decl.is_accessor() {
427436
let op_fn = op_ctx_template(scope, op_ctx);
428437
let method_key = op_ctx.decl.name_fast.v8_string(scope).unwrap();
438+
if op_ctx.decl.is_async {
439+
let undefined = v8::undefined(scope);
440+
let op_fn = op_fn.get_function(scope).unwrap();
441+
442+
let tmpl_fn = constructor.get_function(scope).unwrap();
443+
444+
let _result = set_up_async_stub_fn
445+
.call(
446+
scope,
447+
undefined.into(),
448+
&[method_key.into(), op_fn.into(), tmpl_fn.into()],
449+
)
450+
.unwrap();
451+
452+
return;
453+
}
429454

430455
tmpl.set(method_key.into(), op_fn.into());
431456

ops/op2/config.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ impl MacroConfig {
109109
.collect::<Vec<_>>();
110110
} else if flag == "nofast" {
111111
config.nofast = true;
112-
} else if flag == "async" {
112+
} else if flag == "async" || flag == "async_method" {
113113
config.r#async = true;
114114
} else if flag == "async(lazy)" {
115115
config.r#async = true;

ops/op2/signature.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1259,6 +1259,8 @@ fn parse_attribute(
12591259
(#[getter]) => Some(AttributeModifier::Ignore),
12601260
(#[setter]) => Some(AttributeModifier::Ignore),
12611261
(#[fast]) => Some(AttributeModifier::Ignore),
1262+
// async is a keyword and does not work as #[async] so we use #[async_method] instead
1263+
(#[async_method]) => Some(AttributeModifier::Ignore),
12621264
(#[static_method]) => Some(AttributeModifier::Ignore),
12631265
(#[constructor]) => Some(AttributeModifier::Ignore),
12641266
(#[allow ($_rule:path)]) => None,

testing/checkin/runner/ops.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,12 @@ impl TestObjectWrap {
9494
#[fast]
9595
#[rename("with_RENAME")]
9696
fn with_rename(&self) {}
97+
98+
#[async_method]
99+
async fn with_async_fn(&self, #[smi] ms: u32) -> Result<(), AnyError> {
100+
tokio::time::sleep(std::time::Duration::from_millis(ms as u64)).await;
101+
Ok(())
102+
}
97103
}
98104

99105
pub struct DOMPoint {

testing/ops.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,5 @@ export class TestObjectWrap {
3939
constructor();
4040
withVarargs(...args: any[]): number;
4141
with_RENAME(): void;
42+
withAsyncFn(ms: number): Promise<void>;
4243
}

testing/unit/resource_test.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,9 @@ test(async function testCppgcAsync() {
6464
assertEquals(await op_async_get_cppgc_resource(resource), 42);
6565
});
6666

67-
test(function testDomPoint() {
68-
const p2 = new DOMPoint();
67+
test(async function testDomPoint() {
6968
const p1 = new DOMPoint(100, 100);
69+
const p2 = new DOMPoint();
7070
const p3 = DOMPoint.fromPoint({ x: 200 });
7171
const p4 = DOMPoint.fromPoint({ x: 0, y: 100, z: 99.9, w: 100 });
7272
const p5 = p1.fromPoint({ x: 200 });
@@ -102,4 +102,9 @@ test(function testDomPoint() {
102102
assertEquals(wrap.withVarargs(undefined), 1);
103103

104104
wrap.with_RENAME();
105+
106+
const promise = wrap.withAsyncFn(10);
107+
assert(promise instanceof Promise);
108+
109+
await promise;
105110
});

0 commit comments

Comments
 (0)