2022-01-07 22:09:52 -05:00
|
|
|
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
|
2021-08-06 17:28:10 -04:00
|
|
|
// deno-lint-ignore-file
|
|
|
|
|
2022-01-05 02:25:31 -05:00
|
|
|
import { assertThrows } from "../../test_util/std/testing/asserts.ts";
|
|
|
|
|
2021-08-06 17:28:10 -04:00
|
|
|
const targetDir = Deno.execPath().replace(/[^\/\\]+$/, "");
|
|
|
|
const [libPrefix, libSuffix] = {
|
|
|
|
darwin: ["lib", "dylib"],
|
|
|
|
linux: ["lib", "so"],
|
|
|
|
windows: ["", "dll"],
|
|
|
|
}[Deno.build.os];
|
|
|
|
const libPath = `${targetDir}/${libPrefix}test_ffi.${libSuffix}`;
|
|
|
|
|
|
|
|
const resourcesPre = Deno.resources();
|
2021-10-07 11:03:00 -04:00
|
|
|
|
|
|
|
// dlopen shouldn't panic
|
2022-01-05 02:25:31 -05:00
|
|
|
assertThrows(() => {
|
2021-10-07 11:03:00 -04:00
|
|
|
Deno.dlopen("cli/src/main.rs", {});
|
2022-01-05 02:25:31 -05:00
|
|
|
});
|
|
|
|
|
|
|
|
assertThrows(
|
|
|
|
() => {
|
|
|
|
Deno.dlopen(libPath, {
|
|
|
|
non_existent_symbol: {
|
|
|
|
parameters: [],
|
|
|
|
result: "void",
|
|
|
|
},
|
|
|
|
});
|
|
|
|
},
|
|
|
|
Error,
|
|
|
|
"Failed to register symbol non_existent_symbol",
|
|
|
|
);
|
2021-10-07 11:03:00 -04:00
|
|
|
|
2021-08-06 17:28:10 -04:00
|
|
|
const dylib = Deno.dlopen(libPath, {
|
2022-01-11 01:21:16 -05:00
|
|
|
"printSomething": {
|
|
|
|
name: "print_something",
|
|
|
|
parameters: [],
|
|
|
|
result: "void",
|
|
|
|
},
|
2021-12-15 09:41:49 -05:00
|
|
|
"print_buffer": { parameters: ["pointer", "usize"], result: "void" },
|
2021-10-10 09:18:02 -04:00
|
|
|
"print_buffer2": {
|
2021-12-15 09:41:49 -05:00
|
|
|
parameters: ["pointer", "usize", "pointer", "usize"],
|
2021-10-10 09:18:02 -04:00
|
|
|
result: "void",
|
|
|
|
},
|
2021-12-15 09:41:49 -05:00
|
|
|
"return_buffer": { parameters: [], result: "pointer" },
|
|
|
|
"is_null_ptr": { parameters: ["pointer"], result: "u8" },
|
2021-09-20 14:38:28 -04:00
|
|
|
"add_u32": { parameters: ["u32", "u32"], result: "u32" },
|
|
|
|
"add_i32": { parameters: ["i32", "i32"], result: "i32" },
|
|
|
|
"add_u64": { parameters: ["u64", "u64"], result: "u64" },
|
|
|
|
"add_i64": { parameters: ["i64", "i64"], result: "i64" },
|
|
|
|
"add_usize": { parameters: ["usize", "usize"], result: "usize" },
|
|
|
|
"add_isize": { parameters: ["isize", "isize"], result: "isize" },
|
|
|
|
"add_f32": { parameters: ["f32", "f32"], result: "f32" },
|
|
|
|
"add_f64": { parameters: ["f64", "f64"], result: "f64" },
|
2021-12-15 09:41:49 -05:00
|
|
|
"fill_buffer": { parameters: ["u8", "pointer", "usize"], result: "void" },
|
2022-01-11 01:21:16 -05:00
|
|
|
"sleep_nonblocking": {
|
|
|
|
name: "sleep_blocking",
|
|
|
|
parameters: ["u64"],
|
|
|
|
result: "void",
|
|
|
|
nonblocking: true,
|
|
|
|
},
|
|
|
|
"sleep_blocking": { parameters: ["u64"], result: "void" },
|
2021-10-05 18:27:05 -04:00
|
|
|
"nonblocking_buffer": {
|
2021-12-15 09:41:49 -05:00
|
|
|
parameters: ["pointer", "usize"],
|
2021-10-05 18:27:05 -04:00
|
|
|
result: "void",
|
|
|
|
nonblocking: true,
|
|
|
|
},
|
2022-01-12 06:38:26 -05:00
|
|
|
"get_add_u32_ptr": {
|
|
|
|
parameters: [],
|
|
|
|
result: "pointer",
|
|
|
|
},
|
|
|
|
"get_sleep_blocking_ptr": {
|
|
|
|
parameters: [],
|
|
|
|
result: "pointer",
|
|
|
|
},
|
2022-02-18 07:21:19 -05:00
|
|
|
"static_u32": {
|
|
|
|
type: "u32",
|
|
|
|
},
|
|
|
|
"static_ptr": {
|
|
|
|
type: "pointer",
|
|
|
|
},
|
2021-08-06 17:28:10 -04:00
|
|
|
});
|
|
|
|
|
2022-01-11 01:21:16 -05:00
|
|
|
dylib.symbols.printSomething();
|
2021-10-05 18:27:05 -04:00
|
|
|
const buffer = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]);
|
2021-10-10 09:18:02 -04:00
|
|
|
const buffer2 = new Uint8Array([9, 10]);
|
2021-10-05 18:27:05 -04:00
|
|
|
dylib.symbols.print_buffer(buffer, buffer.length);
|
2021-10-10 09:18:02 -04:00
|
|
|
dylib.symbols.print_buffer2(buffer, buffer.length, buffer2, buffer2.length);
|
2021-12-15 09:41:49 -05:00
|
|
|
const ptr = dylib.symbols.return_buffer();
|
|
|
|
dylib.symbols.print_buffer(ptr, 8);
|
|
|
|
const ptrView = new Deno.UnsafePointerView(ptr);
|
|
|
|
const into = new Uint8Array(6);
|
|
|
|
const into2 = new Uint8Array(3);
|
|
|
|
const into2ptr = Deno.UnsafePointer.of(into2);
|
|
|
|
const into2ptrView = new Deno.UnsafePointerView(into2ptr);
|
|
|
|
const into3 = new Uint8Array(3);
|
|
|
|
ptrView.copyInto(into);
|
|
|
|
console.log([...into]);
|
|
|
|
ptrView.copyInto(into2, 3);
|
|
|
|
console.log([...into2]);
|
|
|
|
into2ptrView.copyInto(into3);
|
|
|
|
console.log([...into3]);
|
|
|
|
const string = new Uint8Array([
|
|
|
|
...new TextEncoder().encode("Hello from pointer!"),
|
|
|
|
0,
|
|
|
|
]);
|
|
|
|
const stringPtr = Deno.UnsafePointer.of(string);
|
|
|
|
const stringPtrview = new Deno.UnsafePointerView(stringPtr);
|
|
|
|
console.log(stringPtrview.getCString());
|
|
|
|
console.log(stringPtrview.getCString(11));
|
|
|
|
console.log(Boolean(dylib.symbols.is_null_ptr(ptr)));
|
|
|
|
console.log(Boolean(dylib.symbols.is_null_ptr(null)));
|
|
|
|
console.log(Boolean(dylib.symbols.is_null_ptr(Deno.UnsafePointer.of(into))));
|
2022-01-12 06:38:26 -05:00
|
|
|
|
|
|
|
const addU32Ptr = dylib.symbols.get_add_u32_ptr();
|
|
|
|
const addU32 = new Deno.UnsafeFnPointer(addU32Ptr, {
|
|
|
|
parameters: ["u32", "u32"],
|
|
|
|
result: "u32",
|
|
|
|
});
|
|
|
|
console.log(addU32.call(123, 456));
|
|
|
|
|
|
|
|
const sleepBlockingPtr = dylib.symbols.get_sleep_blocking_ptr();
|
|
|
|
const sleepNonBlocking = new Deno.UnsafeFnPointer(sleepBlockingPtr, {
|
|
|
|
nonblocking: true,
|
|
|
|
parameters: ["u64"],
|
|
|
|
result: "void",
|
|
|
|
});
|
|
|
|
const before = performance.now();
|
|
|
|
await sleepNonBlocking.call(100);
|
|
|
|
console.log(performance.now() - before >= 100);
|
|
|
|
|
2021-09-20 14:38:28 -04:00
|
|
|
console.log(dylib.symbols.add_u32(123, 456));
|
2022-01-05 02:25:31 -05:00
|
|
|
assertThrows(
|
|
|
|
() => {
|
|
|
|
dylib.symbols.add_u32(-1, 100);
|
|
|
|
},
|
|
|
|
TypeError,
|
|
|
|
"Expected FFI argument to be an unsigned integer, but got Number(-1)",
|
|
|
|
);
|
|
|
|
assertThrows(
|
|
|
|
() => {
|
|
|
|
dylib.symbols.add_u32(null, 100);
|
|
|
|
},
|
|
|
|
TypeError,
|
|
|
|
"Expected FFI argument to be an unsigned integer, but got Null",
|
|
|
|
);
|
2021-09-20 14:38:28 -04:00
|
|
|
console.log(dylib.symbols.add_i32(123, 456));
|
|
|
|
console.log(dylib.symbols.add_u64(123, 456));
|
|
|
|
console.log(dylib.symbols.add_i64(123, 456));
|
|
|
|
console.log(dylib.symbols.add_usize(123, 456));
|
|
|
|
console.log(dylib.symbols.add_isize(123, 456));
|
|
|
|
console.log(dylib.symbols.add_f32(123.123, 456.789));
|
|
|
|
console.log(dylib.symbols.add_f64(123.123, 456.789));
|
2021-08-06 17:28:10 -04:00
|
|
|
|
2021-11-10 08:55:46 -05:00
|
|
|
// test mutating sync calls
|
|
|
|
|
|
|
|
function test_fill_buffer(fillValue, arr) {
|
|
|
|
let buf = new Uint8Array(arr);
|
|
|
|
dylib.symbols.fill_buffer(fillValue, buf, buf.length);
|
|
|
|
for (let i = 0; i < buf.length; i++) {
|
|
|
|
if (buf[i] !== fillValue) {
|
|
|
|
throw new Error(`Found '${buf[i]}' in buffer, expected '${fillValue}'.`);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
test_fill_buffer(0, [2, 3, 4]);
|
|
|
|
test_fill_buffer(5, [2, 7, 3, 2, 1]);
|
|
|
|
|
2021-10-05 08:50:00 -04:00
|
|
|
// Test non blocking calls
|
2021-10-05 18:27:05 -04:00
|
|
|
|
|
|
|
function deferred() {
|
|
|
|
let methods;
|
|
|
|
const promise = new Promise((resolve, reject) => {
|
|
|
|
methods = {
|
|
|
|
async resolve(value) {
|
|
|
|
await value;
|
|
|
|
resolve(value);
|
|
|
|
},
|
|
|
|
reject(reason) {
|
|
|
|
reject(reason);
|
|
|
|
},
|
|
|
|
};
|
|
|
|
});
|
|
|
|
return Object.assign(promise, methods);
|
|
|
|
}
|
|
|
|
|
|
|
|
const promise = deferred();
|
2021-10-10 09:18:02 -04:00
|
|
|
const buffer3 = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]);
|
|
|
|
dylib.symbols.nonblocking_buffer(buffer3, buffer3.length).then(() => {
|
2021-10-05 18:27:05 -04:00
|
|
|
promise.resolve();
|
|
|
|
});
|
|
|
|
await promise;
|
|
|
|
|
2022-01-11 01:21:16 -05:00
|
|
|
let start = performance.now();
|
|
|
|
dylib.symbols.sleep_blocking(100);
|
|
|
|
console.log("After sleep_blocking");
|
|
|
|
console.log(performance.now() - start >= 100);
|
|
|
|
|
|
|
|
start = performance.now();
|
|
|
|
dylib.symbols.sleep_nonblocking(100).then(() => {
|
2021-10-05 08:50:00 -04:00
|
|
|
console.log("After");
|
|
|
|
console.log(performance.now() - start >= 100);
|
|
|
|
// Close after task is complete.
|
|
|
|
cleanup();
|
|
|
|
});
|
|
|
|
console.log("Before");
|
|
|
|
console.log(performance.now() - start < 100);
|
|
|
|
|
2022-02-18 07:21:19 -05:00
|
|
|
console.log("Static u32:", dylib.symbols.static_u32);
|
|
|
|
console.log(
|
|
|
|
"Static ptr:",
|
|
|
|
dylib.symbols.static_ptr instanceof Deno.UnsafePointer,
|
|
|
|
);
|
|
|
|
const view = new Deno.UnsafePointerView(dylib.symbols.static_ptr);
|
|
|
|
console.log("Static ptr value:", view.getUint32());
|
|
|
|
|
2021-10-05 08:50:00 -04:00
|
|
|
function cleanup() {
|
|
|
|
dylib.close();
|
2021-08-06 17:28:10 -04:00
|
|
|
|
2021-10-05 08:50:00 -04:00
|
|
|
const resourcesPost = Deno.resources();
|
|
|
|
|
|
|
|
const preStr = JSON.stringify(resourcesPre, null, 2);
|
|
|
|
const postStr = JSON.stringify(resourcesPost, null, 2);
|
|
|
|
if (preStr !== postStr) {
|
|
|
|
throw new Error(
|
|
|
|
`Difference in open resources before dlopen and after closing:
|
2021-08-06 17:28:10 -04:00
|
|
|
Before: ${preStr}
|
|
|
|
After: ${postStr}`,
|
2021-10-05 08:50:00 -04:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
console.log("Correct number of resources");
|
2021-08-06 17:28:10 -04:00
|
|
|
}
|