Files
bun.sh/src/bun.js/api/HashObject.zig

145 lines
5.4 KiB
Zig

pub const wyhash = hashWrap(std.hash.Wyhash);
pub const adler32 = hashWrap(std.hash.Adler32);
pub const crc32 = hashWrap(std.hash.Crc32);
pub const cityHash32 = hashWrap(std.hash.CityHash32);
pub const cityHash64 = hashWrap(std.hash.CityHash64);
pub const xxHash32 = hashWrap(struct {
pub fn hash(seed: u32, bytes: []const u8) u32 {
// sidestep .hash taking in anytype breaking ArgTuple
// downstream by forcing a type signature on the input
return std.hash.XxHash32.hash(seed, bytes);
}
});
pub const xxHash64 = hashWrap(struct {
pub fn hash(seed: u32, bytes: []const u8) u64 {
// sidestep .hash taking in anytype breaking ArgTuple
// downstream by forcing a type signature on the input
return std.hash.XxHash64.hash(seed, bytes);
}
});
pub const xxHash3 = hashWrap(struct {
pub fn hash(seed: u32, bytes: []const u8) u64 {
// sidestep .hash taking in anytype breaking ArgTuple
// downstream by forcing a type signature on the input
return std.hash.XxHash3.hash(seed, bytes);
}
});
pub const murmur32v2 = hashWrap(std.hash.murmur.Murmur2_32);
pub const murmur32v3 = hashWrap(std.hash.murmur.Murmur3_32);
pub const murmur64v2 = hashWrap(std.hash.murmur.Murmur2_64);
pub fn create(globalThis: *JSC.JSGlobalObject) JSC.JSValue {
const function = JSC.createCallback(globalThis, ZigString.static("hash"), 1, wyhash);
const fns = comptime .{
"wyhash",
"adler32",
"crc32",
"cityHash32",
"cityHash64",
"xxHash32",
"xxHash64",
"xxHash3",
"murmur32v2",
"murmur32v3",
"murmur64v2",
};
inline for (fns) |name| {
const value = JSC.createCallback(
globalThis,
ZigString.static(name),
1,
@field(HashObject, name),
);
function.put(globalThis, comptime ZigString.static(name), value);
}
return function;
}
fn hashWrap(comptime Hasher_: anytype) JSC.JSHostFnZig {
return struct {
const Hasher = Hasher_;
pub fn hash(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSC.JSValue {
const arguments = callframe.arguments_old(2).slice();
var args = JSC.CallFrame.ArgumentsSlice.init(globalThis.bunVM(), arguments);
defer args.deinit();
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,
.Float16Array,
.Float32Array,
.Float64Array,
.BigInt64Array,
.BigUint64Array,
.DataView,
=> {
var array_buffer = arg.asArrayBuffer(globalThis) orelse {
return globalThis.throwInvalidArguments("ArrayBuffer conversion error", .{});
};
input = array_buffer.byteSlice();
},
else => {
input_slice = try arg.toSlice(globalThis, 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));
} else {
var seed: u64 = 0;
if (args.nextEat()) |arg| {
if (arg.isNumber() or arg.isBigInt()) {
seed = arg.toUInt64NoTruncate();
}
}
if (comptime bun.trait.isNumber(@TypeOf(function_args[0]))) {
function_args[0] = @as(@TypeOf(function_args[0]), @truncate(seed));
function_args[1] = input;
} else {
function_args[0] = input;
function_args[1] = @as(@TypeOf(function_args[1]), @truncate(seed));
}
const value = @call(.auto, Function, function_args);
if (@TypeOf(value) == u32) {
return JSC.JSValue.jsNumber(@as(u32, @bitCast(value)));
}
return JSC.JSValue.fromUInt64NoTruncate(globalThis, value);
}
}
}.hash;
}
const HashObject = @This();
const JSC = bun.JSC;
const JSValue = JSC.JSValue;
const JSGlobalObject = JSC.JSGlobalObject;
const JSObject = JSC.JSObject;
const std = @import("std");
const bun = @import("bun");
const ZigString = JSC.ZigString;