diff options
author | 2021-07-21 02:07:07 -0700 | |
---|---|---|
committer | 2021-07-21 02:07:07 -0700 | |
commit | a8a4f280469d4d3baf8ea6e9dbce9ec06bd3d868 (patch) | |
tree | 8a10690daafe99a8d908119f9bb855cd0f3d368a /src/javascript/jsc/bindings/header-gen.zig | |
parent | f2ea2027300949b919f9d595ce3039c8bc82d21a (diff) | |
download | bun-a8a4f280469d4d3baf8ea6e9dbce9ec06bd3d868.tar.gz bun-a8a4f280469d4d3baf8ea6e9dbce9ec06bd3d868.tar.zst bun-a8a4f280469d4d3baf8ea6e9dbce9ec06bd3d868.zip |
most of the bindings!
Diffstat (limited to 'src/javascript/jsc/bindings/header-gen.zig')
-rw-r--r-- | src/javascript/jsc/bindings/header-gen.zig | 559 |
1 files changed, 444 insertions, 115 deletions
diff --git a/src/javascript/jsc/bindings/header-gen.zig b/src/javascript/jsc/bindings/header-gen.zig index 6155c5d1a..7b664785d 100644 --- a/src/javascript/jsc/bindings/header-gen.zig +++ b/src/javascript/jsc/bindings/header-gen.zig @@ -6,16 +6,71 @@ const StructMeta = std.builtin.TypeInfo.Struct; const EnumMeta = std.builtin.TypeInfo.Enum; const UnionMeta = std.builtin.TypeInfo.Union; const warn = std.debug.warn; +const StaticExport = @import("./static_export.zig"); + +const TypeNameMap = std.StringHashMap([]const u8); fn isCppObject(comptime Type: type) bool { return switch (@typeInfo(Type)) { .Struct, .Union, .Opaque => true, + .Enum => |Enum| @hasDecl(Type, "Type"), else => false, }; } +pub fn cTypeLabel(comptime Type: type) ?[]const u8 { + return switch (comptime Type) { + void => "void", + bool => "bool", + usize => "size_t", + isize => "int", + u8 => "char", + u16 => "uint16_t", + u32 => "uint32_t", + u64 => "uint64_t", + i8 => "int8_t", + i16 => "int16_t", + i24 => "int24_t", + i32 => "int32_t", + i64 => "int64_t", + f64 => "double", + f32 => "float", + *c_void => "void*", + [*]bool => "bool*", + [*]usize => "size_t*", + [*]isize => "int*", + [*]u8 => "char*", + [*]u16 => "uint16_t*", + [*]u32 => "uint32_t*", + [*]u64 => "uint64_t*", + [*]i8 => "int8_t*", + [*]i16 => "int16_t*", + [*]i32 => "int32_t*", + [*]i64 => "int64_t*", + [*]const bool => "const bool*", + [*]const usize => "const size_t*", + [*]const isize => "const int*", + [*]const u8 => "const char*", + [*]const u16 => "const uint16_t*", + [*]const u32 => "const uint32_t*", + [*]const u64 => "const uint64_t*", + [*]const i8 => "const int8_t*", + [*]const i16 => "const int16_t*", + [*]const i32 => "const int32_t*", + [*]const i64 => "const int64_t*", + else => null, + }; +} + +var buffer = std.ArrayList(u8).init(std.heap.c_allocator); +var writer = buffer.writer(); +var impl_buffer = std.ArrayList(u8).init(std.heap.c_allocator); +var impl_writer = impl_buffer.writer(); +var bufset = std.BufSet.init(std.heap.c_allocator); +var type_names = TypeNameMap.init(std.heap.c_allocator); +var size_map = std.StringHashMap(u32).init(std.heap.c_allocator); + pub const C_Generator = struct { - file: std.fs.File, filebase: []const u8, direction: Direction = .export_cpp, @@ -26,8 +81,8 @@ pub const C_Generator = struct { export_zig, }; - pub fn init(comptime src_file: []const u8, file: std.fs.File) Self { - var res = Self{ .file = file, .filebase = src_file }; + pub fn init(comptime src_file: []const u8, comptime Writer: type, file: Writer) Self { + var res = Self{ .filebase = src_file }; return res; } @@ -38,7 +93,13 @@ pub const C_Generator = struct { // self.file.writeAll("> ****/\n\n") catch unreachable; } - pub fn gen_func(self: *Self, comptime name: []const u8, comptime func: FnDecl, comptime meta: FnMeta, comptime arg_names: []const []const u8) void { + pub fn gen_func( + self: *Self, + comptime name: []const u8, + comptime func: FnDecl, + comptime meta: FnMeta, + comptime arg_names: []const []const u8, + ) void { switch (meta.calling_convention) { .Naked => self.write("__attribute__((naked)) "), .Stdcall => self.write("__attribute__((stdcall)) "), @@ -48,26 +109,38 @@ pub const C_Generator = struct { } switch (self.direction) { - .export_cpp => self.write("CPP_DECL \"C\" "), - .export_zig => self.write("ZIG_DECL \"C\" "), + .export_cpp => self.write("CPP_DECL "), + .export_zig => self.write("ZIG_DECL "), } self.writeType(func.return_type); self.write(" " ++ name ++ "("); inline for (meta.args) |arg, i| { - self.writeType(arg.arg_type.?); - if (func.arg_names.len > i) { - self.write(comptime arg_names[i]); - } else { - const ArgType = arg.arg_type.?; - if (@typeInfo(ArgType) == .Enum) { - self.write(comptime std.fmt.comptimePrint(" {s}{d}", .{ @typeName(ArgType), i })); - } else { - self.write(comptime std.fmt.comptimePrint(" arg{d}", .{i})); - } + const ArgType = arg.arg_type.?; + + switch (@typeInfo(ArgType)) { + .Fn => { + self.gen_closure(comptime arg.arg_type.?, comptime std.fmt.comptimePrint(" ArgFn{d}", .{i})); + }, + else => { + self.writeType(arg.arg_type.?); + switch (@typeInfo(ArgType)) { + .Enum => { + self.write(comptime std.fmt.comptimePrint(" {s}{d}", .{ @typeName(ArgType), i })); + }, + + else => { + self.write(comptime std.fmt.comptimePrint(" arg{d}", .{i})); + }, + } + }, } + // if (comptime func.arg_names.len > 0 and func.arg_names.len > i) { + // self.write(comptime arg_names[i]); + // } else { + //TODO: Figure out how to get arg names; for now just do arg0..argN if (i != meta.args.len - 1) self.write(", "); @@ -85,6 +158,43 @@ pub const C_Generator = struct { // } } + pub fn gen_closure( + self: *Self, + comptime Function: type, + comptime name: []const u8, + ) void { + const func: std.builtin.TypeInfo.Fn = @typeInfo(Function).Fn; + self.writeType(func.return_type orelse void); + self.write(" (*" ++ name ++ ")("); + inline for (func.args) |arg, i| { + self.writeType(arg.arg_type.?); + // if (comptime func.arg_names.len > 0 and func.arg_names.len > i) { + // self.write(comptime arg_names[i]); + // } else { + const ArgType = arg.arg_type.?; + if (@typeInfo(ArgType) == .Enum) { + self.write(comptime std.fmt.comptimePrint(" {s}{d}", .{ @typeName(ArgType), i })); + } else { + self.write(comptime std.fmt.comptimePrint(" arg{d}", .{i})); + } + // } + + //TODO: Figure out how to get arg names; for now just do arg0..argN + if (i != func.args.len - 1) + self.write(", "); + } + + self.write(")"); + // const ReturnTypeInfo: std.builtin.TypeInfo = comptime @typeInfo(func.return_type); + // switch (comptime ReturnTypeInfo) { + // .Pointer => |Pointer| { + // self.write(" __attribute__((returns_nonnull))"); + // }, + // .Optional => |Optional| {}, + // else => {}, + // } + } + pub fn gen_struct(self: *Self, comptime name: []const u8, comptime meta: StructMeta) void { self.write("typedef struct "); @@ -107,7 +217,7 @@ pub const C_Generator = struct { self.write(" " ++ field.name); if (info == .Array) { - _ = self.file.writer().print("[{}]", .{info.Array.len}) catch unreachable; + writer.print("[{}]", .{info.Array.len}) catch unreachable; } self.write(";\n"); @@ -115,7 +225,11 @@ pub const C_Generator = struct { self.write("} " ++ name ++ "_t;\n\n"); } - pub fn gen_enum(self: *Self, comptime name: []const u8, comptime meta: EnumMeta) void { + pub fn gen_enum( + self: *Self, + comptime name: []const u8, + comptime meta: EnumMeta, + ) void { self.write("enum " ++ name ++ " {\n"); comptime var last = 0; @@ -124,7 +238,7 @@ pub const C_Generator = struct { // if field value is unexpected/custom, manually define it if ((i == 0 and field.value != 0) or (i > 0 and field.value > last + 1)) { - _ = self.file.writer().print(" = {}", .{field.value}) catch unreachable; + writer.print(" = {}", .{field.value}) catch unreachable; } self.write(",\n"); @@ -135,7 +249,11 @@ pub const C_Generator = struct { self.write("};\n\n"); } - pub fn gen_union(self: *Self, comptime name: []const u8, comptime meta: UnionMeta) void { + pub fn gen_union( + self: *Self, + comptime name: []const u8, + comptime meta: UnionMeta, + ) void { self.write("typedef union "); self.write(name ++ " {\n"); @@ -148,7 +266,10 @@ pub const C_Generator = struct { self.write("} " ++ name ++ "_t;\n\n"); } - fn writeType(self: *Self, comptime T: type) void { + fn writeType( + self: *Self, + comptime T: type, + ) void { const TT = comptime if (@typeInfo(T) == .Pointer) @typeInfo(T).Pointer.child else T; if (comptime (isCppObject(TT)) and @hasDecl(TT, "name")) { @@ -158,7 +279,38 @@ pub const C_Generator = struct { } } - self.write(comptime TT.name); + const _formatted_name = comptime brk: { + var original: [TT.name.len]u8 = undefined; + _ = std.mem.replace(u8, TT.name, ":", "_", &original); + break :brk original; + }; + const formatted_name = comptime std.mem.span(&_formatted_name); + + if (@hasDecl(TT, "is_pointer") and !TT.is_pointer) { + if (cTypeLabel(TT.Type)) |label| { + type_names.put(comptime label, formatted_name) catch unreachable; + if (@typeInfo(TT) == .Struct and @hasField(TT, "bytes")) { + size_map.put(comptime formatted_name, @as(u32, TT.shim.byte_size)) catch unreachable; + } + } else { + type_names.put(comptime TT.name, formatted_name) catch unreachable; + if (@typeInfo(TT) == .Struct and @hasField(TT, "bytes")) { + size_map.put(comptime formatted_name, @as(u32, TT.shim.byte_size)) catch unreachable; + } + } + } else { + type_names.put(comptime TT.name, formatted_name) catch unreachable; + if (@typeInfo(TT) == .Struct and @hasField(TT, "bytes")) { + size_map.put(comptime formatted_name, @as(u32, TT.shim.byte_size)) catch unreachable; + } + } + + if (TT == T and @hasField(T, "bytes")) { + write(self, comptime "b" ++ formatted_name); + } else { + write(self, comptime formatted_name); + } + if (@typeInfo(T) == .Pointer or @hasDecl(TT, "Type") and @typeInfo(TT.Type) == .Pointer) { if (@hasDecl(TT, "is_pointer") and !TT.is_pointer) {} else { write(self, "*"); @@ -167,73 +319,35 @@ pub const C_Generator = struct { return; } - switch (T) { - void => self.write("void"), - bool => self.write("bool"), - usize => self.write("size_t"), - isize => self.write("int"), - u8 => self.write("char"), - u16 => self.write("uint16_t"), - u32 => self.write("uint32_t"), - u64 => self.write("uint64_t"), - i8 => self.write("int8_t"), - i16 => self.write("int16_t"), - i24 => self.write("int24_t"), - i32 => self.write("int32_t"), - i64 => self.write("int64_t"), - f64 => self.write("double"), - f32 => self.write("float"), - *c_void => self.write("void*"), - [*]bool => self.write("bool*"), - [*]usize => self.write("size_t*"), - [*]isize => self.write("int*"), - [*]u8 => self.write("char*"), - [*]u16 => self.write("uint16_t*"), - [*]u32 => self.write("uint32_t*"), - [*]u64 => self.write("uint64_t*"), - [*]i8 => self.write("int8_t*"), - [*]i16 => self.write("int16_t*"), - [*]i32 => self.write("int32_t*"), - [*]i64 => self.write("int64_t*"), - [*]const bool => self.write("const bool*"), - [*]const usize => self.write("const size_t*"), - [*]const isize => self.write("const int*"), - [*]const u8 => self.write("const char*"), - [*]const u16 => self.write("const uint16_t*"), - [*]const u32 => self.write("const uint32_t*"), - [*]const u64 => self.write("const uint64_t*"), - [*]const i8 => self.write("const int8_t*"), - [*]const i16 => self.write("const int16_t*"), - [*]const i32 => self.write("const int32_t*"), - [*]const i64 => self.write("const int64_t*"), - else => { - const meta = @typeInfo(T); - switch (meta) { - .Pointer => |Pointer| { - const child = Pointer.child; - const childmeta = @typeInfo(child); - // if (childmeta == .Struct and childmeta.Struct.layout != .Extern) { - // self.write("void"); - // } else { - self.writeType(child); - // } - self.write("*"); - }, - .Optional => self.writeType(meta.Optional.child), - .Array => @compileError("Handle goofy looking C Arrays in the calling function"), - .Enum => |Enum| { - self.writeType(Enum.tag_type); - }, - else => { - return self.write(@typeName(T)); - }, - } - }, + if (comptime cTypeLabel(T)) |label| { + self.write(comptime label); + } else { + const meta = @typeInfo(T); + switch (meta) { + .Pointer => |Pointer| { + const child = Pointer.child; + const childmeta = @typeInfo(child); + // if (childmeta == .Struct and childmeta.Struct.layout != .Extern) { + // self.write("void"); + // } else { + self.writeType(child); + // } + self.write("*"); + }, + .Optional => self.writeType(meta.Optional.child), + .Array => @compileError("Handle goofy looking C Arrays in the calling function"), + .Enum => |Enum| { + self.writeType(Enum.tag_type); + }, + else => { + return self.write(@typeName(T)); + }, + } } } fn write(self: *Self, comptime str: []const u8) void { - _ = self.file.writeAll(str) catch {}; + _ = writer.write(str) catch {}; } }; @@ -295,32 +409,62 @@ pub fn HeaderGen(comptime import: type, comptime fname: []const u8) type { return struct { source_file: []const u8 = fname, gen: C_Generator = undefined, + const Self = @This(); pub fn init() Self { return Self{}; } - pub fn startFile(comptime self: Self, comptime Type: type, comptime prefix: []const u8, file: std.fs.File) void { + pub fn startFile( + comptime self: Self, + comptime Type: type, + comptime prefix: []const u8, + file: anytype, + other: std.fs.File, + ) void { if (comptime std.meta.trait.hasDecls(Type, .{"include"})) { comptime var new_name = std.mem.zeroes([Type.include.len]u8); comptime { _ = std.mem.replace(u8, Type.include, "/", "_", std.mem.span(&new_name)); _ = std.mem.replace(u8, &new_name, ".", "_", std.mem.span(&new_name)); + _ = std.mem.replace(u8, &new_name, "<", "_", std.mem.span(&new_name)); + _ = std.mem.replace(u8, &new_name, ">", "_", std.mem.span(&new_name)); + _ = std.mem.replace(u8, &new_name, "\"", "_", std.mem.span(&new_name)); + } + file.writeAll("\n#pragma mark - " ++ Type.name ++ "\n\n") catch unreachable; + + if (@hasDecl(Type, "include")) { + other.writer().print( + \\ + \\#ifndef INCLUDED_{s} + \\#define INCLUDED_{s} + \\#include {s} + \\#endif + \\ + \\extern "C" const size_t {s} = sizeof({s}); + \\ + , + .{ new_name, new_name, Type.include, Type.shim.size_of_symbol, Type.name }, + ) catch unreachable; } - const inner_name = comptime std.mem.trim(u8, &new_name, "<>\""); - file.writeAll("\n#pragma mark - " ++ Type.name ++ "\n") catch unreachable; - file.writeAll("\n#ifndef BINDINGS__decls__" ++ inner_name ++ "\n") catch {}; - file.writeAll("#define BINDINGS__decls__" ++ inner_name ++ "\n") catch {}; - file.writeAll("#include " ++ Type.include ++ "\n") catch {}; - file.writeAll("namespace " ++ Type.namespace ++ " {\n class " ++ prefix ++ ";\n}\n") catch {}; - file.writeAll("#endif\n\n") catch {}; } } + + pub fn processStaticExport(comptime self: Self, file: anytype, gen: *C_Generator, comptime static_export: StaticExport) void { + const fn_meta = comptime @typeInfo(static_export.Type).Fn; + gen.gen_func( + comptime static_export.symbol_name, + comptime static_export.Decl().data.Fn, + comptime fn_meta, + comptime std.mem.zeroes([]const []const u8), + ); + } + pub fn processDecl( comptime self: Self, - file: std.fs.File, + file: anytype, gen: *C_Generator, comptime Container: type, comptime Decl: std.builtin.TypeInfo.Declaration, @@ -332,14 +476,20 @@ pub fn HeaderGen(comptime import: type, comptime fname: []const u8) type { switch (@typeInfo(Type)) { .Enum => |Enum| { const layout = Enum.layout; - gen.gen_enum(prefix ++ "__" ++ name, Enum); + gen.gen_enum( + prefix ++ "__" ++ name, + Enum, + ); }, .Struct => |Struct| { - gen.gen_struct(decl.name, Struct); + gen.gen_struct(decl.name, Struct, file); }, .Union => |Union| { const layout = Union.layout; - gen.gen_union(prefix ++ "__" ++ name, Union); + gen.gen_union( + prefix ++ "__" ++ name, + Union, + ); }, .Fn => |func| { // if (func.) { @@ -370,41 +520,136 @@ pub fn HeaderGen(comptime import: type, comptime fname: []const u8) type { } } - pub fn exec(comptime self: Self, file: std.fs.File) void { + pub fn exec(comptime self: Self, file: std.fs.File, impl: std.fs.File) void { const Generator = C_Generator; validateGenerator(Generator); - - file.writeAll("#pragma once\n#include <stddef.h>\n#include <stdint.h>\n#include <stdbool.h>\n#define ZIG_DECL extern\n#define CPP_DECL extern \n\n") catch {}; - var bufset = std.BufSet.init(std.heap.c_allocator); + var file_writer = file.writer(); + file_writer.print("//-- AUTOGENERATED FILE -- {d}\n", .{std.time.timestamp()}) catch unreachable; + file.writeAll( + \\#pragma once + \\ + \\#include <stddef.h> + \\#include <stdint.h> + \\#include <stdbool.h> + \\ + \\#ifdef __cplusplus + \\ #define AUTO_EXTERN_C extern "C" + \\#else + \\ #define AUTO_EXTERN_C + \\#endif + \\#define ZIG_DECL AUTO_EXTERN_C + \\#define CPP_DECL AUTO_EXTERN_C + \\#define CPP_SIZE AUTO_EXTERN_C + \\ + \\ + ) catch {}; + + impl.writer().print("//-- AUTOGENERATED FILE -- {d}\n", .{std.time.timestamp()}) catch unreachable; + impl.writer().writeAll( + \\#pragma once + \\ + \\#include <stddef.h> + \\#include <stdint.h> + \\#include <stdbool.h> + \\ + \\#include "root.h" + \\ + ) catch {}; + + var impl_second_buffer = std.ArrayList(u8).init(std.heap.c_allocator); + var impl_second_writer = impl_second_buffer.writer(); + + var impl_third_buffer = std.ArrayList(u8).init(std.heap.c_allocator); + var impl_third_writer = impl_third_buffer.writer(); + + var to_get_sizes: usize = 0; inline for (all_decls) |_decls| { if (comptime _decls.is_pub) { switch (_decls.data) { .Type => |Type| { @setEvalBranchQuota(99999); - if (@hasDecl(Type, "Extern")) { + + if (@hasDecl(Type, "Extern") or @hasDecl(Type, "Export")) { const identifier = comptime std.fmt.comptimePrint("{s}_{s}", .{ Type.shim.name, Type.shim.namespace }); if (!bufset.contains(identifier)) { - self.startFile(Type, Type.shim.name, file); + self.startFile( + Type, + Type.shim.name, + writer, + impl, + ); + bufset.insert(identifier) catch unreachable; - var gen = C_Generator.init(Type.name, file); + var gen = C_Generator.init(Type.name, @TypeOf(writer), writer); defer gen.deinit(); - inline for (Type.Extern) |extern_decl| { - if (@hasDecl(Type, extern_decl)) { - const normalized_name = comptime brk: { - var _normalized_name: [Type.name.len]u8 = undefined; - _ = std.mem.replace(u8, Type.name, ":", "_", std.mem.span(&_normalized_name)); - break :brk _normalized_name; + + if (@hasDecl(Type, "Extern")) { + if (to_get_sizes > 0) { + impl_second_writer.writeAll(", ") catch unreachable; + impl_third_writer.writeAll(", ") catch unreachable; + } + + const formatted_name = comptime brk: { + var original: [Type.name.len]u8 = undefined; + _ = std.mem.replace(u8, Type.name, ":", "_", &original); + break :brk original; + }; + + impl_third_writer.print("sizeof({s})", .{comptime Type.name}) catch unreachable; + impl_second_writer.print("\"{s}\"", .{formatted_name}) catch unreachable; + to_get_sizes += 1; + const ExternList = comptime brk: { + const Sorder = struct { + pub fn lessThan(context: @This(), lhs: []const u8, rhs: []const u8) bool { + return std.ascii.orderIgnoreCase(lhs, rhs) == std.math.Order.lt; + } }; + var extern_list = Type.Extern; + std.sort.sort([]const u8, &extern_list, Sorder{}, Sorder.lessThan); + break :brk extern_list; + }; + // impl_writer.print(" #include {s}\n", .{Type.include}) catch unreachable; + inline for (&ExternList) |extern_decl| { + if (@hasDecl(Type, extern_decl)) { + const normalized_name = comptime brk: { + var _normalized_name: [Type.name.len]u8 = undefined; + _ = std.mem.replace(u8, Type.name, ":", "_", std.mem.span(&_normalized_name)); + break :brk _normalized_name; + }; + + processDecl( + self, + writer, + &gen, + Type, + comptime std.meta.declarationInfo(Type, extern_decl), + comptime extern_decl, + comptime std.mem.span(&normalized_name), + ); + } + } + } - processDecl( + if (@hasDecl(Type, "Export")) { + const ExportLIst = comptime brk: { + const Sorder = struct { + pub fn lessThan(context: @This(), comptime lhs: StaticExport, comptime rhs: StaticExport) bool { + return std.ascii.orderIgnoreCase(lhs.symbol_name, rhs.symbol_name) == std.math.Order.lt; + } + }; + var extern_list = Type.Export; + std.sort.sort(StaticExport, &extern_list, Sorder{}, Sorder.lessThan); + break :brk extern_list; + }; + + gen.direction = C_Generator.Direction.export_zig; + inline for (ExportLIst) |static_export| { + processStaticExport( self, file, &gen, - Type, - comptime std.meta.declarationInfo(Type, extern_decl), - comptime extern_decl, - comptime std.mem.span(&normalized_name), + comptime static_export, ); } } @@ -415,6 +660,90 @@ pub fn HeaderGen(comptime import: type, comptime fname: []const u8) type { } } } + impl.writer().print("\nconst size_t sizes[{d}] = {{", .{to_get_sizes}) catch unreachable; + impl.writeAll(impl_third_buffer.items) catch unreachable; + impl.writeAll("};\n") catch unreachable; + impl.writer().print("\nconst char* names[{d}] = {{", .{to_get_sizes}) catch unreachable; + impl.writeAll(impl_second_buffer.items) catch unreachable; + impl.writeAll("};\n") catch unreachable; + + var iter = type_names.iterator(); + + const NamespaceMap = std.StringArrayHashMap(std.BufMap); + var namespaces = NamespaceMap.init(std.heap.c_allocator); + + file_writer.writeAll("\n#ifndef __cplusplus\n") catch unreachable; + while (iter.next()) |entry| { + const key = entry.key_ptr.*; + const value = entry.value_ptr.*; + if (std.mem.indexOfScalar(u8, entry.key_ptr.*, ':')) |namespace_start| { + const namespace = entry.key_ptr.*[0..namespace_start]; + file_writer.print(" typedef struct {s} {s}; // {s}\n", .{ + value, + value, + key, + }) catch unreachable; + if (!namespaces.contains(namespace)) { + namespaces.put(namespace, std.BufMap.init(std.heap.c_allocator)) catch unreachable; + } + const class = key[namespace_start + 2 ..]; + namespaces.getPtr(namespace).?.put(class, value) catch unreachable; + } else { + file_writer.print(" typedef {s} {s};\n", .{ + key, + value, + }) catch unreachable; + + impl_writer.print(" typedef {s} {s};\n", .{ + key, + value, + }) catch unreachable; + } + } + + file_writer.writeAll("\n#endif\n") catch unreachable; + var size_iter = size_map.iterator(); + while (size_iter.next()) |size| { + file_writer.print(" typedef struct b{s} {{ char bytes[{d}]; }} b{s};\n", .{ + size.key_ptr.*, + size.value_ptr.*, + size.key_ptr.*, + }) catch unreachable; + } + + file_writer.writeAll("\n#ifdef __cplusplus\n") catch unreachable; + + iter = type_names.iterator(); + var namespace_iter = namespaces.iterator(); + while (namespace_iter.next()) |map| { + file_writer.print(" namespace {s} {{\n", .{map.key_ptr.*}) catch unreachable; + var classes = map.value_ptr.iterator(); + while (classes.next()) |class| { + file_writer.print(" class {s};\n", .{class.key_ptr.*}) catch unreachable; + } + file_writer.writeAll(" }\n") catch unreachable; + } + + file_writer.writeAll("\n") catch unreachable; + + file_writer.writeAll(impl_buffer.items) catch unreachable; + + iter = type_names.iterator(); + namespace_iter = namespaces.iterator(); + while (namespace_iter.next()) |map| { + var classes = map.value_ptr.iterator(); + while (classes.next()) |class| { + file_writer.print(" using {s} = {s}::{s};\n", .{ + class.value_ptr.*, + map.key_ptr.*, + class.key_ptr.*, + }) catch unreachable; + } + } + + file_writer.writeAll("\n#endif\n\n") catch unreachable; + + file.writeAll(buffer.items) catch unreachable; // processDecls( // self, |