diff --git a/build.zig b/build.zig index 1a31bbd..43f2446 100644 --- a/build.zig +++ b/build.zig @@ -9,11 +9,11 @@ pub fn build(b: *std.Build) void { // means any target is allowed, and the default is native. Other options // for restricting supported target set are available. - //const target = b.resolveTargetQuery(.{ - // .cpu_arch = .wasm32, - // .os_tag = .freestanding, - //}); - const target = b.standardTargetOptions(.{}); + const target = b.resolveTargetQuery(.{ + .cpu_arch = .wasm32, + .os_tag = .freestanding, + }); + //const target = b.standardTargetOptions(.{}); // Standard optimization options allow the person running `zig build` to select // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not diff --git a/publish-local.sh b/publish-local.sh new file mode 100755 index 0000000..2dc1aac --- /dev/null +++ b/publish-local.sh @@ -0,0 +1,3 @@ +spacetime logout +spacetime login --server-issued-login local +spacetime publish -y --server local --bin-path=zig-out/bin/stdb-zig-helloworld.wasm \ No newline at end of file diff --git a/src/main.zig b/src/main.zig index b9ab24b..9307843 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,426 +1,102 @@ const std = @import("std"); +const spacetime = @import("spacetime.zig"); -//extern "spacetime_10.0" -pub fn console_log( - level: u8, - target_ptr: [*c]const u8, - target_len: usize, - filename_ptr: [*c]const u8, - filename_len: usize, - line_number: u32, - message_ptr: [*c]const u8, - message_len: usize, -) void { - _ = level; - _ = target_ptr; - _ = target_len; - _ = filename_ptr; - _ = filename_len; - _ = line_number; - _ = message_ptr; - _ = message_len; +const reducers = spacetime.parse_reducers(@This()); + +pub fn print(fmt: []const u8) void { + spacetime.console_log(2, null, 0, null, 0, 0, fmt.ptr, fmt.len); } -const BytesSink = extern struct { inner: u32 }; -const BytesSource = extern struct { inner: u32 }; - -//extern "spacetime_10.0" -pub fn bytes_sink_write(sink: BytesSink, buffer_ptr: [*c]const u8, buffer_len_ptr: *usize) u16 { - _ = sink; - _ = buffer_ptr; - _ = buffer_len_ptr; - return 0; -} - -const NO_SUCH_BYTES = 8; -const NO_SPACE = 9; - -fn write_to_sink(sink: BytesSink, _buf: []const u8) void { - var buf: []const u8 = _buf; - while(true) { - const len: *usize = &buf.len; - switch(bytes_sink_write(sink, buf.ptr, len)) { - 0 => { - // Set `buf` to remainder and bail if it's empty. - buf = buf[len.*..]; - if(buf.len == 0) { - break; +const moduleDef: spacetime.RawModuleDefV9 = .{ + .typespace = .{ + .types = &[_]spacetime.AlgebraicType{ + .{ + .Product = .{ + .elements = &[_]spacetime.ProductTypeElement{ + .{ + .name = "name", + .algebraic_type = .String, + } + } } }, - NO_SUCH_BYTES => @panic("invalid sink passed"), - NO_SPACE => @panic("no space left at sink"), - else => unreachable, + }, + }, + .tables = &[_]spacetime.RawTableDefV9{ + .{ + .name = "person", + .product_type_ref = .{ .inner = 0, }, + .primary_key = &[_]u16{}, + .indexes = &[_]spacetime.RawIndexDefV9{}, + .constraints = &[_]spacetime.RawConstraintDefV9{}, + .sequences = &[_]spacetime.RawSequenceDefV9{}, + .schedule = null, + .table_type = .User, + .table_access = .Private, } - } -} - -//pub const ReducerFn = fn(ReducerContext, []u8) ReducerResult; - -pub const SumTypeVariant = struct { - name: ?*[]u8, - algebraic_type: AlgebraicType, + }, + .reducers = reducers, + //&[_]spacetime.RawReducerDefV9{ + //.{ + // .name = "add", + // .params = .{ + // .elements = &[_]spacetime.ProductTypeElement{ + // .{ + // .name = "name", + // .algebraic_type = .String, + // } + // } + // }, + // .lifecycle = null, + //}, + //.{ + // .name = "identity_connected", + // .params = .{ .elements = &[_]spacetime.ProductTypeElement{} }, + // .lifecycle = .OnConnect, + //}, + //.{ + // .name = "identity_disconnected", + // .params = .{ .elements = &[_]spacetime.ProductTypeElement{} }, + // .lifecycle = .OnDisconnect, + //}, + //.{ + // .name = "init", + // .params = .{ .elements = &[_]spacetime.ProductTypeElement{} }, + // .lifecycle = .Init, + //}, + //.{ + // .name = "say_hello", + // .params = .{ .elements = &[_]spacetime.ProductTypeElement{} }, + // .lifecycle = null, + //} + //}, + .types = &[_]spacetime.RawTypeDefV9{ + .{ + .name = .{ + .scope = &[_][]u8{}, + .name = "Person" + }, + .ty = .{ .inner = 0, }, + .custom_ordering = true, + } + }, + .misc_exports = &[_]spacetime.RawMiscModuleExportV9{}, + .row_level_security = &[_]spacetime.RawRowLevelSecurityDefV9{}, }; -pub const SumType = struct { - variants: []SumTypeVariant, -}; - -pub const ArrayType = struct { - /// The base type every element of the array has. - elem_ty: []AlgebraicType, -}; - -pub const AlgebraicType = union(enum) { - Ref: AlgebraicTypeRef, - Sum: SumType, - Product: ProductType, - Array: ArrayType, - String: []u8, - Bool: bool, - I8: i8, - U8: u8, - I16: i16, - U16: u16, - I32: i32, - U32: u32, - I64: i64, - U64: u64, - I128: i128, - U128: u128, - I256: i256, - U256: u256, - F32: f32, - F64: f64, -}; - -pub const Typespace = struct { - types: []AlgebraicType, -}; - -pub const RawIdentifier = *[*c]u8; - -pub const AlgebraicTypeRef = struct { - inner: u32, -}; - -pub const RawIndexAlgorithm = union { - BTree: []u16, - Hash: []u16, - Direct: u16, -}; - -pub const RawIndexDefV9 = struct { - name: ?[]u8, - accessor_name: ?[]u8, - algorithm: RawIndexAlgorithm, -}; - -pub const RawUniqueConstraintDataV9 = union { - Columns: u16, -}; - -pub const RawConstraintDataV9 = union { - unique: RawUniqueConstraintDataV9, -}; - -pub const RawConstraintDefV9 = struct { - name: ?[]u8, - data: RawConstraintDataV9 -}; - -pub const RawSequenceDefV9 = struct { - Name: ?[]u8, - Column: u16, - Start: ?i128, - MinValue: ?i128, - MaxValue: ?i128, - Increment: i128 -}; - -pub const RawScheduleDefV9 = struct { - Name: ?[]u8, - ReducerName: []u8, - ScheduledAtColumn: u16 -}; - -pub const TableType = enum { - System, - User, -}; - -pub const TableAccess = enum { - Public, - Private, -}; - -pub const RawTableDefV9 = struct { - name: RawIdentifier, - product_type_ref: AlgebraicTypeRef, - primary_key: []u16, - indexes: []RawIndexDefV9, - constraints: []RawConstraintDefV9, - sequences: []RawSequenceDefV9, - schedule: ?RawScheduleDefV9, - table_type: TableType, - table_access: TableAccess, -}; - -pub const ProductTypeElement = struct { - name: ?*[]u8, - algebraic_type: AlgebraicType, -}; - -pub const ProductType = struct { - elements: []ProductTypeElement, -}; - -pub const Lifecycle = enum { - Init, - OnConnect, - OnDisconnect, -}; - -pub const RawReducerDefV9 = struct{ - name: RawIdentifier, - params: ProductType, - lifecycle: ?Lifecycle, -}; - -pub const RawScopedTypeNameV9 = struct { - scope: [][]u8, - name: []u8, -}; - -pub const RawTypeDefV9 = struct { - name: RawScopedTypeNameV9, - ty: AlgebraicTypeRef, - custom_ordering: bool, -}; - -pub const RawMiscModuleExportV9 = enum {}; - -pub const RawSql = *[*c]u8; - -pub const RawRowLevelSecurityDefV9 = struct { - sql: RawSql, -}; - -pub const RawModuleDefV9 = struct { - typespace: Typespace, - tables: []RawTableDefV9, - reducers: []RawReducerDefV9, - types: []RawTypeDefV9, - misc_exports: []RawMiscModuleExportV9, - row_level_security: []RawRowLevelSecurityDefV9, -}; - -// V9( -// RawModuleDefV9 { -// typespace: Typespace [ -// Product( -// ProductType { -// "name": String, -// }, -// ), -// ], -// tables: [ -// RawTableDefV9 { -// name: "person", -// product_type_ref: AlgebraicTypeRef( -// 0, -// ), -// primary_key: [], -// indexes: [], -// constraints: [], -// sequences: [], -// schedule: None, -// table_type: User, -// table_access: Private, -// }, -// ], -// reducers: [ -// RawReducerDefV9 { -// name: "add", -// params: ProductType { -// "name": String, -// }, -// lifecycle: None, -// }, -// RawReducerDefV9 { -// name: "identity_connected", -// params: ProductType {}, -// lifecycle: Some( -// OnConnect, -// ), -// }, -// RawReducerDefV9 { -// name: "identity_disconnected", -// params: ProductType {}, -// lifecycle: Some( -// OnDisconnect, -// ), -// }, -// RawReducerDefV9 { -// name: "init", -// params: ProductType {}, -// lifecycle: Some( -// Init, -// ), -// }, -// RawReducerDefV9 { -// name: "say_hello", -// params: ProductType {}, -// lifecycle: None, -// }, -// ], -// types: [ -// RawTypeDefV9 { -// name: "Person", -// ty: AlgebraicTypeRef( -// 0, -// ), -// custom_ordering: true, -// }, -// ], -// misc_exports: [], -// row_level_security: [], -// }, -// ) - -const bytes = [_]u8{ - 1, //VP9 - 1, 0, 0, 0, //Typespace.types.len - 2, //Typespace.types[0].tag(Product) - 1, 0, 0, 0, //Typespace.types[0].tag(Product).elements.len - 0, // optional? - 4, 0, 0, 0, //Typespace.types[0].tag(Product).elements[0].name.len - 110, 97, 109, 101, //Typespace.types[0].tag(Product).elements[0].name[0..4] "name" - 4, //Typespace.types[0].tag(Product).elements[0].algebraic_type(String) - 1, 0, 0, 0, //Typespace.types[0].tag(Product).elements[0].algebraic_type(String).len +export fn __describe_module__(description: spacetime.BytesSink) void { + const allocator = std.heap.wasm_allocator; + print("Hello from Zig!"); - 6, 0, 0, 0, //tables[0].name.len - 112, 101, 114, 115, 111, 110, //tables[0].name "person" - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 1, - 1, - 1, - 5, 0, 0, 0, - - 3, 0, 0, 0, - 97, 100, 100, - - 1, 0, 0, 0, - 0, - - 4, 0, 0, 0, - 110, 97, 109, 101, - 4, - 1, - 18, 0, 0, 0, - 105, 100, 101, 110, 116, 105, 116, 121, 95, 99, 111, 110, 110, 101, 99, 116, 101, 100, - - 0, 0, 0, 0, - 0, - 1, - 21, 0, 0, 0, - 105, 100, 101, 110, 116, 105, 116, 121, 95, 100, 105, 115, 99, 111, 110, 110, 101, 99, 116, 101, 100, - - 0, 0, 0, 0, - 0, - 2, - 4, 0, 0, 0, - 105, 110, 105, 116, - 0, 0, 0, 0, - 0, - 0, - 9, 0, 0, 0, - 115, 97, 121, 95, 104, 101, 108, 108, 111, - 0, 0, 0, 0, - 1, - 1, - 0, 0, 0, 0, - - 0, 0, 0, - - 6, 0, 0, 0, - 80, 101, 114, 115, 111, 110, - - 0, 0, 0, 0, - 1, 0, 0, 0, - 0, 0, 0, 0, - 0 -}; + var moduleDefBytes = std.ArrayList(u8).init(allocator); + defer moduleDefBytes.deinit(); -pub fn print(comptime fmt: []const u8) void { - console_log(0, null, 0, null, 0, 0, fmt.ptr, fmt.len); -} + spacetime.serialize_module(&moduleDefBytes, moduleDef) catch { + print("Allocator Error: Cannot continue!"); + @panic("Allocator Error: Cannot continue!"); + }; -pub fn module_write(val: anytype) void { - switch(@TypeOf(val)) { - RawModuleDefV9 => { - std.debug.print("{{ 1 }},\n", .{}); - module_write(val.typespace); - }, - Typespace => { - std.debug.print("{any},\n", .{std.mem.toBytes(@as(u32, @intCast(val.types.len)))}); - for(val.types) |_type| { - module_write(_type); - } - }, - AlgebraicType => { - switch(val) { - AlgebraicType.String => |string| { - std.debug.print("{any},\n", .{string}); - }, - AlgebraicType.Product => |product| { - module_write(product); - }, - else => std.debug.print("{any},\n", .{val}), - } - }, - ProductType => { - std.debug.print("{any},\n", .{std.mem.toBytes(@as(u32, @intCast(val.elements.len)))}); - for(val.elements) |element| { - module_write(element); - } - - }, - ProductTypeElement => { - if(val.name == null) { - std.debug.print("{{ 1 }},\n", .{}); - } else { - std.debug.print("{{ 0 }},\n", .{}); - std.debug.print("{any},\n", .{val.name}); - } - module_write(val.algebraic_type); - }, - else => |v| @compileLog(v, val), - } -} - -test { - const moduleDef: RawModuleDefV9 = std.mem.zeroes(RawModuleDefV9); - module_write(moduleDef); -} - -export fn __describe_module__(description: BytesSink) void { - console_log(0, null, 0, null, 0, 0, "Hello from Zig!", 15); - - const moduleDef: RawModuleDefV9 = std.mem.zeroes(RawModuleDefV9); - //moduleDef. - - // We need this explicit cast here to make `ToBytes` understand the types correctly. - //RawModuleDef versioned = new RawModuleDef.V9(moduleDef); - //var moduleBytes = IStructuralReadWrite.ToBytes(new RawModuleDef.BSATN(), versioned); - //description.Write(moduleBytes); - module_write(moduleDef); - - - write_to_sink(description, &bytes); + spacetime.write_to_sink(description, moduleDefBytes.items); } export fn __call_reducer__( @@ -432,41 +108,59 @@ export fn __call_reducer__( conn_id_0: u64, conn_id_1: u64, timestamp: u64, - args: BytesSource, - err: BytesSink, + args: spacetime.BytesSource, + err: spacetime.BytesSink, ) i16 { - _ = id; - _ = sender_0; - _ = sender_1; - _ = sender_2; - _ = sender_3; - _ = conn_id_0; - _ = conn_id_1; - _ = timestamp; - _ = args; - _ = err; + const allocator = std.heap.wasm_allocator; + + print(std.fmt.allocPrint(allocator, "id: {}", .{id}) catch "id: err"); + print(std.fmt.allocPrint(allocator, "sender_0: {}", .{sender_0}) catch "sender_0: err"); + print(std.fmt.allocPrint(allocator, "sender_1: {}", .{sender_1}) catch "sender_1: err"); + print(std.fmt.allocPrint(allocator, "sender_2: {}", .{sender_2}) catch "sender_2: err"); + print(std.fmt.allocPrint(allocator, "sender_3: {}", .{sender_3}) catch "sender_3: err"); + print(std.fmt.allocPrint(allocator, "conn_id_0: {}", .{conn_id_0}) catch "conn_id_0: err"); + print(std.fmt.allocPrint(allocator, "conn_id_1: {}", .{conn_id_1}) catch "conn_id_1: err"); + print(std.fmt.allocPrint(allocator, "timestamp: {}", .{timestamp}) catch "timestamp: err"); + print(std.fmt.allocPrint(allocator, "args: {}", .{args}) catch "args: err"); + print(std.fmt.allocPrint(allocator, "err: {}", .{err}) catch "err: err"); return 0; } -const ReducerContext = anyopaque; +pub const Person = struct{ + name: []u8, +}; -var module: RawModuleDefV9 = .{}; - -const ReducerFn = fn(*ReducerContext) void; - -comptime { - for(@typeInfo(@This()).@"struct".decls) |decl| { - const field = @field(@This(), decl.name); - if(@typeInfo(@TypeOf(field)) != .@"fn") continue; - if(@TypeOf(field) != ReducerFn) continue; - - @compileLog(.{field}); - } -} - -pub fn init(_ctx: *ReducerContext) void { +pub fn Init(_ctx: *spacetime.ReducerContext) void { // Called when the module is initially published _ = _ctx; - console_log(0, null, 0, null, 0, 0, "Hello, init!", 12); + print("Hello, Init!"); +} + +pub fn OnConnect(_ctx: *spacetime.ReducerContext) void { + // Called everytime a new client connects + _ = _ctx; + print("Hello, OnConnect!"); +} + +pub fn OnDisconnect(_ctx: *spacetime.ReducerContext) void { + // Called everytime a client disconnects + _ = _ctx; + print("Hello, OnDisconnect!"); +} + +pub fn add(_ctx: *spacetime.ReducerContext, name: []u8) void { + _ = _ctx; + _ = name; + //ctx.db.person().insert(Person { name }); +} + +//#[spacetimedb::reducer] +pub fn say_hello(_ctx: *spacetime.ReducerContext) void { + //for person in ctx.db.person().iter() { + // log::info!("Hello, {}!", person.name); + //} + //log::info!("Hello, World!"); + _ = _ctx; + print("Hello, World!"); } \ No newline at end of file diff --git a/src/spacetime.zig b/src/spacetime.zig new file mode 100644 index 0000000..48b69d1 --- /dev/null +++ b/src/spacetime.zig @@ -0,0 +1,108 @@ +const std = @import("std"); + +pub const types = @import("spacetime/types.zig"); +pub const serializer = @import("spacetime/serializer.zig"); + +pub const SumTypeVariant = types.SumTypeVariant; +pub const SumType = types.SumType; +pub const ArrayType = types.ArrayType; +pub const AlgebraicType = types.AlgebraicType; +pub const Typespace = types.Typespace; +pub const RawIdentifier = types.RawIdentifier; +pub const AlgebraicTypeRef = types.AlgebraicTypeRef; +pub const RawIndexAlgorithm = types.RawIndexAlgorithm; +pub const RawIndexDefV9 = types.RawIndexDefV9; +pub const RawUniqueConstraintDataV9 = types.RawUniqueConstraintDataV9; +pub const RawConstraintDataV9 = types.RawConstraintDataV9; +pub const RawConstraintDefV9 = types.RawConstraintDefV9; +pub const RawSequenceDefV9 = types.RawSequenceDefV9; +pub const RawScheduleDefV9 = types.RawScheduleDefV9; +pub const TableType = types.TableType; +pub const TableAccess = types.TableAccess; +pub const RawTableDefV9 = types.RawTableDefV9; +pub const ProductTypeElement = types.ProductTypeElement; +pub const ProductType = types.ProductType; +pub const Lifecycle = types.Lifecycle; +pub const ReducerContext = types.ReducerContext; +pub const ReducerFn = types.ReducerFn; +pub const RawReducerDefV9 = types.RawReducerDefV9; +pub const RawScopedTypeNameV9 = types.RawScopedTypeNameV9; +pub const RawTypeDefV9 = types.RawTypeDefV9; +pub const RawMiscModuleExportV9 = types.RawMiscModuleExportV9; +pub const RawSql = types.RawSql; +pub const RawRowLevelSecurityDefV9 = types.RawRowLevelSecurityDefV9; +pub const RawModuleDefV9 = types.RawModuleDefV9; + +pub const serialize_module = serializer.serialize_module; + +pub extern "spacetime_10.0" fn console_log( + level: u8, + target_ptr: [*c]const u8, + target_len: usize, + filename_ptr: [*c]const u8, + filename_len: usize, + line_number: u32, + message_ptr: [*c]const u8, + message_len: usize, +) void; + +pub const BytesSink = extern struct { inner: u32 }; +pub const BytesSource = extern struct { inner: u32 }; + +pub extern "spacetime_10.0" fn bytes_sink_write(sink: BytesSink, buffer_ptr: [*c]const u8, buffer_len_ptr: *usize) u16; + +const NO_SUCH_BYTES = 8; +const NO_SPACE = 9; + +pub fn write_to_sink(sink: BytesSink, _buf: []const u8) void { + var buf: []const u8 = _buf; + while(true) { + const len: *usize = &buf.len; + switch(bytes_sink_write(sink, buf.ptr, len)) { + 0 => { + // Set `buf` to remainder and bail if it's empty. + buf = buf[len.*..]; + if(buf.len == 0) { + break; + } + }, + NO_SUCH_BYTES => @panic("invalid sink passed"), + NO_SPACE => @panic("no space left at sink"), + else => unreachable, + } + } +} + +pub fn parse_reducers(root: type) []const RawReducerDefV9 { + const decls = std.meta.declarations(root); + //@compileLog(.{ decls }); + + var reducers : []const RawReducerDefV9 = &[_]RawReducerDefV9{}; + _ = &reducers; + + inline for(decls) |decl| { + + const temp = @field(root, decl.name); + const temp_type = @typeInfo(@TypeOf(temp)); + if(temp_type != .@"fn") continue; + if(temp_type.@"fn".params[0].type.? != *ReducerContext) continue; + + const lifecycle: ?Lifecycle = blk: { + if(std.mem.eql(u8, decl.name, "Init")) break :blk .Init; + if(std.mem.eql(u8, decl.name, "OnConnect")) break :blk .OnConnect; + if(std.mem.eql(u8, decl.name, "OnDisconnect")) break :blk .OnDisconnect; + break :blk null; + }; + + reducers = reducers ++ &[_]RawReducerDefV9{ + .{ + .name = decl.name, + .params = .{ .elements = &[_]ProductTypeElement{} }, + .lifecycle = lifecycle, + }, + }; + + } + + return reducers; +} \ No newline at end of file diff --git a/src/spacetime/serializer.zig b/src/spacetime/serializer.zig new file mode 100644 index 0000000..9616e46 --- /dev/null +++ b/src/spacetime/serializer.zig @@ -0,0 +1,211 @@ +const std = @import("std"); + +pub const types = @import("types.zig"); + +pub const SumTypeVariant = types.SumTypeVariant; +pub const SumType = types.SumType; +pub const ArrayType = types.ArrayType; +pub const AlgebraicType = types.AlgebraicType; +pub const Typespace = types.Typespace; +pub const RawIdentifier = types.RawIdentifier; +pub const AlgebraicTypeRef = types.AlgebraicTypeRef; +pub const RawIndexAlgorithm = types.RawIndexAlgorithm; +pub const RawIndexDefV9 = types.RawIndexDefV9; +pub const RawUniqueConstraintDataV9 = types.RawUniqueConstraintDataV9; +pub const RawConstraintDataV9 = types.RawConstraintDataV9; +pub const RawConstraintDefV9 = types.RawConstraintDefV9; +pub const RawSequenceDefV9 = types.RawSequenceDefV9; +pub const RawScheduleDefV9 = types.RawScheduleDefV9; +pub const TableType = types.TableType; +pub const TableAccess = types.TableAccess; +pub const RawTableDefV9 = types.RawTableDefV9; +pub const ProductTypeElement = types.ProductTypeElement; +pub const ProductType = types.ProductType; +pub const Lifecycle = types.Lifecycle; +pub const ReducerContext = types.ReducerContext; +pub const ReducerFn = types.ReducerFn; +pub const RawReducerDefV9 = types.RawReducerDefV9; +pub const RawScopedTypeNameV9 = types.RawScopedTypeNameV9; +pub const RawTypeDefV9 = types.RawTypeDefV9; +pub const RawMiscModuleExportV9 = types.RawMiscModuleExportV9; +pub const RawSql = types.RawSql; +pub const RawRowLevelSecurityDefV9 = types.RawRowLevelSecurityDefV9; +pub const RawModuleDefV9 = types.RawModuleDefV9; + +fn serialize_raw_table_def_v9(array: *std.ArrayList(u8), val: RawTableDefV9) !void { + try array.appendSlice(&std.mem.toBytes(@as(u32, @intCast(val.name.len)))); + try array.appendSlice(val.name); + try serialize_algebraic_type_ref(array, val.product_type_ref); + try array.appendSlice(&std.mem.toBytes(@as(u32, @intCast(val.primary_key.len)))); + try array.appendSlice(std.mem.sliceAsBytes(val.primary_key)); + try array.appendSlice(&std.mem.toBytes(@as(u32, @intCast(val.indexes.len)))); + for(val.indexes) |index| { + try serialize_raw_index_def_v9(array, index); + } + try array.appendSlice(&std.mem.toBytes(@as(u32, @intCast(val.constraints.len)))); + for(val.constraints) |constraint| { + try serialize_raw_constraint_def_v9(array, constraint); + } + try array.appendSlice(&std.mem.toBytes(@as(u32, @intCast(val.sequences.len)))); + for(val.sequences) |sequence| { + try serialize_raw_sequence_def_v9(array, sequence); + } + try array.appendSlice(&[_]u8{ @intFromBool(val.schedule == null) }); + if(val.schedule) |schedule| { + try serialize_raw_schedule_def_v9(array, schedule); + } + try serialize_table_type(array, val.table_type); + try serialize_table_access(array, val.table_access); +} + +fn serialize_raw_reducer_def_v9(array: *std.ArrayList(u8), val: RawReducerDefV9) !void { + try array.appendSlice(&std.mem.toBytes(@as(u32, @intCast(val.name.len)))); + try array.appendSlice(val.name); + try array.appendSlice(&std.mem.toBytes(@as(u32, @intCast(val.params.elements.len)))); + 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); + } +} + +fn serialize_lifecycle(array: *std.ArrayList(u8), val: Lifecycle) !void { + try array.appendSlice(&[_]u8{@intFromEnum(val)}); +} + +fn serialize_algebraic_type_ref(array: *std.ArrayList(u8), val: AlgebraicTypeRef) !void { + try array.appendSlice(&std.mem.toBytes(@as(u32, @intCast(val.inner)))); +} + +fn serialize_raw_type_def_v9(array: *std.ArrayList(u8), val: RawTypeDefV9) !void { + try serialize_raw_scoped_type_name_v9(array, val.name); + try serialize_algebraic_type_ref(array, val.ty); + try serialize_bool(array, val.custom_ordering); +} + +fn serialize_raw_scoped_type_name_v9(array: *std.ArrayList(u8), val: RawScopedTypeNameV9) !void { + try array.appendSlice(&std.mem.toBytes(@as(u32, @intCast(val.scope.len)))); + for(val.scope) |sub_scope| { + try serialize_raw_identifier(array, sub_scope); + } + try serialize_raw_identifier(array, val.name); +} + +fn serialize_raw_identifier(array: *std.ArrayList(u8), val: RawIdentifier) !void { + try array.appendSlice(&std.mem.toBytes(@as(u32, @intCast(val.len)))); + try array.appendSlice(val); +} + +fn serialize_bool(array: *std.ArrayList(u8), val: bool) !void { + try array.appendSlice(&[_]u8{@intFromBool(val)}); +} + +fn serialize_raw_misc_module_export_v9(array: *std.ArrayList(u8), val: RawMiscModuleExportV9) !void { + _ = array; + _ = val; + unreachable; +} + +fn serialize_raw_row_level_security_def_v9(array: *std.ArrayList(u8), val: RawRowLevelSecurityDefV9) !void { + _ = array; + _ = val; + unreachable; +} + +fn serialize_raw_index_def_v9(array: *std.ArrayList(u8), val: RawIndexDefV9) !void { + _ = array; + _ = val; + unreachable; +} + +fn serialize_raw_constraint_def_v9(array: *std.ArrayList(u8), val: RawConstraintDefV9) !void { + _ = array; + _ = val; + unreachable; +} + +fn serialize_raw_sequence_def_v9(array: *std.ArrayList(u8), val: RawSequenceDefV9) !void { + _ = array; + _ = val; + unreachable; +} + +fn serialize_raw_schedule_def_v9(array: *std.ArrayList(u8), val: RawScheduleDefV9) !void { + _ = array; + _ = val; + unreachable; +} + +fn serialize_table_type(array: *std.ArrayList(u8), val: TableType) !void { + try array.appendSlice(&[_]u8{@intFromEnum(val)}); +} + +fn serialize_table_access(array: *std.ArrayList(u8), val: TableAccess) !void { + try array.appendSlice(&[_]u8{@intFromEnum(val)}); +} + +fn serialize_product_type_element(array: *std.ArrayList(u8), val: ProductTypeElement) !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_product_type(array: *std.ArrayList(u8), val: ProductType) std.mem.Allocator.Error!void { + try array.appendSlice(&std.mem.toBytes(@as(u32, @intCast(val.elements.len)))); + for(val.elements) |element| { + try serialize_product_type_element(array, element); + } +} + +fn serialize_algebraic_type(array: *std.ArrayList(u8), val: AlgebraicType) !void { + switch(val) { + AlgebraicType.Product => |product| { + try array.appendSlice(&[_]u8{@intFromEnum(val)}); + try serialize_product_type(array, product); + }, + else => try array.appendSlice(&[_]u8{@intFromEnum(val)}), + } +} + +fn serialize_typespace(array: *std.ArrayList(u8), val: Typespace) !void { + try array.appendSlice(&std.mem.toBytes(@as(u32, @intCast(val.types.len)))); + for(val.types) |_type| { + try serialize_algebraic_type(array, _type); + } +} + +pub fn serialize_module(array: *std.ArrayList(u8), val: RawModuleDefV9) !void { + try array.appendSlice(&[_]u8{1}); + + try serialize_typespace(array, val.typespace); + + try array.appendSlice(&std.mem.toBytes(@as(u32, @intCast(val.tables.len)))); + for(val.tables) |table| { + try serialize_raw_table_def_v9(array, table); + } + + try array.appendSlice(&std.mem.toBytes(@as(u32, @intCast(val.reducers.len)))); + for(val.reducers) |reducer| { + try serialize_raw_reducer_def_v9(array, reducer); + } + + try array.appendSlice(&std.mem.toBytes(@as(u32, @intCast(val.types.len)))); + for(val.types) |_type| { + try serialize_raw_type_def_v9(array, _type); + } + + try array.appendSlice(&std.mem.toBytes(@as(u32, @intCast(val.misc_exports.len)))); + for(val.misc_exports) |misc_export| { + try serialize_raw_misc_module_export_v9(array, misc_export); + } + + try array.appendSlice(&std.mem.toBytes(@as(u32, @intCast(val.row_level_security.len)))); + for(val.row_level_security) |rls| { + try serialize_raw_row_level_security_def_v9(array, rls); + } +} diff --git a/src/spacetime/types.zig b/src/spacetime/types.zig new file mode 100644 index 0000000..9d283fb --- /dev/null +++ b/src/spacetime/types.zig @@ -0,0 +1,167 @@ +pub const Str = []const u8; + +pub const SumTypeVariant = struct { + name: ?Str, + algebraic_type: AlgebraicType, +}; + +pub const SumType = struct { + variants: []const SumTypeVariant, +}; + +pub const ArrayType = struct { + /// The base type every element of the array has. + elem_ty: []const AlgebraicType, +}; + +pub const AlgebraicType = union(enum) { + Ref: AlgebraicTypeRef, + Sum: SumType, + Product: ProductType, + Array: ArrayType, + String: void, + Bool: void, + I8: void, + U8: void, + I16: void, + U16: void, + I32: void, + U32: void, + I64: void, + U64: void, + I128: void, + U128: void, + I256: void, + U256: void, + F32: void, + F64: void, +}; + +pub const Typespace = struct { + types: []const AlgebraicType, +}; + +pub const RawIdentifier = Str; + +pub const AlgebraicTypeRef = struct { + inner: u32, +}; + +pub const RawIndexAlgorithm = union { + BTree: []const u16, + Hash: []const u16, + Direct: u16, +}; + +pub const RawIndexDefV9 = struct { + name: ?Str, + accessor_name: ?Str, + algorithm: RawIndexAlgorithm, +}; + +pub const RawUniqueConstraintDataV9 = union { + Columns: u16, +}; + +pub const RawConstraintDataV9 = union { + unique: RawUniqueConstraintDataV9, +}; + +pub const RawConstraintDefV9 = struct { + name: ?Str, + data: RawConstraintDataV9 +}; + +pub const RawSequenceDefV9 = struct { + Name: ?Str, + Column: u16, + Start: ?i128, + MinValue: ?i128, + MaxValue: ?i128, + Increment: i128 +}; + +pub const RawScheduleDefV9 = struct { + Name: ?Str, + ReducerName: Str, + ScheduledAtColumn: u16 +}; + +pub const TableType = enum { + System, + User, +}; + +pub const TableAccess = enum { + Public, + Private, +}; + +pub const RawTableDefV9 = struct { + name: RawIdentifier, + product_type_ref: AlgebraicTypeRef, + primary_key: []const u16, + indexes: []const RawIndexDefV9, + constraints: []const RawConstraintDefV9, + sequences: []const RawSequenceDefV9, + schedule: ?RawScheduleDefV9, + table_type: TableType, + table_access: TableAccess, +}; + +pub const ProductTypeElement = struct { + name: ?Str, + algebraic_type: AlgebraicType, +}; + +pub const ProductType = struct { + elements: []const ProductTypeElement, +}; + +pub const Lifecycle = enum { + Init, + OnConnect, + OnDisconnect, +}; + +pub const ReducerContext = struct { + indentity: u256, +}; + +pub const ReducerFn = fn(*ReducerContext) void; + +pub const RawReducerDefV9 = struct { + name: RawIdentifier, + params: ProductType, + lifecycle: ?Lifecycle, +}; + +pub const RawScopedTypeNameV9 = struct { + scope: []RawIdentifier, + name: RawIdentifier, +}; + +pub const RawTypeDefV9 = struct { + name: RawScopedTypeNameV9, + ty: AlgebraicTypeRef, + custom_ordering: bool, +}; + +pub const RawMiscModuleExportV9 = enum { + RESERVED, +}; + +pub const RawSql = []u8; + +pub const RawRowLevelSecurityDefV9 = struct { + sql: RawSql, +}; + +pub const RawModuleDefV9 = struct { + typespace: Typespace, + tables: []const RawTableDefV9, + reducers: []const RawReducerDefV9, + types: []const RawTypeDefV9, + misc_exports: []const RawMiscModuleExportV9, + row_level_security: []const RawRowLevelSecurityDefV9, +};