diff options
Diffstat (limited to 'src/bun.js/bindings/shimmer.zig')
-rw-r--r-- | src/bun.js/bindings/shimmer.zig | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/src/bun.js/bindings/shimmer.zig b/src/bun.js/bindings/shimmer.zig new file mode 100644 index 000000000..c180fc864 --- /dev/null +++ b/src/bun.js/bindings/shimmer.zig @@ -0,0 +1,190 @@ +const std = @import("std"); +const StaticExport = @import("./static_export.zig"); +const Sizes = @import("./sizes.zig"); +pub const is_bindgen: bool = std.meta.globalOption("bindgen", bool) orelse false; +const headers = @import("./headers.zig"); + +fn isNullableType(comptime Type: type) bool { + return @typeInfo(Type) == .Optional; +} + +pub fn Shimmer(comptime _namespace: []const u8, comptime _name: []const u8, comptime Parent: type) type { + return struct { + pub const namespace = _namespace; + pub const name = _name; + + pub fn ref() void { + if (comptime @hasDecl(Parent, "Export")) { + inline for (Parent.Export) |exp| { + _ = exp; + } + } + + if (comptime @hasDecl(Parent, "Extern")) { + inline for (Parent.Extern) |exp| { + _ = @field(Parent, exp); + } + } + } + + // fn toCppType(comptime FromType: type) type { + // var NewReturnType = FromType; + + // if (NewReturnType == anyopaque) { + // return FromType; + // } + + // var ReturnTypeInfo: std.builtin.TypeInfo = @typeInfo(FromType); + + // if (ReturnTypeInfo == .Pointer and NewReturnType != *anyopaque) { + // NewReturnType = ReturnTypeInfo.Pointer.child; + // ReturnTypeInfo = @typeInfo(NewReturnType); + // } + + // switch (ReturnTypeInfo) { + // .Union, + // .Struct, + // .Enum, + // => { + // if (@hasDecl(ReturnTypeInfo., "Type")) { + // return NewReturnType; + // } + // }, + // else => {}, + // } + + // return FromType; + // } + pub const align_of_symbol = std.fmt.comptimePrint("{s}__{s}_object_align_", .{ namespace, name }); + pub const size_of_symbol = std.fmt.comptimePrint("{s}__{s}_object_size_", .{ namespace, name }); + const align_symbol = std.fmt.comptimePrint("{s}__{s}_align", .{ namespace, name }); + + pub const byte_size = brk: { + const identifier = std.fmt.comptimePrint("{s}__{s}", .{ namespace, name }); + if (@hasDecl(Sizes, identifier)) { + break :brk @field(Sizes, identifier); + } else { + break :brk 0; + } + }; + + pub const align_size = brk: { + const identifier = std.fmt.comptimePrint("{s}__{s}_align", .{ namespace, name }); + if (@hasDecl(Sizes, identifier)) { + break :brk @field(Sizes, identifier); + } else { + break :brk 0; + } + }; + pub const Bytes = if (byte_size > 16) [byte_size]u8 else std.meta.Int(.unsigned, byte_size * 8); + + pub const Return = struct { + pub const Type = Parent; + pub const is_return = true; + }; + + fn pointerChild(comptime Type: type) type { + if (@typeInfo(Type) == .Pointer) { + return @typeInfo(Type).Pointer.child_type; + } + + return Type; + } + + pub fn symbolName(comptime typeName: []const u8) []const u8 { + if (comptime namespace.len > 0) { + return comptime std.fmt.comptimePrint("{s}__{s}__{s}", .{ namespace, name, typeName }); + } else { + return comptime std.fmt.comptimePrint("{s}__{s}", .{ name, typeName }); + } + } + + pub fn exportFunctions(comptime Functions: anytype) [std.meta.fieldNames(@TypeOf(Functions)).len]StaticExport { + const FunctionsType = @TypeOf(Functions); + return comptime brk: { + var functions: [std.meta.fieldNames(FunctionsType).len]StaticExport = undefined; + for (std.meta.fieldNames(FunctionsType)) |fn_name, i| { + const Function = @TypeOf(@field(Functions, fn_name)); + if (@typeInfo(Function) != .Fn) { + @compileError("Expected " ++ @typeName(Parent) ++ "." ++ @typeName(Function) ++ " to be a function but received " ++ @tagName(@typeInfo(Function))); + } + var Fn: std.builtin.TypeInfo.Fn = @typeInfo(Function).Fn; + if (Fn.calling_convention != .C) { + @compileError("Expected " ++ @typeName(Parent) ++ "." ++ @typeName(Function) ++ " to have a C Calling Convention."); + } + + const export_name = symbolName(fn_name); + functions[i] = StaticExport{ + .Type = Function, + .symbol_name = export_name, + .local_name = fn_name, + .Parent = Parent, + }; + } + + break :brk functions; + }; + } + + pub fn thenables(comptime Functions: anytype) [std.meta.fieldNames(@TypeOf(Functions)).len * 2]StaticExport { + const FunctionsType = @TypeOf(Functions); + return comptime brk: { + var functions: [std.meta.fieldNames(FunctionsType).len * 2]StaticExport = undefined; + var j: usize = 0; + inline for (Functions) |thenable| { + inline for ([_][]const u8{ "resolve", "reject" }) |fn_name| { + const Function = @TypeOf(@field(thenable, fn_name)); + if (@typeInfo(Function) != .Fn) { + @compileError("Expected " ++ @typeName(Parent) ++ "." ++ @typeName(Function) ++ " to be a function but received " ++ @tagName(@typeInfo(Function))); + } + var Fn: std.builtin.TypeInfo.Fn = @typeInfo(Function).Fn; + if (Fn.calling_convention != .C) { + @compileError("Expected " ++ @typeName(Parent) ++ "." ++ @typeName(Function) ++ " to have a C Calling Convention."); + } + + const export_name = symbolName(fn_name); + functions[j] = StaticExport{ + .Type = Function, + .symbol_name = export_name, + .local_name = fn_name, + .Parent = thenable, + }; + j += 1; + } + } + + break :brk functions; + }; + } + + pub inline fn matchNullable(comptime ExpectedReturnType: type, comptime ExternReturnType: type, value: ExternReturnType) ExpectedReturnType { + if (comptime isNullableType(ExpectedReturnType) != isNullableType(ExternReturnType)) { + return value.?; + } else if (comptime (@typeInfo(ExpectedReturnType) == .Enum) and (@typeInfo(ExternReturnType) != .Enum)) { + return @intToEnum(ExpectedReturnType, value); + } else { + return value; + } + } + + pub inline fn cppFn(comptime typeName: []const u8, args: anytype) (ret: { + @setEvalBranchQuota(99999); + if (!@hasDecl(Parent, typeName)) { + @compileError(@typeName(Parent) ++ " is missing cppFn: " ++ typeName); + } + break :ret @typeInfo(@TypeOf(@field(Parent, typeName))).Fn.return_type.?; + }) { + @setEvalBranchQuota(99999); + if (comptime is_bindgen) { + unreachable; + } else { + const Fn = comptime @field(headers, symbolName(typeName)); + return matchNullable( + comptime @typeInfo(@TypeOf(@field(Parent, typeName))).Fn.return_type.?, + comptime @typeInfo(@TypeOf(Fn)).Fn.return_type.?, + @call(.{}, Fn, args), + ); + } + } + }; +} |