From f5af0e4cafd892124364b0e18d2513f3a985f4ad Mon Sep 17 00:00:00 2001 From: Mahdi Sharifi Date: Wed, 10 Jan 2024 23:33:34 +0330 Subject: [PATCH] Fix support on all Javscript runtimes --- .github/workflows/test-run.yml | 4 +- README.md | 42 +++-------- bench/bench-with-builtin.js | 76 ++++++++----------- bench/faker/generate.js | 2 + bench/package.json | 2 +- build.zig | 22 ++---- src/core/Kivi.zig | 13 ++-- src/drivers/js/deno&bun/bun.js | 92 +++++++++++++++++++++-- src/drivers/js/deno&bun/deno.js | 98 ++++++++++++++++++++++--- src/drivers/js/deno&bun/index.js | 122 ------------------------------- src/drivers/js/index.js | 14 +++- src/drivers/js/nodejs/index.js | 22 ++++-- src/drivers/js/tests/kivi.js | 6 +- 13 files changed, 265 insertions(+), 250 deletions(-) delete mode 100644 src/drivers/js/deno&bun/index.js diff --git a/.github/workflows/test-run.yml b/.github/workflows/test-run.yml index e35453e..c9dc6ca 100644 --- a/.github/workflows/test-run.yml +++ b/.github/workflows/test-run.yml @@ -9,8 +9,8 @@ jobs: - uses: actions/checkout@v3 - uses: goto-bus-stop/setup-zig@v2 - name: Install npm - run: sudo apt-get install -y curl unzip && curl -fsSL https://fnm.vercel.app/install | bash && export PATH="/$HOME/.local/share/fnm:$PATH" && eval "`fnm env`" && fnm install v20.10.0 && fnm use v20.10.0 && npm -g i npm@latest + run: sudo apt-get install -y curl unzip && curl -fsSL https://fnm.vercel.app/install | bash && export PATH="/$HOME/.local/share/fnm:$PATH" && eval "`fnm env`" && fnm install v20.5.1 && fnm use v20.5.1 && npm -g i npm@latest - name: Install Deno and Bun run: npm install -g npm@latest; npm install -g bun deno-bin - name: Run tests - run: zig build test \ No newline at end of file + run: zig build test diff --git a/README.md b/README.md index 39c4266..29ccc42 100644 --- a/README.md +++ b/README.md @@ -4,38 +4,18 @@ Kivi is a high-performance in-memory key-value database written in the Zig progr > :warning: **Kivi is currently in development mode and not production-ready.** -## Latest benchmark: -``` -JsMap: -┌─────────┬─────────────────┬────────────────────┬───────────────────┐ -│ (index) │ totalLookupTime │ totalInsertionTime │ totalDeletionTime │ -├─────────┼─────────────────┼────────────────────┼───────────────────┤ -│ 0 │ '134.71 ms' │ '362.9 ms' │ '212.05 ms' │ -│ 1 │ '140.82 ms' │ '149.01 ms' │ '217.53 ms' │ -│ average │ '137.77 ms' │ '255.95 ms' │ '214.79 ms' │ -└─────────┴─────────────────┴────────────────────┴───────────────────┘ +## Latest benchmark +comparing Kivi to Javascript's builtin Map: +| Runtime | FFI | Lookup | Insertion | Deletion | +|---------|------|--------------|--------------|--------------| +| NodeJs | Napi | 2x slower | 1.2x faster | 1.9x slower | +| Deno | Napi | 1.47x slower | 2.48x slower | 1.44x slower | +| Deno | FFI | 6.89x slower | 4.07x slower | 7.73x slower | +| Bun | Napi | 1.06x faster | 1.23 faster | 1.08x slower | +| Bun | FFI | 1.64x slower | 1.3x slower | 1.97x slower | -Kivi: -┌─────────┬─────────────────┬────────────────────┬───────────────────┐ -│ (index) │ totalLookupTime │ totalInsertionTime │ totalDeletionTime │ -├─────────┼─────────────────┼────────────────────┼───────────────────┤ -│ 0 │ '916.68 ms' │ '225.9 ms' │ '976.8 ms' │ -│ 1 │ '907.01 ms' │ '217.65 ms' │ '1017.35 ms' │ -│ average │ '911.84 ms' │ '221.78 ms' │ '997.08 ms' │ -└─────────┴─────────────────┴────────────────────┴───────────────────┘ - - This table shows how much JsMap is faster than Kivi: -┌───────────┬─────────┐ -│ (index) │ Values │ -├───────────┼─────────┤ -│ lookup │ '6.62x' │ -│ insertion │ '0.85x' │ -│ deletion │ '4.64x' │ -└───────────┴─────────┘ -``` - -## Code of conduct: +## Code of conduct You can check our [code of conduct guidelines](CODE_OF_CONDUCT.md). -## License: +## License Kivi is licensed under MIT. Head over to [LICENSE](LICENSE) for full description. diff --git a/bench/bench-with-builtin.js b/bench/bench-with-builtin.js index d9ae764..df28ecb 100644 --- a/bench/bench-with-builtin.js +++ b/bench/bench-with-builtin.js @@ -1,11 +1,16 @@ import { Kivi } from "../src/drivers/js/index.js"; +import { isBun, isDeno } from "../src/drivers/js/runtime.js"; import { generateFakeData } from "./faker/generate.js"; +import { Buffer } from "node:buffer"; const repeatBenchmark = 2; const data = generateFakeData(); const assert = (name, left, right) => { - if (!left.equals(right)) { + if ( + Buffer.from(left, "utf8").subarray(0, right.length).toString() !== + right.toString() + ) { throw new Error( `Assertion '${name}' failed! Left was '${left.toString()}' and right was '${right.toString()}'.` ); @@ -13,13 +18,6 @@ const assert = (name, left, right) => { }; const roundToTwoDecimal = (num) => +(Math.round(num + "e+2") + "e-2"); -const benchmarkRemove = (data, o, keyidx) => { - const startingTime = performance.now(); - for (const item of data) { - o.rm(item[keyidx]); - } - return performance.now() - startingTime; -}; const benchmarkDeletion = (data, o, keyidx) => { const startingTime = performance.now(); for (const item of data) { @@ -48,7 +46,6 @@ const wrapInHumanReadable = (value) => { totalLookupTime: roundToTwoDecimal(value.totalLookupTime) + " ms", totalInsertionTime: roundToTwoDecimal(value.totalInsertionTime) + " ms", totalDeletionTime: roundToTwoDecimal(value.totalDeletionTime) + " ms", - totalRemoveTime: roundToTwoDecimal(value.totalRemoveTime) + " ms", }; }; const formatLogResult = (value) => { @@ -56,7 +53,6 @@ const formatLogResult = (value) => { totalLookupTime: value.lookupDuration, totalInsertionTime: value.insertionDuration, totalDeletionTime: value.deletionDuration, - totalRemoveTime: value.removeDuration, }; }; const logResults = (name, durationArr, averageArg) => { @@ -71,7 +67,6 @@ const logResults = (name, durationArr, averageArg) => { totalLookupTime: average.totalLookupTime, totalInsertionTime: average.totalInsertionTime, totalDeletionTime: average.totalDeletionTime, - totalRemoveTime: average.totalRemoveTime, }); console.log(`\n${name}:`); @@ -80,36 +75,32 @@ const logResults = (name, durationArr, averageArg) => { average: wrapInHumanReadable(average), }); }; -const logRatio = () => { +const logRatio = (index1, index2) => { console.log( - `\n This table shows how much ${averageLogResult[0].name} is faster than ${averageLogResult[1].name}:` + `\n This table shows how much ${averageLogResult[index1].name} is faster than ${averageLogResult[index2].name}:` ); console.table({ lookup: roundToTwoDecimal( - averageLogResult[1].totalLookupTime / - averageLogResult[0].totalLookupTime + averageLogResult[index2].totalLookupTime / + averageLogResult[index1].totalLookupTime ) + "x", insertion: roundToTwoDecimal( - averageLogResult[1].totalInsertionTime / - averageLogResult[0].totalInsertionTime + averageLogResult[index2].totalInsertionTime / + averageLogResult[index1].totalInsertionTime ) + "x", deletion: roundToTwoDecimal( - averageLogResult[1].totalDeletionTime / - averageLogResult[0].totalDeletionTime - ) + "x", - remove: - roundToTwoDecimal( - averageLogResult[1].totalRemoveTime / - averageLogResult[0].totalRemoveTime + averageLogResult[index2].totalDeletionTime / + averageLogResult[index1].totalDeletionTime ) + "x", }); }; const builtinMapBenchmark = () => { + const name = "JsMap"; const durationArr = []; let average = { insertionDuration: 0, @@ -118,7 +109,7 @@ const builtinMapBenchmark = () => { }; for (let i = 0; i < repeatBenchmark; i++) { let o = { - name: "JsMap", + name, map: new Map(), get: function (k) { return this.map.get(k); @@ -126,9 +117,6 @@ const builtinMapBenchmark = () => { set: function (k, v) { return this.map.set(k, v); }, - rm: function (k) { - this.map.delete(k); - }, del: function (k) { const v = this.map.get(k); this.map.delete(k); @@ -141,34 +129,31 @@ const builtinMapBenchmark = () => { const insertionDuration = benchmarkInsertion(data, o, "key"); const lookupDuration = benchmarkLookup(data, o, "key"); const deletionDuration = benchmarkDeletion(data, o, "key"); - const removeDuration = benchmarkRemove(data, o, "key"); o.destroy(); durationArr.push({ iteration: i, insertionDuration, lookupDuration, deletionDuration, - removeDuration, }); if (average.insertionDuration === 0) { average = { insertionDuration, lookupDuration, deletionDuration, - removeDuration, }; } else { average = { insertionDuration: (average.insertionDuration + insertionDuration) / 2, lookupDuration: (average.lookupDuration + lookupDuration) / 2, deletionDuration: (average.deletionDuration + deletionDuration) / 2, - removeDuration: (average.removeDuration + removeDuration) / 2, }; } } - logResults("JsMap", durationArr, average); + logResults(name, durationArr, average); }; -const kiviBenchmark = () => { +const kiviBenchmark = (config) => { + const name = "Kivi " + (config.forceUseRuntimeFFI ? "FFI" : "Napi"); const durationArr = []; let average = { insertionDuration: 0, @@ -177,8 +162,8 @@ const kiviBenchmark = () => { }; for (let i = 0; i < repeatBenchmark; i++) { let o = { - name: "Kivi", - map: new Kivi(), + name, + map: new Kivi(config), get: function (k) { return this.map.get(k); }, @@ -188,9 +173,6 @@ const kiviBenchmark = () => { del: function (k) { return this.map.del(k); }, - rm: function (k) { - this.map.rm(k); - }, destroy: function () { return this.map.destroy(); }, @@ -198,35 +180,37 @@ const kiviBenchmark = () => { const insertionDuration = benchmarkInsertion(data, o, "kyb"); const lookupDuration = benchmarkLookup(data, o, "kyb"); const deletionDuration = benchmarkDeletion(data, o, "kyb"); - const removeDuration = benchmarkRemove(data, o, "kyb"); o.destroy(); durationArr.push({ iteration: i, insertionDuration, lookupDuration, deletionDuration, - removeDuration, }); if (average.insertionDuration === 0) { average = { insertionDuration, lookupDuration, deletionDuration, - removeDuration, }; } else { average = { insertionDuration: (average.insertionDuration + insertionDuration) / 2, lookupDuration: (average.lookupDuration + lookupDuration) / 2, deletionDuration: (average.deletionDuration + deletionDuration) / 2, - removeDuration: (average.removeDuration + removeDuration) / 2, }; } } - logResults("Kivi", durationArr, average); + logResults(name, durationArr, average); }; builtinMapBenchmark(); -kiviBenchmark(); -logRatio(); +kiviBenchmark({ forceUseRuntimeFFI: false }); +if (isDeno() || isBun()) { + kiviBenchmark({ forceUseRuntimeFFI: true }); + logRatio(0, 1); + logRatio(0, 2); +} else { + logRatio(0, 1); +} diff --git a/bench/faker/generate.js b/bench/faker/generate.js index 83cd8f0..aa13378 100644 --- a/bench/faker/generate.js +++ b/bench/faker/generate.js @@ -1,3 +1,5 @@ +import { Buffer } from "node:buffer"; + const count = 1_000_000; const genRandomNum = (min, max) => { diff --git a/bench/package.json b/bench/package.json index 692bfbe..036cad1 100644 --- a/bench/package.json +++ b/bench/package.json @@ -7,7 +7,7 @@ "scripts": { "nodejs-bench": "node bench-with-builtin.js", "bun-bench": " bun run bench-with-builtin.js", - "deno-bench": "deno run --unstable --allow-all --v8-flags='--max-heap-size=2000,--max-old-space-size=2000' bench-with-builtin.js" + "deno-bench": "deno run --unstable --allow-all bench-with-builtin.js" }, "author": "", "license": "ISC", diff --git a/build.zig b/build.zig index 6633cda..62368c3 100644 --- a/build.zig +++ b/build.zig @@ -113,24 +113,16 @@ inline fn run_npm_command( dependency_steps: anytype, runner_step: *std.Build.Step, ) void { - var last_step: ?std.Build.Step = null; inline for (commands, 0..) |command, idx| { const syscommand = b.addSystemCommand(&[3][]const u8{ "pnpm", "run", command }); syscommand.cwd = get_lazypath(dir); - if (last_step) |step| { - var mutable_step = step; - syscommand.step.dependOn(&mutable_step); - } else { - inline for (dependency_steps) |dependency_step| { - syscommand.step.dependOn(dependency_step); - } + inline for (dependency_steps) |dependency_step| { + syscommand.step.dependOn(dependency_step); } if (idx == commands.len - 1) { runner_step.dependOn(&syscommand.step); } - - last_step = syscommand.step; } } @@ -225,8 +217,8 @@ pub fn build(b: *std.Build) !void { "src/drivers/js", .{ "nodejs-test", - // "deno-test", - // "bun-test", + "deno-test", + "bun-test", }, .{ drivers_build_step, ffi_tests_step }, test_step, @@ -239,10 +231,10 @@ pub fn build(b: *std.Build) !void { "bench", .{ "nodejs-bench", - // "deno-bench", - // "bun-bench", + "deno-bench", + "bun-bench", }, - .{drivers_build_step}, + .{ core_build_step, drivers_build_step }, bench_step, ); } diff --git a/src/core/Kivi.zig b/src/core/Kivi.zig index 05ed3e2..120f82e 100644 --- a/src/core/Kivi.zig +++ b/src/core/Kivi.zig @@ -17,7 +17,10 @@ mem_allocator: std.mem.Allocator, const Kivi = @This(); -inline fn stringcpy(dest: []u8, src: []const u8) void { +inline fn stringcpy(dest: []u8, src: []const u8) !void { + if (dest.len < src.len) { + return error.SmallDestMemory; + } @memcpy(dest[0..src.len], src); } @@ -44,8 +47,8 @@ pub fn putEntry(self: *Kivi, key: []u8, value: []u8) !void { pub fn set(self: *Kivi, key: []const u8, value: []const u8) !usize { const key_slice = try self.reserve_key(key.len); const value_slice = try self.reserve_value(value.len); - stringcpy(key_slice, key); - stringcpy(value_slice, value); + try stringcpy(key_slice, key); + try stringcpy(value_slice, value); try self.putEntry(key_slice, value_slice); @@ -63,7 +66,7 @@ pub fn get(self: *const Kivi, key: []const u8, value: ?[]u8) !usize { const value_slice = try self.get_slice(key); if (value != null) { - stringcpy(value.?, value_slice); + try stringcpy(value.?, value_slice); } return value_slice.len; @@ -84,7 +87,7 @@ pub fn del(self: *Kivi, key: []const u8, value: ?[]u8) !usize { const value_slice_len = value_slice.len; if (value != null) { - stringcpy(value.?, value_slice); + try stringcpy(value.?, value_slice); } self.del_value(value_slice); diff --git a/src/drivers/js/deno&bun/bun.js b/src/drivers/js/deno&bun/bun.js index d51b787..4490da2 100644 --- a/src/drivers/js/deno&bun/bun.js +++ b/src/drivers/js/deno&bun/bun.js @@ -1,5 +1,6 @@ import os from "node:os"; import path from "node:path"; +import { Buffer } from "node:buffer"; import { dlopen, FFIType, suffix, ptr } from "bun:ffi"; export const machine = os.machine(); @@ -15,7 +16,7 @@ const dllPath = path.join( __dirname, `../../../../zig-out/lib/${libNamePrefix}kivi-${machine}-${platform}.${suffix}` ); -export const dlopenLib = dlopen(dllPath, { +export const lib = dlopen(dllPath, { kivi_init: { args: [FFIType.ptr, FFIType.ptr], returns: FFIType.u32, @@ -58,9 +59,86 @@ export const dlopenLib = dlopen(dllPath, { }, }); -export const bunUtils = { - makeBufferPtr: function (value) { - return ptr(value); - }, - symbols: dlopenLib.symbols, -}; +export class BunKivi { + #selfbuf = new ArrayBuffer(72); + #self = ptr(this.#selfbuf); + + value_scratch_buf = new Buffer.alloc(4096); + value_scratch = ptr(this.value_scratch_buf); + + temp_buf; + + init() { + return lib.symbols.kivi_init(this.#self, null); + } + destroy() { + return lib.symbols.kivi_deinit(this.#self); + } + + get(key) { + const written_len = lib.symbols.kivi_get( + this.#self, + ptr(key), + key.length, + this.value_scratch, + this.value_scratch_buf.length + ); + if (written_len) { + return this.value_scratch_buf; + } else { + if (written_len > this.value_scratch_buf.length) { + this.temp_buf = Buffer.alloc(written_len); + lib.symbols.kivi_get( + this.#self, + ptr(key), + key.length, + ptr(this.temp_buf), + this.temp_buf.length + ); + return this.temp_buf; + } + } + return null; + } + set(key, value) { + if ( + !lib.symbols.kivi_set( + this.#self, + ptr(key), + key.length, + ptr(value), + value.length + ) + ) { + throw new Error("Out of memory!"); + } + } + del(key) { + const written_len = lib.symbols.kivi_del( + this.#self, + ptr(key), + key.length, + this.value_scratch, + this.value_scratch_buf.length + ); + if (written_len) { + return this.value_scratch_buf; + } else { + if (written_len > this.value_scratch_buf.length) { + this.temp_buf = Buffer.alloc(written_len); + lib.symbols.kivi_get( + this.#self, + ptr(key), + key.length, + ptr(this.temp_buf), + this.temp_buf.length + ); + return this.temp_buf; + } + } + return null; + } + rm(key) { + lib.symbols.kivi_rm(this.#self, ptr(key), key.length); + } +} diff --git a/src/drivers/js/deno&bun/deno.js b/src/drivers/js/deno&bun/deno.js index ba6c8ea..2355e6d 100644 --- a/src/drivers/js/deno&bun/deno.js +++ b/src/drivers/js/deno&bun/deno.js @@ -1,5 +1,4 @@ -import path from "node:path"; -import { fileURLToPath } from "node:url"; +import { Buffer } from "node:buffer"; let suffix = ""; switch (Deno.build.os) { @@ -13,10 +12,9 @@ switch (Deno.build.os) { suffix = "so"; break; } - export const machine = Deno.build.arch; export let platform = Deno.build.os; -let libNamePrefix = "lib"; +export let libNamePrefix = "lib"; if (platform == "win32") { platform = "windows"; } @@ -28,7 +26,8 @@ const dllPath = new URL( `../../../../zig-out/lib/${libNamePrefix}kivi-${machine}-${platform}.${suffix}` ) ); -export const dlopenLib = Deno.dlopen(dllPath, { + +const lib = Deno.dlopen(dllPath, { kivi_init: { parameters: ["pointer", "pointer"], result: "u32" }, kivi_deinit: { parameters: ["pointer"], result: "void" }, kivi_get: { @@ -49,9 +48,86 @@ export const dlopenLib = Deno.dlopen(dllPath, { }, }); -export const denoUtils = { - makeBufferPtr: function (value) { - return Deno.UnsafePointer.of(value); - }, - symbols: dlopenLib.symbols, -}; +export class DenoKivi { + #selfbuf = new ArrayBuffer(72); + #self = Deno.UnsafePointer.of(this.#selfbuf); + + value_scratch_buf = new Buffer.alloc(4096); + value_scratch = Deno.UnsafePointer.of(this.value_scratch_buf); + + temp_buf; + + init() { + return lib.symbols.kivi_init(this.#self, null); + } + destroy() { + return lib.symbols.kivi_deinit(this.#self); + } + + get(key) { + const written_len = lib.symbols.kivi_get( + this.#self, + Deno.UnsafePointer.of(key), + key.length, + this.value_scratch, + this.value_scratch_buf.length + ); + if (written_len) { + return this.value_scratch_buf; + } else { + if (written_len > this.value_scratch_buf.length) { + this.temp_buf = Buffer.alloc(written_len); + lib.symbols.kivi_get( + this.#self, + Deno.UnsafePointer.of(key), + key.length, + Deno.UnsafePointer.of(this.temp_buf), + this.temp_buf.length + ); + return this.temp_buf; + } + } + return null; + } + set(key, value) { + if ( + !lib.symbols.kivi_set( + this.#self, + Deno.UnsafePointer.of(key), + key.length, + Deno.UnsafePointer.of(value), + value.length + ) + ) { + throw new Error("Out of memory!"); + } + } + del(key) { + const written_len = lib.symbols.kivi_del( + this.#self, + Deno.UnsafePointer.of(key), + key.length, + this.value_scratch, + this.value_scratch_buf.length + ); + if (written_len) { + return this.value_scratch_buf; + } else { + if (written_len > this.value_scratch_buf.length) { + this.temp_buf = Buffer.alloc(written_len); + lib.symbols.kivi_get( + this.#self, + Deno.UnsafePointer.of(key), + key.length, + Deno.UnsafePointer.of(this.temp_buf), + this.temp_buf.length + ); + return this.temp_buf; + } + } + return null; + } + rm(key) { + lib.symbols.kivi_rm(this.#self, Deno.UnsafePointer.of(key), key.length); + } +} diff --git a/src/drivers/js/deno&bun/index.js b/src/drivers/js/deno&bun/index.js deleted file mode 100644 index 916b972..0000000 --- a/src/drivers/js/deno&bun/index.js +++ /dev/null @@ -1,122 +0,0 @@ -const { isBun, isDeno } = await import("../runtime.js"); - -let utils = undefined; -export let machine = undefined; -export let platform = undefined; -if (isBun()) { - const { - bunUtils, - machine: bunMachine, - platform: bunPlatform, - } = await import("./bun.js"); - utils = bunUtils; - machine = bunMachine; - platform = bunPlatform; -} else if (isDeno()) { - const { - denoUtils, - machine: denoMachine, - platform: denoPlatform, - } = await import("./deno.js"); - utils = denoUtils; - machine = denoMachine; - platform = denoPlatform; -} - -export class DenoAndBunKivi { - #array_buf = new ArrayBuffer(72); - #buf = utils.makeBufferPtr(this.#array_buf); - - #key_scratch = new Uint8Array(4096); - #key_scratch_ptr = utils.makeBufferPtr(this.#key_scratch); - - #value_scratch = new Uint8Array(4096); - #value_scratch_ptr = utils.makeBufferPtr(this.#value_scratch); - - init() { - return utils.symbols.kivi_init(this.#buf, null); - } - destroy() { - return utils.symbols.kivi_deinit(this.#buf); - } - - get(key) { - const encoded_str = new TextEncoder().encodeInto(key, this.#key_scratch); - const written_len = utils.symbols.kivi_get( - this.#buf, - this.#key_scratch_ptr, - encoded_str.written, - this.#value_scratch_ptr, - 4096 - ); - - if (written_len != 0) { - return new TextDecoder().decode( - this.#value_scratch.subarray(0, written_len) - ); - } - - return null; - } - set(key, value) { - const key_len = new TextEncoder().encodeInto( - key, - this.#key_scratch - ).written; - const value_len = new TextEncoder().encodeInto( - value, - this.#value_scratch - ).written; - - return utils.symbols.kivi_set( - this.#buf, - this.#key_scratch_ptr, - key_len, - this.#value_scratch_ptr, - value_len - ); - } - del(key) { - const key_len = new TextEncoder().encodeInto( - key, - this.#key_scratch - ).written; - const written_len = utils.symbols.kivi_del( - this.#buf, - this.#key_scratch_ptr, - key_len, - this.#value_scratch_ptr, - 4096 - ); - - if (written_len != 0) { - return new TextDecoder().decode( - this.#value_scratch.subarray(0, written_len) - ); - } - - return null; - } - - rm(key) { - const key_len = new TextEncoder().encodeInto( - key, - this.#key_scratch - ).written; - const written_len = utils.symbols.kivi_del( - this.#buf, - this.#key_scratch_ptr, - key_len, - this.#value_scratch_ptr, - 4096 - ); - - if (written_len != 0) { - return new TextDecoder().decode( - this.#value_scratch.subarray(0, written_len) - ); - } - - return null; - } -} diff --git a/src/drivers/js/index.js b/src/drivers/js/index.js index 2552931..1c5b8b9 100644 --- a/src/drivers/js/index.js +++ b/src/drivers/js/index.js @@ -19,14 +19,22 @@ const { getRuntimeKind } = await import( ); switch (getRuntimeKind()) { case "bun": + const { BunKivi } = await import( + path.resolve( + path.dirname(fileURLToPath(import.meta.url)), + "./deno&bun/bun.js" + ) + ); + RuntimeKivi = BunKivi; + break; case "deno": - const { DenoAndBunKivi } = await import( + const { DenoKivi } = await import( path.resolve( path.dirname(fileURLToPath(import.meta.url)), - "./deno&bun/index.js" + "./deno&bun/deno.js" ) ); - RuntimeKivi = DenoAndBunKivi; + RuntimeKivi = DenoKivi; break; case "node": RuntimeKivi = NodeKivi; diff --git a/src/drivers/js/nodejs/index.js b/src/drivers/js/nodejs/index.js index 797a055..ee05481 100644 --- a/src/drivers/js/nodejs/index.js +++ b/src/drivers/js/nodejs/index.js @@ -1,7 +1,7 @@ import path from "node:path"; import { fileURLToPath } from "node:url"; import { createRequire } from "node:module"; -import { isNodeJS } from "../runtime.js"; +import { isDeno, isNodeJS, isBun } from "../runtime.js"; const require = createRequire(import.meta.url); @@ -12,15 +12,25 @@ if (isNodeJS()) { machine = os.machine(); platform = os.platform(); } else { - const { machine: denoOrBunMachine, platform: denoOrBunPlatform } = - await import( + if (isBun()) { + const { machine: bunMachine, platform: bunPlatform } = await import( path.resolve( path.dirname(fileURLToPath(import.meta.url)), - "../deno&bun/index.js" + "../deno&bun/bun.js" ) ); - machine = denoOrBunMachine; - platform = denoOrBunPlatform; + machine = bunMachine; + platform = bunPlatform; + } else if (isDeno()) { + const { machine: denoMachine, platform: denoPlatform } = await import( + path.resolve( + path.dirname(fileURLToPath(import.meta.url)), + "../deno&bun/deno.js" + ) + ); + machine = denoMachine; + platform = denoPlatform; + } } if (platform == "win32") { platform = "windows"; diff --git a/src/drivers/js/tests/kivi.js b/src/drivers/js/tests/kivi.js index 82a8022..75dc594 100644 --- a/src/drivers/js/tests/kivi.js +++ b/src/drivers/js/tests/kivi.js @@ -1,9 +1,13 @@ import { Kivi } from "../index.js"; +import { Buffer } from "node:buffer"; const run = (config) => { const assert = (name, left, right) => { if (Buffer.isBuffer(left) && Buffer.isBuffer(right)) { - if (left.toString("utf8") == right.toString("utf8")) { + if ( + left.subarray(0, right.length).toString("utf8") == + right.toString("utf8") + ) { return; } } else {