diff --git a/src/main.zig b/src/main.zig index 07b8fea..5966efa 100644 --- a/src/main.zig +++ b/src/main.zig @@ -7,7 +7,8 @@ pub export fn spacetime_includes() void { } pub const moduleTablesDef = .{ - .person = Person, + .person = spacetime.Table(.{.name = "person", .layout = Person}), + .person2 = spacetime.Table(.{.name = "person2", .layout = Person}), }; pub const moduleReducersDef = .{ diff --git a/src/spacetime.zig b/src/spacetime.zig index aec3b4f..2b20255 100644 --- a/src/spacetime.zig +++ b/src/spacetime.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const utils = @import("spacetime/utils.zig"); pub const st_types = @import("spacetime/types.zig"); pub const serializer = @import("spacetime/serializer.zig"); @@ -146,11 +147,14 @@ fn spacetimeType2ZigType(t: AlgebraicType) type { }; } +const StructFieldImpl = struct { + name: []const u8, + type: AlgebraicType, +}; + pub fn Struct(comptime decl: StructDecl) type { const @"spacetime_10.0__struct_" = struct { - name: ?[]const u8 = decl.name, - table_type: TableType = .User, - table_access: TableAccess = .Private, + name: []const u8 = decl.name, }; var zigStructMembers: []const std.builtin.Type.StructField = &[_]std.builtin.Type.StructField{ @@ -185,16 +189,21 @@ pub fn Struct(comptime decl: StructDecl) type { }); } -// pub fn Table(comptime decl: type) type { -// const @"spacetime_10.0__table_" = struct { -// name: []const u8, -// table_type: TableType = .User, -// table_access: TableAccess = .Private, -// type: decl = std.mem.zeroes(decl), -// }; +pub const TableDecl = struct { + name: []const u8, + layout: type, +}; -// return @"spacetime_10.0__table_"; -//} +pub fn Table(comptime decl: TableDecl) type { + const @"spacetime_10.0__table_" = struct { + name: []const u8 = decl.name, + table_type: TableType = .User, + table_access: TableAccess = .Private, + layout: @TypeOf(decl.layout) = decl.layout, + }; + + return @"spacetime_10.0__table_"; +} pub fn readArg(allocator: std.mem.Allocator, args: BytesSource, comptime t: AlgebraicType) !spacetimeType2ZigType(t) { switch(t) { @@ -236,62 +245,53 @@ pub fn zigTypeToSpacetimeType(comptime param: ?type) AlgebraicType { }; } -pub fn buildTypeList(name: []const u8, default_values: type, raw_types: *[]const AlgebraicType, types: *[]const RawTypeDefV9) usize -{ - var product_elements: []const ProductTypeElement = &[_]ProductTypeElement{}; +const StructImpl = struct { + name: []const u8, + fields: []const StructFieldImpl, +}; - inline for(@typeInfo(default_values).@"struct".fields, 0..) |table_field, i| { - if(i == 0) continue; - - - if(@typeInfo(table_field.type) == .@"struct" and std.meta.fieldIndex(table_field.type, MagicStruct) != null) { - - const table = std.meta.fields(table_field.type)[std.meta.fieldIndex(table_field.type, MagicStruct).?]; - const subname = @as(*table.type, @constCast(@alignCast(@ptrCast(table.default_value)))).*.name.?; - //_ = subname; - //@compileLog(table_field.type); - const id = buildTypeList(subname, table_field.type, raw_types, types); - product_elements = product_elements ++ &[_]ProductTypeElement{ +pub fn addStructImpl(structImpls: *[]const StructImpl, layout: anytype) u32 { + var members: []const StructFieldImpl = &[_]StructFieldImpl{}; + + const fields = std.meta.fields(layout); + const name = utils.getMemberDefaultValue(fields[0].type, "name"); + + //FIXME: Search for existing structImpl of provided layout. I think the current might work, but I don't trust it. + inline for(structImpls.*, 0..) |structImpl, i| { + if(std.mem.eql(u8, structImpl.name, name)) { + return i; + } + } + + inline for(fields[1..]) |field| { + if(@typeInfo(field.type) == .@"struct") { + members = members ++ &[_]StructFieldImpl{ .{ - .name = table_field.name, - .algebraic_type = .{ + .name = field.name, + .type = .{ .Ref = .{ - .inner = id, + .inner = addStructImpl(structImpls, field.type), } } } }; - } else { - product_elements = product_elements ++ &[_]ProductTypeElement{ + members = members ++ &[_]StructFieldImpl{ .{ - .name = table_field.name, - .algebraic_type = zigTypeToSpacetimeType(table_field.type) + .name = field.name, + .type = zigTypeToSpacetimeType(field.type), } }; } - + members = members ++ &[_]StructFieldImpl{}; } - - raw_types.* = raw_types.* ++ &[_]AlgebraicType{ + structImpls.* = structImpls.* ++ &[_]StructImpl{ .{ - .Product = .{ - .elements = product_elements, - } + .name = name, + .fields = members, }, }; - types.* = types.* ++ &[_]RawTypeDefV9{ - .{ - .name = .{ - .scope = &[_][]u8{}, - .name = name - }, - .ty = .{ .inner = raw_types.len-1, }, - .custom_ordering = true, - } - }; - - return types.len-1; + return structImpls.len - 1; } pub fn compile(comptime moduleTables : anytype, comptime moduleReducers : anytype) !RawModuleDefV9 { @@ -304,25 +304,16 @@ pub fn compile(comptime moduleTables : anytype, comptime moduleReducers : anytyp var raw_types: []const AlgebraicType = &[_]AlgebraicType{}; var types: []const RawTypeDefV9 = &[_]RawTypeDefV9{}; + var structDecls: []const StructImpl = &[_]StructImpl{}; + inline for(std.meta.fields(@TypeOf(moduleTables))) |field| { - //const struct_decl = @as(*const field.type, @alignCast(@ptrCast(field.default_value.?))).*; - //@compileLog(@TypeOf(struct_decl.type)); - const default_values = @as(*const field.type, @alignCast(@ptrCast(field.default_value.?))).*; - const structInfo = blk: { - for(@typeInfo(default_values).@"struct".fields) |structInfoField| { - if(std.mem.eql(u8, structInfoField.name, MagicStruct)) { - break :blk structInfoField.type{}; - } - } - }; - + const table: @as(*const field.type, @alignCast(@ptrCast(field.default_value))).* = .{}; + const name: []const u8 = table.name; + const table_type: TableType = table.table_type; + const table_access: TableAccess = table.table_access; const product_type_ref: AlgebraicTypeRef = AlgebraicTypeRef{ - .inner = buildTypeList(field.name, default_values, &raw_types, &types), + .inner = addStructImpl(&structDecls, table.layout), }; - - const name: []const u8 = structInfo.name.?; - const table_type: TableType = structInfo.table_type; - const table_access: TableAccess = structInfo.table_access; tables = tables ++ &[_]RawTableDefV9{ .{ .name = name, @@ -338,6 +329,39 @@ pub fn compile(comptime moduleTables : anytype, comptime moduleReducers : anytyp }; } + inline for(structDecls) |structDecl| { + var product_elements: []const ProductTypeElement = &[_]ProductTypeElement{}; + + inline for(structDecl.fields) |field| + { + product_elements = product_elements ++ &[_]ProductTypeElement{ + .{ + .name = field.name, + .algebraic_type = field.type, + } + }; + } + + raw_types = raw_types ++ &[_]AlgebraicType{ + .{ + .Product = .{ + .elements = product_elements, + } + }, + }; + + types = types ++ &[_]RawTypeDefV9{ + .{ + .name = .{ + .scope = &[_][]u8{}, + .name = structDecl.name + }, + .ty = .{ .inner = raw_types.len-1, }, + .custom_ordering = true, + } + }; + } + inline for(std.meta.fields(@TypeOf(moduleReducers))) |field| { const default_values = @as(*const field.type, @alignCast(@ptrCast(field.default_value.?))).*; const name: []const u8 = default_values.name orelse field.name; @@ -501,20 +525,6 @@ pub export fn __describe_module__(description: BytesSink) void { write_to_sink(description, moduleDefBytes.items); } -fn itoa(comptime value: anytype) [:0]const u8 { - comptime var s: []const u8 = &[_]u8{}; - comptime var n = value; - if (n == 0) { - s = s ++ .{'0'}; - } else { - comptime while (n != 0) { - s = s ++ .{'0' + (n % 10)}; - n = n / 10; - }; - } - return @ptrCast(s ++ .{0}); -} - pub export fn __call_reducer__( id: usize, sender_0: u64, @@ -545,7 +555,7 @@ pub export fn __call_reducer__( if( comptime std.mem.endsWith(u8, @typeName(field.type), "spacetime_10.0__reducer_")) { defer i += 1; if(id == i) { - const func = std.meta.fields(field.type)[std.meta.fieldIndex(field.type, "func").?].type; + const func = utils.getMemberDefaultType(field.type, "func"); const params = @typeInfo(func).@"fn".params; const param_names = @field(moduleReducersDef, field.name).param_names; comptime var argCount = 1; @@ -566,7 +576,7 @@ pub export fn __call_reducer__( .alignment = 0, .default_value = null, .is_comptime = false, - .name = comptime itoa(argCount), + .name = comptime utils.itoa(argCount), .type = param.type.?, } }; @@ -590,7 +600,7 @@ pub export fn __call_reducer__( if(args.inner != 0) { inline for(params, 0..) |param, name| { comptime if(name == 0) continue; - @field(constructedArg, itoa(name)) = readArg(allocator, args, zigTypeToSpacetimeType(param.type.?)) catch |err2| { + @field(constructedArg, utils.itoa(name)) = readArg(allocator, args, zigTypeToSpacetimeType(param.type.?)) catch |err2| { var buf: [512]u8 = undefined; print(std.fmt.bufPrint(&buf, "Error: {}", .{err2}) catch "Expand Error Buffer!"); @panic("blah"); diff --git a/src/spacetime/types.zig b/src/spacetime/types.zig index a89d6e2..5ca406d 100644 --- a/src/spacetime/types.zig +++ b/src/spacetime/types.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const utils = @import("utils.zig"); const spacetime = @import("../spacetime.zig"); const console_log = spacetime.console_log; const TableId = spacetime.TableId; @@ -130,7 +131,8 @@ pub const Lifecycle = enum { fn getStructSize(data: anytype) usize { const struct_type = @TypeOf(data); - const @"spacetime_10.0__table_" = std.meta.fields(struct_type)[std.meta.fieldIndex(struct_type, spacetime.MagicStruct).?].type; + + const @"spacetime_10.0__table_" = utils.getMemberDefaultType(struct_type, spacetime.MagicStruct); const fields = std.meta.fields(@TypeOf(data)); var size: usize = 0; @@ -155,7 +157,6 @@ fn getStructSize(data: anytype) usize { size += getStructSize(@field(data, field.name)); break :blk; } - //const subname = @as(*field.type, @constCast(@alignCast(@ptrCast(field.default_value)))).*.name.?; @compileLog(field.type); @compileError("Unsupported type in StructSerializer"); }, @@ -167,7 +168,7 @@ fn getStructSize(data: anytype) usize { fn getStructData(data: anytype, mem: []u8) []u8 { const struct_type = @TypeOf(data); - const @"spacetime_10.0__table_" = std.meta.fields(struct_type)[std.meta.fieldIndex(struct_type, spacetime.MagicStruct).?].type; + const @"spacetime_10.0__table_" = utils.getMemberDefaultType(struct_type, spacetime.MagicStruct); const fields = std.meta.fields(@TypeOf(data)); var offset_mem = mem; @@ -220,8 +221,7 @@ pub fn StructSerializer(struct_type: type) fn(std.mem.Allocator, struct_type) st } pub fn StructDeserializer(struct_type: type) fn(allocator: std.mem.Allocator, *[]const u8) std.mem.Allocator.Error!*struct_type { - - const @"spacetime_10.0__table_" = std.meta.fields(struct_type)[std.meta.fieldIndex(struct_type, spacetime.MagicStruct).?].type; + const @"spacetime_10.0__table_" = utils.getMemberDefaultType(struct_type, spacetime.MagicStruct); return struct { pub fn deserialize(allocator: std.mem.Allocator, data: *[]const u8) std.mem.Allocator.Error!*struct_type { @@ -265,13 +265,10 @@ pub fn StructDeserializer(struct_type: type) fn(allocator: std.mem.Allocator, *[ }.deserialize; } -pub fn Table2Struct(comptime table_type: type) type { +pub fn Table2ORM(comptime table_type: type) type { + const table_name = utils.getMemberDefaultValue(table_type, "name"); + const struct_type = utils.getMemberDefaultValue(table_type, "layout"); - const fields = std.meta.fields(table_type); - const field = fields[std.meta.fieldIndex(table_type, spacetime.MagicStruct).?]; - const struct_type = @as(*const field.type, @alignCast(@ptrCast(field.default_value.?))).*; - const table_name: []const u8 = struct_type.name.?; - return struct { allocator: std.mem.Allocator, @@ -282,7 +279,7 @@ pub fn Table2Struct(comptime table_type: type) type { contents: []u8 = undefined, last_ret: i16 = spacetime.OK, - pub fn next(self: *@This()) !?*table_type { + pub fn next(self: *@This()) !?*struct_type { var buffer_len: usize = undefined; while(true) { @@ -302,7 +299,7 @@ pub fn Table2Struct(comptime table_type: type) type { switch(ret) { spacetime.EXHAUSTED, spacetime.OK => { - return StructDeserializer(table_type)(self.allocator, &self.contents); + return StructDeserializer(struct_type)(self.allocator, &self.contents); }, spacetime.BUFFER_TOO_SMALL => { return error.BUFFER_TOO_SMALL; @@ -321,10 +318,10 @@ pub fn Table2Struct(comptime table_type: type) type { } }; - pub fn insert(self: @This(), data: table_type) void { + pub fn insert(self: @This(), data: struct_type) void { var id: TableId = undefined; _ = spacetime.table_id_from_name(table_name.ptr, table_name.len, &id); - const raw_data = StructSerializer(table_type)(self.allocator, data) catch return; + const raw_data = StructSerializer(struct_type)(self.allocator, data) catch return; defer self.allocator.free(raw_data); var raw_data_len: usize = raw_data.len; _ = spacetime.datastore_insert_bsatn(id, raw_data.ptr, &raw_data_len); @@ -346,7 +343,7 @@ pub fn Table2Struct(comptime table_type: type) type { pub const Local = struct { allocator: std.mem.Allocator, - pub fn get(self: @This(), table: anytype) Table2Struct(table) { + pub fn get(self: @This(), table: anytype) Table2ORM(table) { return .{ .allocator = self.allocator, }; diff --git a/src/spacetime/utils.zig b/src/spacetime/utils.zig new file mode 100644 index 0000000..40d0240 --- /dev/null +++ b/src/spacetime/utils.zig @@ -0,0 +1,26 @@ +const std = @import("std"); + +pub fn getMemberDefaultType(t: type, comptime member: []const u8) type { + const field = std.meta.fields(t)[std.meta.fieldIndex(t, member).?]; + return field.type; +} + +pub fn getMemberDefaultValue(t: type, comptime member: []const u8) getMemberDefaultType(t, member) { + const field = std.meta.fields(t)[std.meta.fieldIndex(t, member).?]; + const value = @as(*const field.type, @alignCast(@ptrCast(field.default_value))).*; + return value; +} + +pub fn itoa(comptime value: anytype) [:0]const u8 { + comptime var s: []const u8 = &[_]u8{}; + comptime var n = value; + if (n == 0) { + s = s ++ .{'0'}; + } else { + comptime while (n != 0) { + s = s ++ .{'0' + (n % 10)}; + n = n / 10; + }; + } + return @ptrCast(s ++ .{0}); +} \ No newline at end of file