From 0184b1103b400f9f333784913f7b4dc5774f6bb0 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Mon, 18 Oct 2021 21:42:31 +0530 Subject: [PATCH] support non_blocking attribute for symbols --- codegen.ts | 15 +++++--- example/add_test.ts | 16 +++++++- example/bindings/bindings.ts | 72 ++++++++++++++++++++++++------------ example/src/lib.rs | 7 ++++ src/lib.rs | 24 ++++++++++-- 5 files changed, 100 insertions(+), 34 deletions(-) diff --git a/codegen.ts b/codegen.ts index c7effb3..96e7f4a 100644 --- a/codegen.ts +++ b/codegen.ts @@ -37,6 +37,7 @@ function resolveDlopenParameter(typeDefs: TypeDef, type: any): string { type Sig = Record; type Options = { @@ -70,12 +71,12 @@ const _lib = await Plug.prepare(opts, { return `"${ffiParam}"${typeof p !== "string" ? `, "usize"` : ""}`; }) .join(", ") - } ], result: "${signature[sig].result}" }` + } ], result: "${signature[sig].result}", nonblocking: ${ + String(!!signature[sig].nonBlocking) + } }` ).join(", ") } }); -${ - Object.keys(decl).map((def) => typescript[def]).join("\n") - } +${Object.keys(decl).map((def) => typescript[def]).join("\n")} ${ Object.keys(signature).map((sig) => `export function ${sig}(${ @@ -94,7 +95,11 @@ ${ signature[sig].parameters.map((p, i) => typeof p !== "string" ? `a${i}_buf, a${i}_buf.byteLength` : `a${i}` ).join(", ") - }) as ${resolveType(decl, signature[sig].result)} + }) as ${ + signature[sig].nonBlocking + ? `Promise<${resolveType(decl, signature[sig].result)}>` + : resolveType(decl, signature[sig].result) + } }` ).join("\n") } diff --git a/example/add_test.ts b/example/add_test.ts index ed3764a..aeb46c8 100644 --- a/example/add_test.ts +++ b/example/add_test.ts @@ -2,11 +2,12 @@ import { add, add2, OptionStruct, + sleep, test_mixed, test_mixed_order, test_serde, } from "./bindings/bindings.ts"; -import { assertEquals } from "https://deno.land/std/testing/asserts.ts"; +import { assert, assertEquals } from "https://deno.land/std/testing/asserts.ts"; Deno.test({ name: "add#test", @@ -45,10 +46,21 @@ Deno.test({ }); Deno.test({ - name: "test_options", + name: "test_options#test", fn: () => { let opts: OptionStruct = { maybe: " " }; opts.maybe = null; opts.maybe = undefined; }, }); + +Deno.test({ + name: "sleep#test", + fn: async () => { + const ms = 100; + const start = performance.now(); + const promise = sleep(ms).then(() => assert(start >= ms)); + assert(performance.now() - start < ms); + await promise; + }, +}); diff --git a/example/bindings/bindings.ts b/example/bindings/bindings.ts index c1e7389..eb87196 100644 --- a/example/bindings/bindings.ts +++ b/example/bindings/bindings.ts @@ -3,47 +3,71 @@ import { Plug } from "https://deno.land/x/plug@0.4.0/mod.ts"; const encode = (s: string) => new TextEncoder().encode(s); const opts = { name: "add", - url: "target/debug" + url: "target/debug", }; const _lib = await Plug.prepare(opts, { - add: { parameters: [ "i32", "i32" ], result: "i32" }, test_mixed: { parameters: [ "isize", "buffer", "usize" ], result: "i32" }, test_serde: { parameters: [ "buffer", "usize" ], result: "u8" }, add2: { parameters: [ "buffer", "usize" ], result: "i32" }, test_mixed_order: { parameters: [ "i32", "buffer", "usize", "i32" ], result: "i32" } }); -export type OptionStruct = { - maybe: string | undefined | null; + add: { parameters: ["i32", "i32"], result: "i32", nonblocking: false }, + sleep: { parameters: ["u64"], result: "void", nonblocking: true }, + test_serde: { + parameters: ["buffer", "usize"], + result: "u8", + nonblocking: false, + }, + add2: { parameters: ["buffer", "usize"], result: "i32", nonblocking: false }, + test_mixed_order: { + parameters: ["i32", "buffer", "usize", "i32"], + result: "i32", + nonblocking: false, + }, + test_mixed: { + parameters: ["isize", "buffer", "usize"], + result: "i32", + nonblocking: false, + }, +}); +export type MyStruct = { + arr: Array; }; /** - * Doc comment for `Input` struct. - * ...testing multiline - **/ + * Doc comment for `Input` struct. + * ...testing multiline + */ export type Input = { /** - * Doc comments get - * transformed to JS doc - * comments. - **/ + * Doc comments get + * transformed to JS doc + * comments. + */ a: number; b: number; }; -export type MyStruct = { - arr: Array; +export type OptionStruct = { + maybe: string | undefined | null; }; -export function add(a0: number,a1: number) { - - return _lib.symbols.add(a0, a1) as number +export function add(a0: number, a1: number) { + return _lib.symbols.add(a0, a1) as number; } -export function test_mixed(a0: number,a1: Input) { - const a1_buf = encode(JSON.stringify(a1)); - return _lib.symbols.test_mixed(a0, a1_buf, a1_buf.byteLength) as number +export function sleep(a0: number) { + return _lib.symbols.sleep(a0) as Promise; } export function test_serde(a0: MyStruct) { const a0_buf = encode(JSON.stringify(a0)); - return _lib.symbols.test_serde(a0_buf, a0_buf.byteLength) as number + return _lib.symbols.test_serde(a0_buf, a0_buf.byteLength) as number; } export function add2(a0: Input) { const a0_buf = encode(JSON.stringify(a0)); - return _lib.symbols.add2(a0_buf, a0_buf.byteLength) as number + return _lib.symbols.add2(a0_buf, a0_buf.byteLength) as number; +} +export function test_mixed_order(a0: number, a1: Input, a2: number) { + const a1_buf = encode(JSON.stringify(a1)); + return _lib.symbols.test_mixed_order( + a0, + a1_buf, + a1_buf.byteLength, + a2, + ) as number; } -export function test_mixed_order(a0: number,a1: Input,a2: number) { +export function test_mixed(a0: number, a1: Input) { const a1_buf = encode(JSON.stringify(a1)); - return _lib.symbols.test_mixed_order(a0, a1_buf, a1_buf.byteLength, a2) as number + return _lib.symbols.test_mixed(a0, a1_buf, a1_buf.byteLength) as number; } - \ No newline at end of file diff --git a/example/src/lib.rs b/example/src/lib.rs index 87effad..333289f 100644 --- a/example/src/lib.rs +++ b/example/src/lib.rs @@ -58,3 +58,10 @@ fn test_serde(s: MyStruct) -> u8 { struct OptionStruct { maybe: Option, } + +// Test non_blocking +#[deno_bindgen(non_blocking)] +fn sleep(ms: u64) { + std::thread::sleep(std::time::Duration::from_millis(ms)); +} + diff --git a/src/lib.rs b/src/lib.rs index 4172586..3d1ab73 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,11 +11,14 @@ use std::env; use std::fs::OpenOptions; use std::io::Read; use std::io::Write; +use syn::parse_macro_input; use syn::parse_quote; use syn::Data; use syn::DataStruct; use syn::Fields; use syn::ItemFn; +use syn::Meta; +use syn::NestedMeta; #[derive(Serialize, Deserialize, Clone)] #[serde(rename_all = "lowercase")] @@ -71,9 +74,11 @@ impl From for syn::Type { } #[derive(Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] struct Symbol { parameters: Vec, result: Type, + non_blocking: bool, } #[derive(Serialize, Deserialize, Default)] @@ -95,7 +100,7 @@ const ENDIANNESS: bool = true; const ENDIANNESS: bool = false; #[proc_macro_attribute] -pub fn deno_bindgen(_attr: TokenStream, input: TokenStream) -> TokenStream { +pub fn deno_bindgen(attr: TokenStream, input: TokenStream) -> TokenStream { let mut metadata: Glue = match OpenOptions::new().read(true).open(METAFILE) { Ok(mut fd) => { let mut meta = String::new(); @@ -119,7 +124,8 @@ pub fn deno_bindgen(_attr: TokenStream, input: TokenStream) -> TokenStream { let (func, symbol) = match syn::parse::(input.clone()) { Ok(func) => { - let symbol = process_function(func.clone(), &mut metadata).unwrap(); + let attr = parse_macro_input!(attr as syn::AttributeArgs); + let symbol = process_function(func.clone(), attr, &mut metadata).unwrap(); (func, symbol) } Err(_) => { @@ -199,6 +205,7 @@ pub fn deno_bindgen(_attr: TokenStream, input: TokenStream) -> TokenStream { fn process_function( function: ItemFn, + attr: syn::AttributeArgs, metadata: &mut Glue, ) -> Result { let params = &function.sig.inputs; @@ -268,7 +275,18 @@ fn process_function( }; let symbol_name = function.sig.ident.to_string(); - let symbol = Symbol { parameters, result }; + let non_blocking = match attr.get(0).as_ref() { + Some(NestedMeta::Meta(Meta::Path(ref attr_ident))) => { + attr_ident.is_ident("non_blocking") + } + _ => false, + }; + + let symbol = Symbol { + parameters, + result, + non_blocking, + }; metadata.symbols.insert(symbol_name, symbol.clone()); Ok(symbol)