diff --git a/src/main.zig b/src/main.zig index 5966efa..4564704 100644 --- a/src/main.zig +++ b/src/main.zig @@ -6,69 +6,64 @@ pub export fn spacetime_includes() void { _ = &spacetime.__call_reducer__; } -pub const moduleTablesDef = .{ - .person = spacetime.Table(.{.name = "person", .layout = Person}), - .person2 = spacetime.Table(.{.name = "person2", .layout = Person}), +pub const DbVector2 = struct { + x: f32, + y: f32, }; -pub const moduleReducersDef = .{ - .Init = spacetime.Reducer(Init){ .lifecycle = .Init }, - .OnConnect = spacetime.Reducer(OnConnect){ .lifecycle = .OnConnect }, - .OnDisconnect = spacetime.Reducer(OnDisconnect){ .lifecycle = .OnDisconnect }, - .add = spacetime.Reducer(add){ .param_names = &[_][:0]const u8{ "name" }}, - .say_hello = spacetime.Reducer(say_hello){}, +pub const person: spacetime.Table = .{ .schema = Person, }; +pub const Person = struct{ + name: []const u8, + pos: DbVector2, + schedule: spacetime.ScheduleAt, }; -pub const DbVector2 = spacetime.Struct(.{ - .name = "DbVector2", - .fields = &[_]spacetime.StructFieldDecl{ - .{ .name = "x", .type = f32, }, - .{ .name = "y", .type = f32 }, - }, -}); +pub const Init: spacetime.Reducer = .{ + .func_type = @TypeOf(InitReducer), + .func = @ptrCast(&InitReducer), + .lifecycle = .Init, +}; -pub const Person = spacetime.Struct(.{ - .name = "person", - .fields = &[_]spacetime.StructFieldDecl{ - .{ .name = "name", .type = []const u8, }, - .{ .name = "pos", .type = DbVector2, }, - }, -}); - -pub fn Init(ctx: *spacetime.ReducerContext) void { +pub fn InitReducer(_: *spacetime.ReducerContext) void { // Called when the module is initially published - _ = ctx; spacetime.print("[Init]"); } -pub fn OnConnect(ctx: *spacetime.ReducerContext) void { +pub const OnConnect = spacetime.Reducer{ .func_type = @TypeOf(OnConnectReducer), .func = @ptrCast(&OnConnectReducer), .lifecycle = .OnConnect, }; +pub fn OnConnectReducer(_: *spacetime.ReducerContext) void { // Called everytime a new client connects - _ = ctx; spacetime.print("[OnConnect]"); } -pub fn OnDisconnect(ctx: *spacetime.ReducerContext) void { +pub const OnDisconnect = spacetime.Reducer{ .func_type = @TypeOf(OnDisconnectReducer), .func = @ptrCast(&OnDisconnectReducer), .lifecycle = .OnDisconnect, }; +pub fn OnDisconnectReducer(_: *spacetime.ReducerContext) void { // Called everytime a client disconnects - _ = ctx; spacetime.print("[OnDisconnect]"); } -pub fn add(ctx: *spacetime.ReducerContext, name: []const u8) void { - const personTable = ctx.*.db.get(moduleTablesDef.person); - personTable.insert(Person{ .name = name, .pos = DbVector2{ .x = 10.4, .y = 20.6 } }); +pub const add = spacetime.Reducer{ .func_type = @TypeOf(addReducer), .func = @ptrCast(&addReducer), .params = &.{ "name", "time" }}; +pub fn addReducer(ctx: *spacetime.ReducerContext, name: []const u8, time: i64) void { + const personTable = ctx.*.db.get("person"); + personTable.insert(Person{ + .name = name, + .pos = DbVector2{ .x = 10.4, .y = 20.6 }, + .schedule = .{ .Interval = .{ .__time_duration_micros__ = time, }, }, + }); var buf: [128]u8 = undefined; spacetime.print(std.fmt.bufPrint(&buf, "[add] {{{s}}}!", .{ name }) catch "[add] Error: name to long"); } -pub fn say_hello(ctx: *spacetime.ReducerContext) void { - var personIter = ctx.*.db.get(moduleTablesDef.person).iter(); - while(personIter.next() catch { - @panic("person Iter errored!"); - }) |person| { - var buffer: [512]u8 = undefined; - const msg = std.fmt.bufPrint(&buffer, "Hello, {s} (pos: {{{d}, {d}}})!", .{ person.name, person.pos.x, person.pos.y }) catch ""; - spacetime.print(msg); - } - spacetime.print("Hello, World!"); +pub const say_hello = spacetime.Reducer{ .func_type = @TypeOf(say_helloReducer), .func = @ptrCast(&say_helloReducer), }; +pub fn say_helloReducer(ctx: *spacetime.ReducerContext) void { + //_ = ctx; + var personIter = ctx.*.db.get("person").iter(); + while(personIter.next() catch { + @panic("person Iter errored!"); + }) |item| { + var buffer: [512]u8 = undefined; + const msg = std.fmt.bufPrint(&buffer, "Hello, {s} (pos: {{{d}, {d}}}) (time: {})!", .{ item.name, item.pos.x, item.pos.y, item.schedule.Interval.__time_duration_micros__ }) catch ""; + spacetime.print(msg); + } + spacetime.print("Hello, World!"); } \ No newline at end of file diff --git a/src/spacetime.zig b/src/spacetime.zig index 2b20255..b27e030 100644 --- a/src/spacetime.zig +++ b/src/spacetime.zig @@ -51,6 +51,15 @@ pub fn print(fmt: []const u8) void { console_log(2, null, 0, null, 0, 0, fmt.ptr, fmt.len); } +pub fn debug_print(comptime fmt: []const u8, args: anytype) void { + var buf: [512]u8 = undefined; + var fbs = std.io.fixedBufferStream(&buf); + std.fmt.format(fbs.writer().any(), fmt, args) catch { + return print("Expand the buf in debug_print!"); + }; + return print(fbs.getWritten()); +} + pub const BytesSink = extern struct { inner: u32 }; pub const BytesSource = extern struct { inner: u32 }; @@ -65,12 +74,10 @@ pub const RowIter = extern struct { _inner: u32, pub const INVALID = RowIter{ ._ pub extern "spacetime_10.0" fn row_iter_bsatn_advance(iter: RowIter, buffer_ptr: [*c]u8, buffer_len_ptr: *usize) i16; pub extern "spacetime_10.0" fn datastore_table_scan_bsatn(table_id: TableId, out: [*c]RowIter) u16; -// pub const Identity = struct { -// __identity__: u256, -// }; - -pub const MagicStruct = "spacetime_10.0__struct_"; -pub const MagicTable = "spacetime_10.0__table_"; +pub const ScheduleAt = union(enum){ + Interval: struct{ __time_duration_micros__: i64 }, + Time: struct{ __timestamp_micros_since_unix_epoch__: i64 }, +}; pub const EXHAUSTED = -1; pub const OK = 0; @@ -111,21 +118,6 @@ pub fn write_to_sink(sink: BytesSink, _buf: []const u8) void { } } -pub const Param = struct { - name: []const u8, -}; - -pub fn Reducer(comptime func: anytype) type { - const @"spacetime_10.0__reducer_" = struct { - name: ?[]const u8 = null, - func: @TypeOf(func) = func, - lifecycle: ?Lifecycle = null, - param_names: []const [:0]const u8 = &[_][:0]const u8{}, - }; - - return @"spacetime_10.0__reducer_"; -} - pub const StructFieldDecl = struct { name: [:0]const u8, type: type, @@ -143,6 +135,8 @@ fn spacetimeType2ZigType(t: AlgebraicType) type { .String => []const u8, .U32 => u32, .U64 => u64, + .I32 => i32, + .I64 => i64, else => unreachable, }; } @@ -152,59 +146,6 @@ const StructFieldImpl = struct { type: AlgebraicType, }; -pub fn Struct(comptime decl: StructDecl) type { - const @"spacetime_10.0__struct_" = struct { - name: []const u8 = decl.name, - }; - - var zigStructMembers: []const std.builtin.Type.StructField = &[_]std.builtin.Type.StructField{ - std.builtin.Type.StructField{ - .name = MagicStruct, - .type = @"spacetime_10.0__struct_", - .default_value = @as(?*const anyopaque, &@"spacetime_10.0__struct_"{}), - .is_comptime = false, - .alignment = 0, - }, - }; - - inline for(decl.fields) |field| { - zigStructMembers = zigStructMembers ++ &[_]std.builtin.Type.StructField{ - std.builtin.Type.StructField{ - .name = field.name, - .type = field.type, - .default_value = null, - .is_comptime = false, - .alignment = 0, - }, - }; - } - - return @Type(.{ - .@"struct" = std.builtin.Type.Struct{ - .decls = &[_]std.builtin.Type.Declaration{}, - .fields = zigStructMembers, - .is_tuple = false, - .layout = .@"auto", - }, - }); -} - -pub const TableDecl = struct { - name: []const u8, - layout: type, -}; - -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) { .String => { @@ -214,16 +155,11 @@ pub fn readArg(allocator: std.mem.Allocator, args: BytesSource, comptime t: Alge const string_buf = try allocator.alloc(u8, len); return try read_bytes_source(args, string_buf); }, - .U32 => { - var maxbuf: [4]u8 = undefined; + .U32, .U64, .I32, .I64 => { + const read_type = spacetimeType2ZigType(t); + var maxbuf: [@sizeOf(read_type)]u8 = undefined; const len_buf = try read_bytes_source(args, &maxbuf); - const len: u32 = std.mem.bytesToValue(u32, len_buf); - return len; - }, - .U64 => { - var maxbuf: [8]u8 = undefined; - const len_buf = try read_bytes_source(args, &maxbuf); - const len: u64 = std.mem.bytesToValue(u64, len_buf); + const len: read_type = std.mem.bytesToValue(read_type, len_buf); return len; }, else => @compileError("unsupported type in readArg!"), @@ -234,11 +170,31 @@ pub fn zigTypeToSpacetimeType(comptime param: ?type) AlgebraicType { if(param == null) @compileError("Null parameter type passed to zigParamsToSpacetimeParams"); return switch(param.?) { []const u8 => .{ .String = {} }, + i32 => .{ .I32 = {}, }, + i64 => .{ .I64 = {}, }, u32 => .{ .U32 = {}, }, u64 => .{ .U64 = {}, }, f32 => .{ .F32 = {}, }, //Identity => .{ .U256 = {}, }, - else => { + else => blk: { + if(@typeInfo(param.?) == .@"struct") { + var elements: []const ProductTypeElement = &.{}; + const fields = std.meta.fields(param.?); + for(fields) |field| { + elements = elements ++ &[_]ProductTypeElement{ + ProductTypeElement{ + .name = field.name, + .algebraic_type = zigTypeToSpacetimeType(field.type), + }, + }; + } + + break :blk .{ + .Product = ProductType{ + .elements = elements + } + }; + } @compileLog(param.?); @compileError("Unmatched type passed to zigTypeToSpacetimeType!"); }, @@ -251,10 +207,12 @@ const StructImpl = struct { }; 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"); + const name = blk: { + var temp: []const u8 = @typeName(layout); + if(std.mem.lastIndexOf(u8, temp, ".")) |idx| + temp = temp[idx+1..]; + break :blk temp; + }; //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| { @@ -263,7 +221,9 @@ pub fn addStructImpl(structImpls: *[]const StructImpl, layout: anytype) u32 { } } - inline for(fields[1..]) |field| { + const fields = std.meta.fields(layout); + var members: []const StructFieldImpl = &[_]StructFieldImpl{}; + inline for(fields) |field| { if(@typeInfo(field.type) == .@"struct") { members = members ++ &[_]StructFieldImpl{ .{ @@ -275,6 +235,29 @@ pub fn addStructImpl(structImpls: *[]const StructImpl, layout: anytype) u32 { } } }; + } else if(@typeInfo(field.type) == .@"union") { + var variants: []const SumTypeVariant = &[_]SumTypeVariant{}; + _ = &variants; + + const unionFields = std.meta.fields(field.type); + inline for(unionFields) |unionField| { + variants = variants ++ &[_]SumTypeVariant{ + SumTypeVariant{ + .name = unionField.name, + .algebraic_type = zigTypeToSpacetimeType(unionField.type), + } + }; + } + members = members ++ &[_]StructFieldImpl{ + .{ + .name = field.name, + .type = .{ + .Sum = .{ + .variants = variants, + } + } + } + }; } else { members = members ++ &[_]StructFieldImpl{ .{ @@ -294,27 +277,27 @@ pub fn addStructImpl(structImpls: *[]const StructImpl, layout: anytype) u32 { return structImpls.len - 1; } -pub fn compile(comptime moduleTables : anytype, comptime moduleReducers : anytype) !RawModuleDefV9 { +pub fn compile(comptime moduleTables : []const Table, comptime moduleReducers : []const Reducer) !RawModuleDefV9 { var def : RawModuleDefV9 = undefined; _ = &def; - var tables: []const RawTableDefV9 = &[_]RawTableDefV9{}; - var reducers: []const RawReducerDefV9 = &[_]RawReducerDefV9{}; + var tableDefs: []const RawTableDefV9 = &[_]RawTableDefV9{}; + var reducerDefs: []const RawReducerDefV9 = &[_]RawReducerDefV9{}; 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 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; + inline for(moduleTables) |table| { + //const table: @as(*const field.type, @alignCast(@ptrCast(field.default_value))).* = .{}; + const name: []const u8 = table.name.?; + const table_type: TableType = table.type; + const table_access: TableAccess = table.access; const product_type_ref: AlgebraicTypeRef = AlgebraicTypeRef{ - .inner = addStructImpl(&structDecls, table.layout), + .inner = addStructImpl(&structDecls, table.schema), }; - tables = tables ++ &[_]RawTableDefV9{ + tableDefs = tableDefs ++ &[_]RawTableDefV9{ .{ .name = name, .product_type_ref = product_type_ref, @@ -362,64 +345,56 @@ pub fn compile(comptime moduleTables : anytype, comptime moduleReducers : anytyp }; } - 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; - if( std.mem.endsWith(u8, @typeName(field.type), "spacetime_10.0__reducer_")) { - const lifecycle: ?Lifecycle = default_values.lifecycle; - - var params: []const ProductTypeElement = &[_]ProductTypeElement{}; - const param_names = default_values.param_names; + inline for(moduleReducers) |reducer| { + const name: []const u8 = reducer.name.?; + const lifecycle: Lifecycle = reducer.lifecycle; + + var params: []const ProductTypeElement = &[_]ProductTypeElement{}; + const param_names = reducer.params; - for(@typeInfo(@TypeOf(default_values.func)).@"fn".params[1..], param_names) |param, param_name| { - params = params ++ &[_]ProductTypeElement{ - .{ - .name = param_name, - .algebraic_type = zigTypeToSpacetimeType(param.type), - } - }; - } - - reducers = reducers ++ &[_]RawReducerDefV9{ + for(@typeInfo(reducer.func_type).@"fn".params[1..], param_names) |param, param_name| { + params = params ++ &[_]ProductTypeElement{ .{ - .name = name, - .params = .{ .elements = params }, - .lifecycle = lifecycle, - }, + .name = param_name, + .algebraic_type = zigTypeToSpacetimeType(param.type), + } }; - continue; } - @compileLog(.{ field }); + + reducerDefs = reducerDefs ++ &[_]RawReducerDefV9{ + .{ + .name = name, + .params = .{ .elements = params }, + .lifecycle = lifecycle, + }, + }; } return .{ .typespace = .{ .types = raw_types, }, - .tables = tables, - .reducers = reducers, + .tables = tableDefs, + .reducers = reducerDefs, .types = types, .misc_exports = &[_]RawMiscModuleExportV9{}, .row_level_security = &[_]RawRowLevelSecurityDefV9{}, }; } -pub fn callReducer(comptime mdef: anytype, id: usize, args: anytype) void { - comptime var i = 0; - inline for(std.meta.fields(@TypeOf(mdef))) |field| { - if( comptime std.mem.endsWith(u8, @typeName(field.type), "spacetime_10.0__reducer_")) { - if(id == i) { - const func = @as(*const field.type, @alignCast(@ptrCast(field.default_value.?))).*.func; - if(std.meta.fields(@TypeOf(args)).len == @typeInfo(@TypeOf(func)).@"fn".params.len) { - return @call(.auto, func, args); - } - - const name: []const u8 = @as(*const field.type, @alignCast(@ptrCast(field.default_value.?))).*.name orelse field.name; - var buf: [128]u8 = undefined; - print(std.fmt.bufPrint(&buf, "invalid number of args passed to {s}, expected {} got {}", .{name, @typeInfo(@TypeOf(func)).@"fn".params.len, std.meta.fields(@TypeOf(args)).len}) catch "!!!Error while printing last error!!!"); - @panic("invalid number of args passed to func"); +pub fn callReducer(comptime mdef: []const Reducer, id: usize, args: anytype) void { + inline for(mdef, 0..) |field, i| { + if(id == i) { + const func = field.func_type; + if(std.meta.fields(@TypeOf(args)).len == @typeInfo(func).@"fn".params.len) { + const func_val: func = @as(*const func, @ptrCast(field.func)).*; + return @call(.auto, func_val, args); } - i += 1; + + const name: []const u8 = field.name.?; + var buf: [128]u8 = undefined; + print(std.fmt.bufPrint(&buf, "invalid number of args passed to {s}, expected {} got {}", .{name, @typeInfo(func).@"fn".params.len, std.meta.fields(@TypeOf(args)).len}) catch "!!!Error while printing last error!!!"); + @panic("invalid number of args passed to func"); } } } @@ -494,8 +469,64 @@ pub fn PrintModule(data: anytype) void { print("},"); } -const moduleTablesDef = @import("root").moduleTablesDef; -const moduleReducersDef = @import("root").moduleReducersDef; +pub const Param = struct { + name: []const u8, +}; + +pub const Reducer = struct { + name: ?[]const u8 = null, + lifecycle: Lifecycle = .None, + params: []const [:0]const u8 = &.{}, + param_types: ?[]type = null, + func_type: type, + func: *const fn()void, +}; + +pub const Table = struct { + name: ?[]const u8 = null, + schema: type, + type: TableType = .User, + access: TableAccess = .Private, +}; + +pub const reducers: []const Reducer = blk: { + var temp: []const Reducer = &.{}; + const root = @import("root"); + for(@typeInfo(root).@"struct".decls) |decl| { + const field = @field(root, decl.name); + if(@TypeOf(@field(root, decl.name)) == Reducer) { + temp = temp ++ &[_]Reducer{ + Reducer{ + .name = field.name orelse decl.name, + .lifecycle = field.lifecycle, + .params = field.params, + .func = field.func, + .func_type = field.func_type, + } + }; + } + } + break :blk temp; +}; + +pub const tables: []const Table = blk: { + var temp: []const Table = &.{}; + const root = @import("root"); + for(@typeInfo(root).@"struct".decls) |decl| { + const field = @field(root, decl.name); + if(@TypeOf(@field(root, decl.name)) == Table) { + temp = temp ++ &[_]Table{ + Table{ + .type = field.type, + .access = field.access, + .schema = field.schema, + .name = field.name orelse decl.name, + } + }; + } + } + break :blk temp; +}; pub export fn __describe_module__(description: BytesSink) void { const allocator = std.heap.wasm_allocator; @@ -504,7 +535,7 @@ pub export fn __describe_module__(description: BytesSink) void { var moduleDefBytes = std.ArrayList(u8).init(allocator); defer moduleDefBytes.deinit(); - const compiledModule = comptime compile(moduleTablesDef, moduleReducersDef) catch |err| { + const compiledModule = comptime compile(tables, reducers) catch |err| { var buf: [1024]u8 = undefined; const fmterr = std.fmt.bufPrint(&buf, "Error: {}", .{err}) catch { @compileError("ERROR2: No Space Left! Expand error buffer size!"); @@ -512,16 +543,11 @@ pub export fn __describe_module__(description: BytesSink) void { @compileError(fmterr); }; - //PrintModule(compiledModule); - serialize_module(&moduleDefBytes, compiledModule) catch { - print("Allocator Error: Cannot continue!"); - @panic("Allocator Error: Cannot continue!"); + print("Allocator Error: Cannot continue!"); + @panic("Allocator Error: Cannot continue!"); }; - //var buffer: [8196]u8 = undefined; - //print(std.fmt.bufPrint(&buffer, "{any}", .{moduleDefBytes.items}) catch "Expand buffer"); - write_to_sink(description, moduleDefBytes.items); } @@ -550,66 +576,62 @@ pub export fn __call_reducer__( }, }; - var i: usize = 0; - inline for(std.meta.fields(@TypeOf(moduleReducersDef))) |field| { - if( comptime std.mem.endsWith(u8, @typeName(field.type), "spacetime_10.0__reducer_")) { - defer i += 1; - if(id == i) { - 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; - comptime var argList: []const std.builtin.Type.StructField = &[_]std.builtin.Type.StructField{ + inline for(reducers, 0..) |reducer, i| { + if(id == i) { + const func = reducer.func_type; + const params = @typeInfo(func).@"fn".params; + const param_names = reducer.params; + comptime var argCount = 1; + comptime var argList: []const std.builtin.Type.StructField = &[_]std.builtin.Type.StructField{ + std.builtin.Type.StructField{ + .alignment = 0, + .default_value = null, + .is_comptime = false, + .name = "0", + .type = *ReducerContext, + } + }; + + inline for(params[1..], param_names) |param, name| { + _ = name; + argList = argList ++ &[_]std.builtin.Type.StructField{ std.builtin.Type.StructField{ .alignment = 0, .default_value = null, .is_comptime = false, - .name = "0", - .type = *ReducerContext, + .name = comptime utils.itoa(argCount), + .type = param.type.?, } }; - - inline for(params[1..], param_names) |param, name| { - _ = name; - argList = argList ++ &[_]std.builtin.Type.StructField{ - std.builtin.Type.StructField{ - .alignment = 0, - .default_value = null, - .is_comptime = false, - .name = comptime utils.itoa(argCount), - .type = param.type.?, - } - }; - argCount += 1; - } - - const argsStruct = @Type(.{ - .@"struct" = std.builtin.Type.Struct{ - .backing_integer = null, - .decls = &[_]std.builtin.Type.Declaration{}, - .fields = argList, - .is_tuple = true, - .layout = .auto, - } - }); - - var constructedArg: argsStruct = undefined; - - @field(constructedArg, "0") = &ctx; - - if(args.inner != 0) { - inline for(params, 0..) |param, name| { - comptime if(name == 0) continue; - @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"); - }; - } - } - - callReducer(moduleReducersDef, i, constructedArg); + argCount += 1; } + + const argsStruct = @Type(.{ + .@"struct" = std.builtin.Type.Struct{ + .backing_integer = null, + .decls = &[_]std.builtin.Type.Declaration{}, + .fields = argList, + .is_tuple = true, + .layout = .auto, + } + }); + + var constructedArg: argsStruct = undefined; + + @field(constructedArg, "0") = &ctx; + + if(args.inner != 0) { + inline for(params, 0..) |param, name| { + comptime if(name == 0) continue; + @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"); + }; + } + } + + callReducer(reducers, i, constructedArg); } } diff --git a/src/spacetime/serializer.zig b/src/spacetime/serializer.zig index b1674c7..39aa3df 100644 --- a/src/spacetime/serializer.zig +++ b/src/spacetime/serializer.zig @@ -65,9 +65,9 @@ fn serialize_raw_reducer_def_v9(array: *std.ArrayList(u8), val: RawReducerDefV9) for(val.params.elements) |element| { try serialize_product_type_element(array, element); } - try array.appendSlice(&[_]u8{ @intFromBool(val.lifecycle == null) }); - if(val.lifecycle) |lifecycle| { - try serialize_lifecycle(array, lifecycle); + try array.appendSlice(&[_]u8{ @intFromBool(val.lifecycle == .None) }); + if(val.lifecycle != .None) { + try serialize_lifecycle(array, val.lifecycle); } } @@ -146,6 +146,22 @@ fn serialize_table_access(array: *std.ArrayList(u8), val: TableAccess) !void { try array.appendSlice(&[_]u8{@intFromEnum(val)}); } +fn serialize_sum_type_variant(array: *std.ArrayList(u8), val: SumTypeVariant) !void { + try array.appendSlice(&[_]u8{ @intFromBool(val.name == null) }); + if(val.name) |name| { + try array.appendSlice(&std.mem.toBytes(@as(u32, @intCast(name.len)))); + try array.appendSlice(name); + } + try serialize_algebraic_type(array, val.algebraic_type); +} + +fn serialize_sum_type(array: *std.ArrayList(u8), val: SumType) std.mem.Allocator.Error!void { + try array.appendSlice(&std.mem.toBytes(@as(u32, @intCast(val.variants.len)))); + for(val.variants) |variant| { + try serialize_sum_type_variant(array, variant); + } +} + fn serialize_product_type_element(array: *std.ArrayList(u8), val: ProductTypeElement) !void { try array.appendSlice(&[_]u8{ 0 }); try array.appendSlice(&std.mem.toBytes(@as(u32, @intCast(val.name.len)))); @@ -170,6 +186,10 @@ fn serialize_algebraic_type(array: *std.ArrayList(u8), val: AlgebraicType) !void try array.appendSlice(&[_]u8{@intFromEnum(val)}); try array.appendSlice(&std.mem.toBytes(ref.inner)); }, + AlgebraicType.Sum => |sum| { + try array.appendSlice(&[_]u8{@intFromEnum(val)}); + try serialize_sum_type(array, sum); + }, else => try array.appendSlice(&[_]u8{@intFromEnum(val)}), } } diff --git a/src/spacetime/types.zig b/src/spacetime/types.zig index 5ca406d..44cbc79 100644 --- a/src/spacetime/types.zig +++ b/src/spacetime/types.zig @@ -127,13 +127,42 @@ pub const Lifecycle = enum { Init, OnConnect, OnDisconnect, + None, }; +fn getUnionSize(data: anytype) usize { + //const fields = std.meta.fields(@TypeOf(data)); + var size: usize = 0; + + switch(data) { + inline else => |field| { + switch(@TypeOf(field)) { + []const u8 => { + const val = @field(data, field.name); + size = @max(size, 4 + val.len); + }, + i64, u32, u64, f32 => { + size = @max(size, @sizeOf(field.type)); + }, + else => { + switch(@typeInfo(@TypeOf(field))) { + .@"struct" => { + size = @max(size, getStructSize(field)); + }, + .@"union" => { + size = @max(size, 1 + getUnionSize(field)); + }, + else => @compileError("Unsupported type in getUnionSize"), + } + } + } + } + } + + return size; +} + fn getStructSize(data: anytype) usize { - const struct_type = @TypeOf(data); - - const @"spacetime_10.0__table_" = utils.getMemberDefaultType(struct_type, spacetime.MagicStruct); - const fields = std.meta.fields(@TypeOf(data)); var size: usize = 0; inline for(fields) |field| { @@ -142,23 +171,18 @@ fn getStructSize(data: anytype) usize { const val = @field(data, field.name); size += 4 + val.len; }, - u32 => { - size += 4; + i64, u32, u64, f32 => { + size += @sizeOf(field.type); }, - u64 => { - size += 8; - }, - f32 => { - size += 4; - }, - @"spacetime_10.0__table_" => {}, else => blk: { - if(@typeInfo(field.type) == .@"struct" and std.meta.fieldIndex(field.type, spacetime.MagicStruct) != null) { + if(@typeInfo(field.type) == .@"struct") { size += getStructSize(@field(data, field.name)); break :blk; + } else if(@typeInfo(field.type) == .@"union") { + size += 1 + getUnionSize(@field(data, field.name)); + break :blk; } - @compileLog(field.type); - @compileError("Unsupported type in StructSerializer"); + @compileError("Unsupported type in getStructSize"); }, } } @@ -166,10 +190,19 @@ fn getStructSize(data: anytype) usize { return size; } -fn getStructData(data: anytype, mem: []u8) []u8 { - const struct_type = @TypeOf(data); - const @"spacetime_10.0__table_" = utils.getMemberDefaultType(struct_type, spacetime.MagicStruct); +fn getUnionData(data: anytype, mem: []u8) []u8 { + var offset_mem = mem; + switch(data) { + inline else => |field| { + std.mem.bytesAsValue(u8, offset_mem[0..@sizeOf(u8)]).* = @intFromEnum(data); + offset_mem = offset_mem[@sizeOf(u8)..]; + offset_mem = getStructData(field, offset_mem); + }, + } + return offset_mem; +} +fn getStructData(data: anytype, mem: []u8) []u8 { const fields = std.meta.fields(@TypeOf(data)); var offset_mem = mem; inline for(fields) |field| { @@ -180,26 +213,18 @@ fn getStructData(data: anytype, mem: []u8) []u8 { std.mem.copyForwards(u8, offset_mem[4..], val); offset_mem = offset_mem[4 + val.len ..]; }, - u32 => { + i32, i64, u32, u64, f32 => { const val = @field(data, field.name); - std.mem.bytesAsValue(u32, offset_mem[0..4]).* = val; - offset_mem = offset_mem[4..]; + std.mem.bytesAsValue(field.type, offset_mem[0..@sizeOf(field.type)]).* = val; + offset_mem = offset_mem[@sizeOf(field.type)..]; }, - u64 => { - const val = @field(data, field.name); - std.mem.bytesAsValue(u64, offset_mem[0..4]).* = val; - offset_mem = offset_mem[8..]; - }, - f32 => { - const val = @field(data, field.name); - std.mem.bytesAsValue(f32, offset_mem[0..4]).* = val; - offset_mem = offset_mem[4..]; - }, - @"spacetime_10.0__table_" => {}, else => blk: { - if(@typeInfo(field.type) == .@"struct" and std.meta.fieldIndex(field.type, spacetime.MagicStruct) != null) { + if(@typeInfo(field.type) == .@"struct") { offset_mem = getStructData(@field(data, field.name), offset_mem); break :blk; + } else if(@typeInfo(field.type) == .@"union") { + offset_mem = getUnionData(@field(data, field.name), offset_mem); + break :blk; } @compileLog(field.type); @compileError("Unsupported type in StructSerializer"); @@ -220,9 +245,52 @@ pub fn StructSerializer(struct_type: type) fn(std.mem.Allocator, struct_type) st }.serialize; } +pub fn UnionDeserializer(union_type: type) fn(allocator: std.mem.Allocator, *[]const u8) std.mem.Allocator.Error!*union_type { + return struct { + pub fn deserialize(allocator: std.mem.Allocator, data: *[]const u8) std.mem.Allocator.Error!*union_type { + const ret = try allocator.create(union_type); + var offset_mem = data.*; + + const tagType = u8; + + const tag: std.meta.Tag(union_type) = @enumFromInt(std.mem.bytesAsValue(tagType, offset_mem[0..@sizeOf(tagType)]).*); + offset_mem = offset_mem[@sizeOf(tagType)..]; + switch(tag) { + inline else => |union_field| { + const field = std.meta.fields(union_type)[@intFromEnum(union_field)]; + switch(field.type) { + []const u8 => { + const len = std.mem.bytesAsValue(u32, offset_mem[0..4]).*; + const str = try allocator.dupe(u8, offset_mem[4..(4+len)]); + @field(ret.*, field.name) = str; + offset_mem = offset_mem[4+len ..]; + }, + u32, u64, i32, i64, f32 => { + @field(ret.*, field.name) = std.mem.bytesAsValue(field.type, offset_mem[0..@sizeOf(field.type)]).*; + offset_mem = offset_mem[@sizeOf(field.type)..]; + }, + else => blk: { + if(@typeInfo(field.type) == .@"struct") { + @field(ret.*, field.name) = (try StructDeserializer(field.type)(allocator, &offset_mem)).*; + break :blk; + } else if(@typeInfo(field.type) == .@"union") { + @field(ret.*, field.name) = (try UnionDeserializer(field.type)(allocator, &offset_mem)).*; + break :blk; + } + @compileLog(field.type); + @compileError("Unsupported type in StructDeserializer"); + }, + } + } + } + + data.* = offset_mem; + return ret; + } + }.deserialize; +} + pub fn StructDeserializer(struct_type: type) fn(allocator: std.mem.Allocator, *[]const u8) std.mem.Allocator.Error!*struct_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 { const ret = try allocator.create(struct_type); @@ -236,23 +304,17 @@ pub fn StructDeserializer(struct_type: type) fn(allocator: std.mem.Allocator, *[ @field(ret.*, field.name) = str; offset_mem = offset_mem[4+len ..]; }, - u32 => { - @field(ret.*, field.name) = std.mem.bytesAsValue(u32, offset_mem[0..4]).*; - offset_mem = offset_mem[4..]; + u32, u64, i32, i64, f32 => { + @field(ret.*, field.name) = std.mem.bytesAsValue(field.type, offset_mem[0..@sizeOf(field.type)]).*; + offset_mem = offset_mem[@sizeOf(field.type)..]; }, - u64 => { - @field(ret.*, field.name) = std.mem.bytesAsValue(u64, offset_mem[0..4]).*; - offset_mem = offset_mem[8..]; - }, - f32 => { - @field(ret.*, field.name) = std.mem.bytesAsValue(f32, offset_mem[0..4]).*; - offset_mem = offset_mem[4..]; - }, - @"spacetime_10.0__table_" => {}, else => blk: { - if(@typeInfo(field.type) == .@"struct" and std.meta.fieldIndex(field.type, spacetime.MagicStruct) != null) { + if(@typeInfo(field.type) == .@"struct") { @field(ret.*, field.name) = (try StructDeserializer(field.type)(allocator, &offset_mem)).*; break :blk; + } else if(@typeInfo(field.type) == .@"union") { + @field(ret.*, field.name) = (try UnionDeserializer(field.type)(allocator, &offset_mem)).*; + break :blk; } @compileLog(field.type); @compileError("Unsupported type in StructDeserializer"); @@ -265,9 +327,15 @@ pub fn StructDeserializer(struct_type: type) fn(allocator: std.mem.Allocator, *[ }.deserialize; } -pub fn Table2ORM(comptime table_type: type) type { - const table_name = utils.getMemberDefaultValue(table_type, "name"); - const struct_type = utils.getMemberDefaultValue(table_type, "layout"); +pub fn Table2ORM(comptime table_name: []const u8) type { + const table = blk: { + for(spacetime.tables) |table| { + if(std.mem.eql(u8, table_name, table.name.?)) { + break :blk table; + } + } + }; + const struct_type = table.schema; return struct { allocator: std.mem.Allocator, @@ -343,7 +411,7 @@ pub fn Table2ORM(comptime table_type: type) type { pub const Local = struct { allocator: std.mem.Allocator, - pub fn get(self: @This(), table: anytype) Table2ORM(table) { + pub fn get(self: @This(), comptime table: []const u8) Table2ORM(table) { return .{ .allocator = self.allocator, }; @@ -362,7 +430,7 @@ pub const ReducerFn = fn(*ReducerContext) void; pub const RawReducerDefV9 = struct { name: RawIdentifier, params: ProductType, - lifecycle: ?Lifecycle, + lifecycle: Lifecycle, }; pub const RawScopedTypeNameV9 = struct {