Skip to content

Commit

Permalink
feat: support struct and pointer return types (#41)
Browse files Browse the repository at this point in the history
Co-authored-by: Divy Srivastava <[email protected]>
  • Loading branch information
zifeo and littledivy authored Jan 10, 2022
1 parent 2e91011 commit ccbd96e
Show file tree
Hide file tree
Showing 8 changed files with 312 additions and 116 deletions.
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).expect("Failed to serialize as JSON");
let encoded = json.into_bytes();
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

0 comments on commit ccbd96e

Please sign in to comment.