Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ptr and struct type output + async support (close #40) #41

Merged
merged 2 commits into from
Jan 10, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ fmt:
deno fmt --ignore=target/,example/target/,example/bindings/

test:
cd example && deno_bindgen && deno test -A --unstable
cd example && deno run -A ../cli.ts && deno test -A --unstable
63 changes: 47 additions & 16 deletions codegen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ const BufferTypes: Record<string, string> = {
str: "string",
buffer: "Uint8Array",
buffermut: "Uint8Array",
ptr: "Uint8Array",
};

enum Encoder {
Expand All @@ -53,6 +54,7 @@ const BufferTypeEncoders: Record<keyof typeof BufferTypes, Encoder> = {
str: Encoder.None,
buffer: Encoder.None,
buffermut: Encoder.None,
ptr: Encoder.None,
};

type TypeDef = Record<string, Record<string, string>>;
Expand Down Expand Up @@ -90,8 +92,12 @@ type Options = {
release?: boolean;
};

function isTypeDef(p: any) {
return typeof p !== "string";
}

function isBufferType(p: any) {
return typeof p !== "string" || BufferTypes[p] !== undefined;
return isTypeDef(p) || BufferTypes[p] !== undefined;
}

// @littledivy is a dumb kid!
Expand Down Expand Up @@ -125,7 +131,10 @@ function encode(v: string | Uint8Array): Uint8Array {
if (typeof v !== "string") return v;
return new TextEncoder().encode(v);
}
function decode(v: any): Uint8Array {
function decode(v: Uint8Array): string {
return new TextDecoder().decode(v);
}
function read_pointer(v: any): Uint8Array {
const ptr = new Deno.UnsafePointerView(v as Deno.UnsafePointer)
const lengthBe = new Uint8Array(4);
const view = new DataView(lengthBe.buffer);
Expand Down Expand Up @@ -156,14 +165,14 @@ const _lib = await prepare(opts, {
} });
${Object.keys(decl).map((def) => typescript[def]).join("\n")}
${
Object.keys(signature).map((sig) =>
`export function ${sig}(${
signature[sig].parameters.map((p, i) =>
`a${i}: ${resolveType(decl, p)}`
).join(",")
Object.keys(signature).map((sig) => {
const { parameters, result, nonBlocking } = signature[sig];

return `export function ${sig}(${
parameters.map((p, i) => `a${i}: ${resolveType(decl, p)}`).join(",")
}) {
${
signature[sig].parameters.map((p, i) =>
parameters.map((p, i) =>
isBufferType(p)
? `const a${i}_buf = encode(${
BufferTypeEncoders[p] ?? Encoder.JsonStringify
Expand All @@ -172,18 +181,40 @@ ${
).filter((c) => c !== null).join("\n")
}
let result = _lib.symbols.${sig}(${
signature[sig].parameters.map((p, i) =>
parameters.map((p, i) =>
isBufferType(p) ? `a${i}_buf, a${i}_buf.byteLength` : `a${i}`
).join(", ")
}) as ${
signature[sig].nonBlocking
? `Promise<${resolveType(decl, signature[sig].result)}>`
: resolveType(decl, signature[sig].result)
nonBlocking
? `Promise<${
isTypeDef(result)
? "Uint8Array"
: resolveType(decl, result)
}>`
: isTypeDef(result)
? "Uint8Array"
: resolveType(decl, result)
}
${isBufferType(signature[sig].result) ? `result = decode(result);` : ""}
return result;
}`
).join("\n")
${
isBufferType(result)
? nonBlocking
? `result = result.then(read_pointer)`
: `result = read_pointer(result)`
: ""
};
${
isTypeDef(result)
? nonBlocking
? `return result.then(r => JSON.parse(decode(r))) as Promise<${
resolveType(decl, result)
}>`
: `return JSON.parse(decode(result)) as ${
resolveType(decl, result)
}`
: "return result"
};
}`;
}).join("\n")
}
`,
);
Expand Down
8 changes: 7 additions & 1 deletion deno_bindgen_macro/src/derive_fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ pub fn process_function(
let result = match &function.sig.output {
ReturnType::Default => Type::Void,
ReturnType::Type(_, ref ty) => match ty.as_ref() {
syn::Type::Ptr(_) => Type::Ptr,
syn::Type::Path(ref ty) => {
let segment = ty.path.segments.first().unwrap();
let ident = segment.ident.to_string();
Expand All @@ -105,7 +106,12 @@ pub fn process_function(
"isize" => Type::Isize,
"f32" => Type::F32,
"f64" => Type::F64,
_ => panic!("{} return type not supported by Deno FFI", ident),
_ => {
match metadata.type_defs.get(&ident) {
Some(_) => Type::StructEnum { ident },
None => panic!("{} return type not supported by Deno FFI", ident)
}
}
}
}
syn::Type::Reference(ref ty) => match *ty.elem {
Expand Down
24 changes: 21 additions & 3 deletions deno_bindgen_macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,11 +146,30 @@ pub fn deno_bindgen(attr: TokenStream, input: TokenStream) -> TokenStream {
let result = v.as_ptr();
// Leak the result to JS land.
::std::mem::forget(v);
result
};

(ty, transformer)
}
_ => (syn::Type::from(symbol.result), quote! {}),
Type::StructEnum { .. } => {
let ty = parse_quote! { *const u8 };
let transformer = quote! {
let json = deno_bindgen::serde_json::to_string(&result);
let encoded = json.unwrap().into_bytes();
littledivy marked this conversation as resolved.
Show resolved Hide resolved
let length = (encoded.len() as u32).to_be_bytes();
let mut v = length.to_vec();
v.extend(encoded.clone());

let ret = v.as_ptr();
// Leak the result to JS land.
::std::mem::forget(v);
ret
};

(ty, transformer)
},
Type::Ptr => (parse_quote! { *const u8 }, quote! { result }),
_ => (syn::Type::from(symbol.result), quote! { result }),
};

let name = &func.sig.ident;
Expand All @@ -174,7 +193,6 @@ pub fn deno_bindgen(attr: TokenStream, input: TokenStream) -> TokenStream {
#overrides
let result = __inner_impl(#(#input_idents, ) *);
#transformer
result
}
})
}
Expand All @@ -187,7 +205,7 @@ pub fn deno_bindgen(attr: TokenStream, input: TokenStream) -> TokenStream {
.unwrap();

TokenStream::from(quote! {
#[derive(::serde::Deserialize)]
#[derive(::serde::Deserialize,::serde::Serialize)]
#input
})
}
Expand Down
1 change: 1 addition & 0 deletions deno_bindgen_macro/src/meta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pub enum Type {
Buffer,
BufferMut,
Str,
Ptr,

/// Not-so straightforward types that
/// `deno_bingen` maps to.
Expand Down
Loading