summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cli/dts/lib.deno.unstable.d.ts202
-rw-r--r--ext/ffi/lib.rs16
-rw-r--r--test_ffi/tests/ffi_types.ts55
-rw-r--r--test_ffi/tests/test.js29
4 files changed, 125 insertions, 177 deletions
diff --git a/cli/dts/lib.deno.unstable.d.ts b/cli/dts/lib.deno.unstable.d.ts
index 389d08f9f..643386ced 100644
--- a/cli/dts/lib.deno.unstable.d.ts
+++ b/cli/dts/lib.deno.unstable.d.ts
@@ -329,32 +329,86 @@ declare namespace Deno {
*/
export function getGid(): number | null;
- /** All possible types for interfacing with foreign functions */
- export type NativeType =
- | "void"
+ /** All plain number types for interfacing with foreign functions */
+ type NativeNumberType =
| "u8"
| "i8"
| "u16"
| "i16"
| "u32"
| "i32"
+ | "f32"
+ | "f64";
+
+ /** All BigInt number type sfor interfacing with foreign functions */
+ type NativeBigIntType =
| "u64"
| "i64"
| "usize"
- | "isize"
- | "f32"
- | "f64"
- | "pointer";
+ | "isize";
+
+ type NativePointerType = "pointer";
- type NativeParameterType =
- | NativeType
- | NativeCallbackType;
+ type NativeFunctionType = "function";
+
+ type NativeVoidType = "void";
+
+ /** All possible types for interfacing with foreign functions */
+ export type NativeType =
+ | NativeNumberType
+ | NativeBigIntType
+ | NativePointerType
+ | NativeFunctionType;
+
+ export type NativeResultType = NativeType | NativeVoidType;
+
+ /** Type conversion for foreign symbol parameters and unsafe callback return types */
+ type ToNativeType<T extends NativeType = NativeType> = T extends
+ NativeNumberType ? number
+ : T extends NativeBigIntType ? bigint | number
+ : T extends NativePointerType ? TypedArray | bigint | null
+ : T extends NativeFunctionType ? bigint | null
+ : never;
+
+ /** Type conversion for unsafe callback return types */
+ type ToNativeResultType<T extends NativeResultType = NativeResultType> =
+ T extends NativeType ? ToNativeType<T>
+ : T extends NativeVoidType ? void
+ : never;
+
+ type ToNativeParameterTypes<T extends readonly NativeType[]> = T extends
+ readonly [] ? []
+ : T extends readonly [
+ infer U extends NativeType,
+ ...(infer V extends NativeType[]),
+ ] ? [ToNativeType<U>, ...ToNativeParameterTypes<V>]
+ : never;
+
+ /** Type conversion for foreign symbol return types and unsafe callback parameters */
+ type FromNativeType<T extends NativeType = NativeType> = T extends
+ NativeNumberType ? number
+ : T extends NativeBigIntType | NativePointerType | NativeFunctionType
+ ? bigint
+ : never;
+
+ /** Type conversion for foregin symbol return types */
+ type FromNativeResultType<T extends NativeResultType = NativeResultType> =
+ T extends NativeType ? FromNativeType<T>
+ : T extends NativeVoidType ? void
+ : never;
+
+ type FromNativeParameterTypes<T extends readonly NativeType[]> = T extends
+ readonly [] ? []
+ : T extends readonly [
+ infer U extends NativeType,
+ ...(infer V extends NativeType[]),
+ ] ? [FromNativeType<U>, ...FromNativeParameterTypes<V>]
+ : never;
/** A foreign function as defined by its parameter and result types */
export interface ForeignFunction<
- Parameters extends readonly NativeParameterType[] =
- readonly NativeParameterType[],
- Result extends NativeType = NativeType,
+ Parameters extends readonly NativeType[] = readonly NativeType[],
+ Result extends NativeResultType = NativeResultType,
NonBlocking extends boolean = boolean,
> {
/** Name of the symbol, defaults to the key name in symbols object. */
@@ -368,7 +422,7 @@ declare namespace Deno {
export interface ForeignStatic<Type extends NativeType = NativeType> {
/** Name of the symbol, defaults to the key name in symbols object. */
name?: string;
- type: Exclude<Type, "void">;
+ type: Type;
}
/** A foreign library interface descriptor */
@@ -376,50 +430,21 @@ declare namespace Deno {
[name: string]: ForeignFunction | ForeignStatic;
}
- /** All possible number types interfacing with foreign functions */
- type StaticNativeNumberType = Exclude<
- NativeType,
- "void" | "pointer" | StaticNativeBigIntType
- >;
-
- /** All possible bigint types interfacing with foreign functions */
- type StaticNativeBigIntType = "u64" | "i64" | "usize" | "isize";
-
- /** Infers a foreign function return type */
- type StaticForeignFunctionResult<T extends NativeType> = T extends "void"
- ? void
- : T extends StaticNativeBigIntType ? bigint
- : T extends StaticNativeNumberType ? number
- : T extends "pointer" ? bigint
- : never;
-
- type StaticForeignFunctionParameter<T> = T extends "void" ? void
- : T extends StaticNativeNumberType | StaticNativeBigIntType
- ? number | bigint
- : T extends "pointer" ? bigint | TypedArray | null
- : T extends NativeCallbackType ? bigint | null
- : unknown;
-
- /** Infers a foreign function parameter list. */
- type StaticForeignFunctionParameters<
- T extends readonly NativeParameterType[],
- > = [
- ...{
- [K in keyof T]: StaticForeignFunctionParameter<T[K]>;
- },
- ];
-
/** Infers a foreign symbol */
type StaticForeignSymbol<T extends ForeignFunction | ForeignStatic> =
- T extends ForeignFunction ? (
- ...args: StaticForeignFunctionParameters<T["parameters"]>
- ) => ConditionalAsync<
- T["nonblocking"],
- StaticForeignFunctionResult<T["result"]>
- >
- : T extends ForeignStatic ? StaticForeignFunctionResult<T["type"]>
+ T extends ForeignFunction ? FromForeignFunction<T>
+ : T extends ForeignStatic ? FromNativeType<T["type"]>
: never;
+ type FromForeignFunction<T extends ForeignFunction> = T["parameters"] extends
+ readonly [] ? () => StaticForeignSymbolReturnType<T>
+ : (
+ ...args: ToNativeParameterTypes<T["parameters"]>
+ ) => StaticForeignSymbolReturnType<T>;
+
+ type StaticForeignSymbolReturnType<T extends ForeignFunction> =
+ ConditionalAsync<T["nonblocking"], FromNativeResultType<T["result"]>>;
+
type ConditionalAsync<IsAsync extends boolean | undefined, T> =
IsAsync extends true ? Promise<T> : T;
@@ -504,63 +529,23 @@ declare namespace Deno {
constructor(pointer: bigint, definition: Fn);
- call(
- ...args: StaticForeignFunctionParameters<Fn["parameters"]>
- ): ConditionalAsync<
- Fn["nonblocking"],
- StaticForeignFunctionResult<Fn["result"]>
- >;
+ call: FromForeignFunction<Fn>;
}
export interface UnsafeCallbackDefinition<
Parameters extends readonly NativeType[] = readonly NativeType[],
- Result extends NativeParameterType = NativeParameterType,
+ Result extends NativeResultType = NativeResultType,
> {
parameters: Parameters;
result: Result;
}
- interface NativeCallbackType<
- Parameters extends readonly NativeType[] = readonly NativeType[],
- Result extends NativeParameterType = NativeParameterType,
- > {
- readonly function: UnsafeCallbackDefinition<Parameters, Result>;
- }
-
- type UnsafeCallbackParameters<T extends readonly NativeType[]> = T extends []
- ? []
- : T extends
- readonly [infer U extends NativeType, ...(infer V extends NativeType[])]
- ? [
- UnsafeCallbackParameter<U>,
- ...UnsafeCallbackParameters<V>,
- ]
- : never;
-
- type UnsafeCallbackParameter<T extends NativeType> = T extends
- StaticNativeBigIntType ? bigint
- : T extends StaticNativeNumberType ? number
- : T extends "pointer" ? bigint
- : never;
-
- type UnsafeCallbackResult<T extends NativeParameterType> = T extends "void"
- ? void
- : T extends StaticNativeBigIntType ? number | bigint
- : T extends StaticNativeNumberType ? number
- : T extends "pointer" ? bigint | TypedArray | null
- : T extends NativeCallbackType ? bigint | null
- : never;
-
type UnsafeCallbackFunction<
Parameters extends readonly NativeType[] = readonly NativeType[],
- Result extends NativeParameterType = NativeParameterType,
- > = Result extends NativeParameterType
- ? Parameters extends readonly [] ? () => UnsafeCallbackResult<Result>
- : Parameters extends readonly NativeType[] ? (
- ...args: UnsafeCallbackParameters<Parameters>
- ) => UnsafeCallbackResult<Result>
- : never
- : never;
+ Result extends NativeResultType = NativeResultType,
+ > = Parameters extends readonly [] ? () => ToNativeResultType<Result> : (
+ ...args: FromNativeParameterTypes<Parameters>
+ ) => ToNativeResultType<Result>;
/**
* **UNSTABLE**: Unsafe and new API, beware!
@@ -571,17 +556,22 @@ declare namespace Deno {
* The function pointer remains valid until the `close()` method is called.
*/
export class UnsafeCallback<
- Parameters extends readonly NativeType[] = readonly NativeType[],
- Result extends NativeParameterType = NativeParameterType,
+ Definition extends UnsafeCallbackDefinition = UnsafeCallbackDefinition,
> {
constructor(
- definition: UnsafeCallbackDefinition<Parameters, Result>,
- callback: UnsafeCallbackFunction<Parameters, Result>,
+ definition: Definition,
+ callback: UnsafeCallbackFunction<
+ Definition["parameters"],
+ Definition["result"]
+ >,
);
pointer: bigint;
- definition: UnsafeCallbackDefinition<Parameters, Result>;
- callback: UnsafeCallbackFunction<Parameters, Result>;
+ definition: Definition;
+ callback: UnsafeCallbackFunction<
+ Definition["parameters"],
+ Definition["result"]
+ >;
close(): void;
}
diff --git a/ext/ffi/lib.rs b/ext/ffi/lib.rs
index 691d44460..f380546b0 100644
--- a/ext/ffi/lib.rs
+++ b/ext/ffi/lib.rs
@@ -228,7 +228,7 @@ enum NativeType {
F32,
F64,
Pointer,
- Function {},
+ Function,
}
impl From<NativeType> for libffi::middle::Type {
@@ -248,7 +248,7 @@ impl From<NativeType> for libffi::middle::Type {
NativeType::F32 => libffi::middle::Type::f32(),
NativeType::F64 => libffi::middle::Type::f64(),
NativeType::Pointer => libffi::middle::Type::pointer(),
- NativeType::Function {} => libffi::middle::Type::pointer(),
+ NativeType::Function => libffi::middle::Type::pointer(),
}
}
}
@@ -289,7 +289,7 @@ impl NativeValue {
NativeType::ISize => Arg::new(&self.isize_value),
NativeType::F32 => Arg::new(&self.f32_value),
NativeType::F64 => Arg::new(&self.f64_value),
- NativeType::Pointer | NativeType::Function {} => Arg::new(&self.pointer),
+ NativeType::Pointer | NativeType::Function => Arg::new(&self.pointer),
}
}
@@ -317,7 +317,7 @@ impl NativeValue {
}
NativeType::F32 => Value::from(self.f32_value),
NativeType::F64 => Value::from(self.f64_value),
- NativeType::Pointer | NativeType::Function {} => {
+ NativeType::Pointer | NativeType::Function => {
json!(U32x2::from(self.pointer as u64))
}
}
@@ -394,7 +394,7 @@ impl NativeValue {
v8::Number::new(scope, self.f64_value).into();
local_value.into()
}
- NativeType::Pointer | NativeType::Function {} => {
+ NativeType::Pointer | NativeType::Function => {
let local_value: v8::Local<v8::Value> =
v8::BigInt::new_from_u64(scope, self.pointer as u64).into();
local_value.into()
@@ -702,7 +702,7 @@ where
return Err(type_error("Invalid FFI pointer type, expected null, BigInt, ArrayBuffer, or ArrayBufferView"));
}
}
- NativeType::Function {} => {
+ NativeType::Function => {
if value.is_null() {
let value: *const u8 = ptr::null();
ffi_args.push(NativeValue { pointer: value })
@@ -777,7 +777,7 @@ fn ffi_call(
NativeType::F64 => NativeValue {
f64_value: unsafe { cif.call::<f64>(fun_ptr, &call_args) },
},
- NativeType::Pointer | NativeType::Function {} => NativeValue {
+ NativeType::Pointer | NativeType::Function => NativeValue {
pointer: unsafe { cif.call::<*const u8>(fun_ptr, &call_args) },
},
})
@@ -1245,7 +1245,7 @@ fn op_ffi_get_static<'scope>(
let number = v8::Number::new(scope, result as f64);
serde_v8::from_v8(scope, number.into())?
}
- NativeType::Pointer | NativeType::Function {} => {
+ NativeType::Pointer | NativeType::Function => {
let result = data_ptr as *const u8 as u64;
let big_int = v8::BigInt::new_from_u64(scope, result);
serde_v8::from_v8(scope, big_int.into())?
diff --git a/test_ffi/tests/ffi_types.ts b/test_ffi/tests/ffi_types.ts
index 92ac13892..742f92748 100644
--- a/test_ffi/tests/ffi_types.ts
+++ b/test_ffi/tests/ffi_types.ts
@@ -6,7 +6,7 @@ const remote = Deno.dlopen(
"dummy_lib.so",
{
method1: { parameters: ["usize", "usize"], result: "void" },
- method2: { parameters: ["void"], result: "void" },
+ method2: { parameters: [], result: "void" },
method3: { parameters: ["usize"], result: "void" },
method4: { parameters: ["isize"], result: "void" },
method5: { parameters: ["u8"], result: "void" },
@@ -25,24 +25,17 @@ const remote = Deno.dlopen(
method18: { parameters: [], result: "pointer" },
method19: { parameters: [], result: "pointer", nonblocking: true },
method20: {
- parameters: [{
- function: { parameters: ["u8", "u32", "pointer"], result: "void" },
- }],
+ parameters: ["pointer"],
result: "void",
},
method21: {
parameters: [
- { function: { parameters: [], result: "u8" } },
+ "pointer",
],
result: "void",
},
method22: {
- parameters: [{
- function: {
- parameters: [],
- result: { function: { parameters: [], result: "u8" } },
- },
- }],
+ parameters: ["pointer"],
result: "void",
},
static1: { type: "usize" },
@@ -65,7 +58,7 @@ const remote = Deno.dlopen(
Deno.dlopen(
"dummy_lib_2.so",
// @ts-expect-error: Returning a function pointer
- // is declared using "pointer" + UnsafeFnPointer
+ // is declared using "pointer" or "function" + UnsafeFnPointer
{
wrong_method1: {
parameters: [],
@@ -85,9 +78,9 @@ remote.symbols.method1(0);
<number> remote.symbols.method1(0, 0);
<void> remote.symbols.method1(0n, 0n);
-// @ts-expect-error: Invalid argument
+// @ts-expect-error: Expected 0 arguments, but got 1.
remote.symbols.method2(null);
-remote.symbols.method2(void 0);
+remote.symbols.method2();
// @ts-expect-error: Invalid argument
remote.symbols.method3(null);
@@ -140,7 +133,7 @@ remote.symbols.method14(0);
// @ts-expect-error: Invalid argument
remote.symbols.method15(0);
remote.symbols.method15(new Uint16Array(1));
-remote.symbols.method15({} as Deno.UnsafePointer);
+remote.symbols.method15(0n);
const result = remote.symbols.method16();
// @ts-expect-error: Invalid argument
@@ -162,9 +155,8 @@ const result4 = remote.symbols.method19();
result4.then((_0: Deno.TypedArray) => {});
result4.then((_1: Deno.UnsafePointer) => {});
-const ptr = new Deno.UnsafePointer(0n);
const fnptr = new Deno.UnsafeFnPointer(
- ptr,
+ 0n,
{
parameters: ["u32", "pointer"],
result: "void",
@@ -180,7 +172,7 @@ const unsafe_callback_wrong1 = new Deno.UnsafeCallback(
result: "void",
} as const,
// @ts-expect-error: i8 is not a pointer
- (_: Deno.UnsafePointer) => {},
+ (_: bigint) => {},
);
const unsafe_callback_wrong2 = new Deno.UnsafeCallback(
{
@@ -223,15 +215,10 @@ const unsafe_callback_right2 = new Deno.UnsafeCallback(
const unsafe_callback_right3 = new Deno.UnsafeCallback(
{
parameters: [],
- result: {
- function: {
- parameters: [],
- result: "u8",
- },
- },
+ result: "function",
} as const,
- // Callbacks can return other callbacks, if really wanted.
- () => unsafe_callback_right2,
+ // Callbacks can return other callbacks' pointers, if really wanted.
+ () => unsafe_callback_right2.pointer,
);
const unsafe_callback_right4 = new Deno.UnsafeCallback(
{
@@ -252,21 +239,9 @@ const unsafe_callback_right5 = new Deno.UnsafeCallback(
remote.symbols.method20();
// nullptr is okay
remote.symbols.method20(null);
-// Foreign function ptr received as UnsafePointer is okay
-remote.symbols.method20({} as Deno.UnsafePointer);
-// @ts-expect-error: Callback does not match the parameter
+// @ts-expect-error: Callback cannot be passed directly
remote.symbols.method20(unsafe_callback_right2);
-remote.symbols.method20(unsafe_callback_right1);
-// @ts-expect-error: Callback must match return value as well
-remote.symbols.method20(unsafe_callback_right4);
-// @ts-expect-error: Subtle differences in parameter types are not allowed (i32 vs u32)
-remote.symbols.method20(unsafe_callback_right5);
-remote.symbols.method21(unsafe_callback_right2);
-remote.symbols.method22(unsafe_callback_right3);
-// @ts-expect-error: Callback returns a callback with the wrong return value
-remote.symbols.method21(unsafe_callback_right3);
-// @ts-expect-error: Callback returns a callback with the wrong return value
-remote.symbols.method22(unsafe_callback_right2);
+remote.symbols.method20(unsafe_callback_right1.pointer);
// @ts-expect-error: Invalid member type
const static1_wrong: null = remote.symbols.static1;
diff --git a/test_ffi/tests/test.js b/test_ffi/tests/test.js
index 0caa416a1..8190b3c8e 100644
--- a/test_ffi/tests/test.js
+++ b/test_ffi/tests/test.js
@@ -127,44 +127,27 @@ const dylib = Deno.dlopen(libPath, {
},
// Callback function
call_fn_ptr: {
- parameters: [{ function: { parameters: [], result: "void" } }],
+ parameters: ["function"],
result: "void",
},
call_fn_ptr_many_parameters: {
- parameters: [{
- function: {
- parameters: [
- "u8",
- "i8",
- "u16",
- "i16",
- "u32",
- "i32",
- "u64",
- "i64",
- "f32",
- "f64",
- "pointer",
- ],
- result: "void",
- },
- }],
+ parameters: ["function"],
result: "void",
},
call_fn_ptr_return_u8: {
- parameters: [{ function: { parameters: [], result: "u8" } }],
+ parameters: ["function"],
result: "void",
},
call_fn_ptr_return_buffer: {
- parameters: [{ function: { parameters: [], result: "pointer" } }],
+ parameters: ["function"],
result: "void",
},
store_function: {
- parameters: [{ function: { parameters: [], result: "void" } }],
+ parameters: ["function"],
result: "void",
},
store_function_2: {
- parameters: [{ function: { parameters: ["u8"], result: "u8" } }],
+ parameters: ["function"],
result: "void",
},
call_stored_function: {