diff options
-rw-r--r-- | integration/bunjs-only-snippets/hash.test.js | 28 | ||||
-rw-r--r-- | src/javascript/jsc/api/bun.zig | 132 |
2 files changed, 160 insertions, 0 deletions
diff --git a/integration/bunjs-only-snippets/hash.test.js b/integration/bunjs-only-snippets/hash.test.js new file mode 100644 index 000000000..c907002cc --- /dev/null +++ b/integration/bunjs-only-snippets/hash.test.js @@ -0,0 +1,28 @@ +import fs from "fs"; +import { it, expect } from "bun:test"; +import path from "path"; + +it(`Bun.hash()`, () => { + console.log(Bun.hash("hello world")); +}); +it(`Bun.hash.wyhash()`, () => { + console.log(Bun.hash.wyhash("hello world")); +}); +it(`Bun.hash.adler32()`, () => { + console.log(Bun.hash.adler32("hello world")); +}); +it(`Bun.hash.crc32()`, () => { + console.log(Bun.hash.crc32("hello world")); +}); +it(`Bun.hash.cityHash32()`, () => { + console.log(Bun.hash.cityHash32("hello world")); +}); +it(`Bun.hash.cityHash64()`, () => { + console.log(Bun.hash.cityHash64("hello world")); +}); +it(`Bun.hash.murmur32v3()`, () => { + console.log(Bun.hash.murmur32v3("hello world")); +}); +it(`Bun.hash.murmur64v2()`, () => { + console.log(Bun.hash.murmur64v2("hello world")); +}); diff --git a/src/javascript/jsc/api/bun.zig b/src/javascript/jsc/api/bun.zig index b43771f07..f408a95dc 100644 --- a/src/javascript/jsc/api/bun.zig +++ b/src/javascript/jsc/api/bun.zig @@ -1088,6 +1088,9 @@ pub const Class = NewClass( .get = getTranspilerConstructor, .ts = d.ts{ .name = "Transpiler", .@"return" = "Transpiler.prototype" }, }, + .hash = .{ + .get = getHashObject, + }, .TOML = .{ .get = getTOMLObject, .ts = d.ts{ .name = "TOML", .@"return" = "TOML.prototype" }, @@ -1227,6 +1230,135 @@ pub fn getTranspilerConstructor( return existing.asObjectRef(); } +pub fn getHashObject( + _: void, + ctx: js.JSContextRef, + _: js.JSValueRef, + _: js.JSStringRef, + _: js.ExceptionRef, +) js.JSValueRef { + var existing = ctx.ptr().getCachedObject(&ZigString.init("BunHash")); + if (existing.isEmpty()) { + return ctx.ptr().putCachedObject( + &ZigString.init("BunHash"), + JSC.JSValue.fromRef(JSC.C.JSObjectMake(ctx, Hash.Class.get().*, null)), + ).asObjectRef(); + } + + return existing.asObjectRef(); +} + +pub const Hash = struct { + pub const Class = NewClass( + void, + .{ + .name = "Hash", + }, + .{ + .call = .{ + .rfn = call, + }, + .wyhash = .{ + .rfn = hashWrap(std.hash.Wyhash).hash, + }, + .adler32 = .{ + .rfn = hashWrap(std.hash.Adler32).hash, + }, + .crc32 = .{ + .rfn = hashWrap(std.hash.Crc32).hash, + }, + .cityHash32 = .{ + .rfn = hashWrap(std.hash.CityHash32).hash, + }, + .cityHash64 = .{ + .rfn = hashWrap(std.hash.CityHash64).hash, + }, + .murmur32v3 = .{ + .rfn = hashWrap(std.hash.murmur.Murmur3_32).hash, + }, + .murmur64v2 = .{ + .rfn = hashWrap(std.hash.murmur.Murmur2_64).hash, + }, + .murmur64v2 = .{ + .rfn = hashWrap(std.hash.murmur.Murmur2_64).hash, + }, + }, + .{}, + ); + + pub fn call( + _: void, + ctx: js.JSContextRef, + _: js.JSObjectRef, + _: js.JSObjectRef, + arguments: []const js.JSValueRef, + exception: js.ExceptionRef, + ) js.JSObjectRef { + return hashWrap(std.hash.Wyhash).hash(void{}, ctx, null, null, arguments, exception); + } + fn hashWrap(comptime Hasher: anytype) type { + return struct { + pub fn hash( + _: void, + ctx: js.JSContextRef, + _: js.JSObjectRef, + _: js.JSObjectRef, + arguments: []const js.JSValueRef, + exception: js.ExceptionRef, + ) js.JSValueRef { + var args = JSC.Node.ArgumentsSlice.from(arguments); + var input: []const u8 = ""; + var input_slice = ZigString.Slice.empty; + defer input_slice.deinit(); + if (args.nextEat()) |arg| { + if (arg.as(JSC.WebCore.Blob)) |blob| { + // TODO: files + input = blob.sharedView(); + } else { + switch (arg.jsTypeLoose()) { + .ArrayBuffer, .Int8Array, .Uint8Array, .Uint8ClampedArray, .Int16Array, .Uint16Array, .Int32Array, .Uint32Array, .Float32Array, .Float64Array, .BigInt64Array, .BigUint64Array, .DataView => { + var array_buffer = arg.asArrayBuffer(ctx.ptr()) orelse { + JSC.throwInvalidArguments("ArrayBuffer conversion error", .{}, ctx, exception); + return null; + }; + input = array_buffer.slice(); + }, + else => { + input_slice = arg.toSlice(ctx.ptr(), bun.default_allocator); + input = input_slice.slice(); + }, + } + } + } + + // std.hash has inconsistent interfaces + // + const Function = if (@hasDecl(Hasher, "hashWithSeed")) Hasher.hashWithSeed else Hasher.hash; + var function_args: std.meta.ArgsTuple(@TypeOf(Function)) = undefined; + if (comptime std.meta.fields(std.meta.ArgsTuple(@TypeOf(Function))).len == 1) { + return JSC.JSValue.jsNumber(Function(input)).asObjectRef(); + } else { + var seed: u64 = 0; + if (args.nextEat()) |arg| { + if (arg.isNumber()) { + seed = arg.toU32(); + } + } + if (comptime std.meta.trait.isNumber(@TypeOf(function_args[0]))) { + function_args[0] = @intCast(@TypeOf(function_args[0]), seed); + function_args[1] = input; + } else { + function_args[1] = @intCast(@TypeOf(function_args[1]), seed); + function_args[0] = input; + } + + return JSC.JSValue.jsNumber(@call(.{}, Function, function_args)).asObjectRef(); + } + } + }; + } +}; + pub fn getTOMLObject( _: void, ctx: js.JSContextRef, |