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; // 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 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 std.meta.declarationInfo(Parent, typeName).data.Fn.return_type; }) { @setEvalBranchQuota(99999); if (comptime is_bindgen) { unreachable; } else { const Fn = comptime @field(headers, symbolName(typeName)); return matchNullable( comptime std.meta.declarationInfo(Parent, typeName).data.Fn.return_type, comptime @typeInfo(@TypeOf(Fn)).Fn.return_type.?, @call(.{}, Fn, args), ); } } }; }