From e60ef4b0a19e7765f5b84c2aaf9cbbe6bedaab45 Mon Sep 17 00:00:00 2001 From: rekhoff Date: Tue, 2 Dec 2025 11:53:08 -0800 Subject: [PATCH 1/4] First pass on implementing Transactions for Procedures --- crates/bindings-csharp/BSATN.Codegen/Type.cs | 25 ++ crates/bindings-csharp/Codegen/Module.cs | 317 ++++++++++++++++-- crates/bindings-csharp/Runtime/Exceptions.cs | 19 ++ .../bindings-csharp/Runtime/Internal/FFI.cs | 84 +++-- .../Runtime/Internal/IProcedure.cs | 6 + .../Runtime/Internal/Module.cs | 31 ++ .../Runtime/Internal/Procedure.cs | 136 ++++++++ crates/bindings-csharp/Runtime/bindings.c | 10 + .../examples~/regression-tests/server/Lib.cs | 78 ++++- 9 files changed, 646 insertions(+), 60 deletions(-) create mode 100644 crates/bindings-csharp/Runtime/Internal/Procedure.cs diff --git a/crates/bindings-csharp/BSATN.Codegen/Type.cs b/crates/bindings-csharp/BSATN.Codegen/Type.cs index 4bfbf45ec7e..56c4af41f07 100644 --- a/crates/bindings-csharp/BSATN.Codegen/Type.cs +++ b/crates/bindings-csharp/BSATN.Codegen/Type.cs @@ -44,6 +44,11 @@ public abstract record TypeUse(string Name, string BSATNName) /// public static string BsatnFieldSuffix => $"{BSATN_FIELD_SUFFIX}"; + /// + /// Indicates whether this type represents a void return. + /// + public virtual bool IsVoid => false; + /// /// Parse a type use for a member. /// @@ -53,6 +58,11 @@ public abstract record TypeUse(string Name, string BSATNName) /// public static TypeUse Parse(ISymbol member, ITypeSymbol typeSymbol, DiagReporter diag) { + if (typeSymbol.SpecialType == SpecialType.System_Void) + { + return new VoidUse("void", "SpacetimeDB.BSATN.Unit"); + } + var type = SymbolToName(typeSymbol); string typeInfo; @@ -194,6 +204,21 @@ public override string GetHashCodeStatement(string inVar, string outVar, int lev $"var {outVar} = {inVar} == null ? 0 : {inVar}.GetHashCode();"; } +public sealed record VoidUse(string Type, string TypeInfo) : TypeUse(Type, TypeInfo) +{ + public override bool IsVoid => true; + + public override string EqualsStatement( + string inVar1, + string inVar2, + string outVar, + int level = 0 + ) => $"var {outVar} = true;"; + + public override string GetHashCodeStatement(string inVar, string outVar, int level = 0) => + $"var {outVar} = 0;"; +} + /// /// A use of an array type. /// diff --git a/crates/bindings-csharp/Codegen/Module.cs b/crates/bindings-csharp/Codegen/Module.cs index 1049a10668a..79617a0646e 100644 --- a/crates/bindings-csharp/Codegen/Module.cs +++ b/crates/bindings-csharp/Codegen/Module.cs @@ -1232,33 +1232,63 @@ public string GenerateClass() { var invocationArgs = Args.Length == 0 ? "" : ", " + string.Join(", ", Args.Select(a => a.Name)); + var invocation = $"{FullName}((SpacetimeDB.ProcedureContext)ctx{invocationArgs})"; - var invokeBody = HasWrongSignature - ? "throw new System.InvalidOperationException(\"Invalid procedure signature.\");" - : $$""" - var result = {{FullName}}((SpacetimeDB.ProcedureContext)ctx{{invocationArgs}}); - using var output = new MemoryStream(); - using var writer = new BinaryWriter(output); - new {{ReturnType.BSATNName}}().Write(writer, result); - return output.ToArray(); - """; + string[] bodyLines; - return $$""" - class {{Name}} : SpacetimeDB.Internal.IProcedure { - {{MemberDeclaration.GenerateBsatnFields(Accessibility.Private, Args)}} + if (HasWrongSignature) + { + bodyLines = new[] + { + "throw new System.InvalidOperationException(\"Invalid procedure signature.\");", + }; + } + else if (ReturnType.IsVoid) + { + bodyLines = new[] + { + $"{invocation};", + "return System.Array.Empty();", + }; + } + else + { + var serializer = $"new {ReturnType.BSATNName}()"; + bodyLines = new[] + { + $"var result = {invocation};", + "using var output = new MemoryStream();", + "using var writer = new BinaryWriter(output);", + $"{serializer}.Write(writer, result);", + "return output.ToArray();", + }; + } + + var invokeBody = string.Join("\n", bodyLines.Select(line => $" {line}")); + var paramReads = Args.Length == 0 + ? string.Empty + : string.Join( + "\n", + Args.Select(a => + $" var {a.Name} = {a.Name}{TypeUse.BsatnFieldSuffix}.Read(reader);" + ) + ) + "\n"; + var returnTypeExpr = ReturnType.IsVoid + ? "SpacetimeDB.BSATN.AlgebraicType.Unit" + : $"new {ReturnType.BSATNName}().GetAlgebraicType(registrar)"; + + return $$$""" + class {{{Name}}} : SpacetimeDB.Internal.IProcedure { + {{{MemberDeclaration.GenerateBsatnFields(Accessibility.Private, Args)}}} public SpacetimeDB.Internal.RawProcedureDefV9 MakeProcedureDef(SpacetimeDB.BSATN.ITypeRegistrar registrar) => new( - nameof({{Name}}), - [{{MemberDeclaration.GenerateDefs(Args)}}], - new {{ReturnType.BSATNName}}().GetAlgebraicType(registrar) + nameof({{{Name}}}), + [{{{MemberDeclaration.GenerateDefs(Args)}}}], + {{{returnTypeExpr}}} ); public byte[] Invoke(BinaryReader reader, SpacetimeDB.Internal.IProcedureContext ctx) { - {{string.Join( - "\n", - Args.Select(a => $"var {a.Name} = {a.Name}{TypeUse.BsatnFieldSuffix}.Read(reader);") - )}} - {{invokeBody}} + {{{paramReads}}}{{{invokeBody}}} } } """; @@ -1591,6 +1621,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) // This is needed so every module build doesn't generate a full LocalReadOnly type, but just adds on to the existing. // We extend it here with generated table accessors, and just need to suppress the duplicate-type warning. #pragma warning disable CS0436 + #pragma warning disable STDB_UNSTABLE using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; @@ -1607,20 +1638,22 @@ public sealed record ReducerContext : DbContext, Internal.IReducerContext // We need this property to be non-static for parity with client SDK. public Identity Identity => Internal.IReducerContext.GetIdentity(); - internal ReducerContext(Identity identity, ConnectionId? connectionId, Random random, Timestamp time) { + internal ReducerContext(Identity identity, ConnectionId? connectionId, Random random, + Timestamp time, AuthCtx? senderAuth = null) + { Sender = identity; ConnectionId = connectionId; Rng = random; Timestamp = time; - SenderAuth = AuthCtx.BuildFromSystemTables(connectionId, identity); + SenderAuth = senderAuth ?? AuthCtx.BuildFromSystemTables(connectionId, identity); } } - public sealed record ProcedureContext : Internal.IProcedureContext { + public sealed record ProcedureContext : Internal.IInternalProcedureContext { public readonly Identity Sender; public readonly ConnectionId? ConnectionId; public readonly Random Rng; - public readonly Timestamp Timestamp; + public Timestamp Timestamp { get; private set; } public readonly AuthCtx SenderAuth; // We need this property to be non-static for parity with client SDK. @@ -1633,6 +1666,237 @@ internal ProcedureContext(Identity identity, ConnectionId? connectionId, Random Timestamp = time; SenderAuth = AuthCtx.BuildFromSystemTables(connectionId, identity); } + + private Internal.TransactionOffset? pendingTxOffset; + + public bool TryTakeTransactionOffset(out Internal.TransactionOffset offset) + { + if (pendingTxOffset is { } value) + { + pendingTxOffset = null; + offset = value; + return true; + } + offset = default; + return false; + } + + public void SetTransactionOffset(Internal.TransactionOffset offset) => + pendingTxOffset = offset; + + [Experimental("STDB_UNSTABLE")] + public sealed record TxContext(Local Db, ReducerContext Reducer) : DbContext(Db) + { + public Identity Sender => Reducer.Sender; + public ConnectionId? ConnectionId => Reducer.ConnectionId; + public Timestamp Timestamp => Reducer.Timestamp; + public Random Rng => Reducer.Rng; + public AuthCtx SenderAuth => Reducer.SenderAuth; + } + + private sealed class AbortGuard : IDisposable + { + private readonly Action abort; + private bool disarmed; + public AbortGuard(Action abort) => this.abort = abort; + public void Disarm() => disarmed = true; + public void Dispose() { if (!disarmed) abort(); } + } + + [Experimental("STDB_UNSTABLE")] + public TxOutcome TryWithTx( + Func> body) + where TError : Exception + { + try + { + var result = RunWithRetry(body); + return result.IsSuccess + ? TxOutcome.Success(result.Value!) + : TxOutcome.Failure(result.Error!); + } + catch (Exception ex) + { + return TxOutcome.Failure(ex); + } + } + + [Experimental("STDB_UNSTABLE")] + public T WithTx(Func body) + { + var outcome = TryWithTx(ctx => + TxResult.Success(body(ctx))); + if (outcome.IsSuccess) return outcome.Value!; + throw outcome.Error!; + } + + [Experimental("STDB_UNSTABLE")] + public readonly record struct TxOutcome(bool IsSuccess, T? Value, Exception? Error) + { + public static TxOutcome Success(T value) => new(true, value, null); + public static TxOutcome Failure(Exception error) => new(false, default, error); + + public TxOutcome Map(Func mapper) => + IsSuccess ? TxOutcome.Success(mapper(Value!)) : TxOutcome.Failure(Error!); + } + + private TxResult RunWithRetry( + Func> body) + where TError : Exception + { + var result = RunOnce(body); + + bool retry() + { + result = RunOnce(body); + return true; + } + + if (!SpacetimeDB.Internal.Procedure.CommitMutTxWithRetry(retry)) + { + SpacetimeDB.Internal.Procedure.AbortMutTx(); + } + + if (TryTakeTransactionOffset(out var offset)) + { + SpacetimeDB.Internal.Module.RecordProcedureTxOffset(offset); + } + return result; + } + + [Experimental("STDB_UNSTABLE")] + public async Task WithTxAsync(Func> body) + { + var outcome = await TryWithTxAsync(async ctx => + TxResult.Success(await body(ctx).ConfigureAwait(false))).ConfigureAwait(false); + if (outcome.IsSuccess) return outcome.Value!; + throw outcome.Error!; + } + + public async Task> TryWithTxAsync( + Func>> body) + where TError : Exception + { + try + { + return (await RunWithRetryAsync(body).ConfigureAwait(false)).Match( + onSuccess: TxOutcome.Success, + onError: TxOutcome.Failure); + } + catch (Exception ex) + { + return TxOutcome.Failure(ex); + } + } + + [Experimental("STDB_UNSTABLE")] + public readonly record struct TxResult + where TError : Exception + { + public bool IsSuccess { get; } + public TSuccess? Value { get; } + public TError? Error { get; } + + private TxResult(bool isSuccess, TSuccess? value, TError? error) + { + IsSuccess = isSuccess; + Value = value; + Error = error; + } + + public static TxResult Success(TSuccess value) => + new(true, value, default); + + public static TxResult Failure(TError error) => + new(false, default, error); + + public TResult Match( + Func onSuccess, + Func onError) + { + if (onSuccess is null) throw new ArgumentNullException(nameof(onSuccess)); + if (onError is null) throw new ArgumentNullException(nameof(onError)); + return IsSuccess ? onSuccess(Value!) : onError(Error!); + } + } + + private async Task> RunWithRetryAsync( + Func>> body) + where TError : Exception + { + var result = await RunOnceAsync(body).ConfigureAwait(false); + + async Task Retry() + { + result = await RunOnceAsync(body).ConfigureAwait(false); + return true; + } + + if (!await SpacetimeDB.Internal.Procedure.CommitMutTxWithRetryAsync(Retry).ConfigureAwait(false)) + { + await SpacetimeDB.Internal.Procedure.AbortMutTxAsync().ConfigureAwait(false); + } + if (TryTakeTransactionOffset(out var offset)) { + SpacetimeDB.Internal.Module.RecordProcedureTxOffset(offset); + } + + return result; + } + + private async Task> RunOnceAsync( + Func>> body) + where TError : Exception + { + var micros = SpacetimeDB.Internal.Procedure.StartMutTx(); + await using var guard = new AsyncAbortGuard(SpacetimeDB.Internal.Procedure.AbortMutTxAsync); + var txCtx = MakeTxContext(micros); + var output = await body(txCtx).ConfigureAwait(false); + await guard.DisarmAsync().ConfigureAwait(false); + return output; + } + + private sealed class AsyncAbortGuard : IAsyncDisposable + { + private readonly Func abort; + private bool disarmed; + public AsyncAbortGuard(Func abort) => this.abort = abort; + public Task DisarmAsync() { disarmed = true; return Task.CompletedTask; } + public async ValueTask DisposeAsync() + { + if (!disarmed) await abort().ConfigureAwait(false); + } + } + + private bool RetryOnce( + Func> body, + out TxResult result) + where TError : Exception + { + result = RunOnce(body); + return true; + } + + private TxResult RunOnce( + Func> body) + where TError : Exception + { + var micros = SpacetimeDB.Internal.Procedure.StartMutTx(); + using var guard = new AbortGuard(SpacetimeDB.Internal.Procedure.AbortMutTx); + var txCtx = MakeTxContext(micros); + var output = body(txCtx); + guard.Disarm(); + return output; + } + + private TxContext MakeTxContext(long micros) + { + var txTimestamp = new Timestamp(micros); + Timestamp = txTimestamp; + var reducerCtx = new ReducerContext( + Sender, ConnectionId, new Random(unchecked((int)micros)), + txTimestamp, SenderAuth); + return new TxContext(new Local(), reducerCtx); + } } public sealed record ViewContext : DbContext, Internal.IViewContext @@ -1805,6 +2069,10 @@ SpacetimeDB.Internal.BytesSink result_sink args, result_sink ); + + [UnmanagedCallersOnly(EntryPoint = "__take_procedure_tx_offset__")] + public static byte __take_procedure_tx_offset__(ulong* offset) => + SpacetimeDB.Internal.Module.__take_procedure_tx_offset__(out *offset) ? (byte)1 : (byte)0; [UnmanagedCallersOnly(EntryPoint = "__call_view__")] public static SpacetimeDB.Internal.Errno __call_view__( @@ -1838,6 +2106,7 @@ SpacetimeDB.Internal.BytesSink sink #endif } + #pragma warning restore STDB_UNSTABLE #pragma warning restore CS0436 """ ); diff --git a/crates/bindings-csharp/Runtime/Exceptions.cs b/crates/bindings-csharp/Runtime/Exceptions.cs index 1488b00d91f..e6cd7ceacbf 100644 --- a/crates/bindings-csharp/Runtime/Exceptions.cs +++ b/crates/bindings-csharp/Runtime/Exceptions.cs @@ -77,6 +77,25 @@ public class AutoIncOverflowException : StdbException public override string Message => "The auto-increment sequence overflowed"; } +public class TransactionWouldBlockException : StdbException { + public override string Message => "Attempted operation while another transaction is open"; +} + +public class TransactionNotAnonymousException : StdbException +{ + public override string Message => "The transaction is not anonymous"; +} + +public class TransactionIsReadOnlyException : StdbException +{ + public override string Message => "The transaction is read-only"; +} + +public class TransactionIsMutableException : StdbException { + public override string Message => + "ABI call can only be made while inside a read-only transaction"; +} + public class UnknownException : StdbException { private readonly Errno code; diff --git a/crates/bindings-csharp/Runtime/Internal/FFI.cs b/crates/bindings-csharp/Runtime/Internal/FFI.cs index 1f63e70135a..a5e3b1e612b 100644 --- a/crates/bindings-csharp/Runtime/Internal/FFI.cs +++ b/crates/bindings-csharp/Runtime/Internal/FFI.cs @@ -37,6 +37,10 @@ public enum Errno : short INDEX_NOT_UNIQUE = 14, NO_SUCH_ROW = 15, AUTO_INC_OVERFLOW = 16, + WOULD_BLOCK_TRANSACTION = 17, + TRANSACTION_NOT_ANONYMOUS = 18, + TRANSACTION_IS_READ_ONLY = 19, + TRANSACTION_IS_MUT = 20, } #pragma warning disable IDE1006 // Naming Styles - Not applicable to FFI stuff. @@ -68,6 +72,14 @@ internal static partial class FFI "bindings" #endif ; + + const string StdbNamespace10_3 = +#if EXPERIMENTAL_WASM_AOT + "spacetime_10.3" +#else + "bindings" +#endif + ; [NativeMarshalling(typeof(Marshaller))] public struct CheckedStatus @@ -86,30 +98,45 @@ internal static class Marshaller { public static CheckedStatus ConvertToManaged(Errno status) { - if (status == 0) - { - return default; - } - throw status switch - { - Errno.NOT_IN_TRANSACTION => new NotInTransactionException(), - Errno.BSATN_DECODE_ERROR => new BsatnDecodeException(), - Errno.NO_SUCH_TABLE => new NoSuchTableException(), - Errno.NO_SUCH_INDEX => new NoSuchIndexException(), - Errno.NO_SUCH_ITER => new NoSuchIterException(), - Errno.NO_SUCH_CONSOLE_TIMER => new NoSuchLogStopwatch(), - Errno.NO_SUCH_BYTES => new NoSuchBytesException(), - Errno.NO_SPACE => new NoSpaceException(), - Errno.BUFFER_TOO_SMALL => new BufferTooSmallException(), - Errno.UNIQUE_ALREADY_EXISTS => new UniqueConstraintViolationException(), - Errno.SCHEDULE_AT_DELAY_TOO_LONG => new ScheduleAtDelayTooLongException(), - Errno.INDEX_NOT_UNIQUE => new IndexNotUniqueException(), - Errno.NO_SUCH_ROW => new NoSuchRowException(), - Errno.AUTO_INC_OVERFLOW => new AutoIncOverflowException(), - _ => new UnknownException(status), - }; + ErrnoHelpers.ThrowIfError(status); + return default; + } + } + } + + internal static class ErrnoHelpers + { + public static void ThrowIfError(Errno status) + { + if (status == Errno.OK) + { + return; } + + throw ToException(status); } + + public static Exception ToException(Errno status) => status switch + { + Errno.NOT_IN_TRANSACTION => new NotInTransactionException(), + Errno.BSATN_DECODE_ERROR => new BsatnDecodeException(), + Errno.NO_SUCH_TABLE => new NoSuchTableException(), + Errno.NO_SUCH_INDEX => new NoSuchIndexException(), + Errno.NO_SUCH_ITER => new NoSuchIterException(), + Errno.NO_SUCH_CONSOLE_TIMER => new NoSuchLogStopwatch(), + Errno.NO_SUCH_BYTES => new NoSuchBytesException(), + Errno.NO_SPACE => new NoSpaceException(), + Errno.BUFFER_TOO_SMALL => new BufferTooSmallException(), + Errno.UNIQUE_ALREADY_EXISTS => new UniqueConstraintViolationException(), + Errno.INDEX_NOT_UNIQUE => new IndexNotUniqueException(), + Errno.NO_SUCH_ROW => new NoSuchRowException(), + Errno.AUTO_INC_OVERFLOW => new AutoIncOverflowException(), + Errno.WOULD_BLOCK_TRANSACTION => new TransactionWouldBlockException(), + Errno.TRANSACTION_NOT_ANONYMOUS => new TransactionNotAnonymousException(), + Errno.TRANSACTION_IS_READ_ONLY => new TransactionIsReadOnlyException(), + Errno.TRANSACTION_IS_MUT => new TransactionIsMutableException(), + _ => new UnknownException(status), + }; } [StructLayout(LayoutKind.Sequential)] @@ -318,4 +345,17 @@ uint args_len [DllImport(StdbNamespace10_2)] public static extern Errno get_jwt(ref ConnectionId connectionId, out BytesSource source); + + [LibraryImport(StdbNamespace10_3, EntryPoint = "procedure_start_mut_tx")] + public static partial Errno procedure_start_mut_tx(out long micros); + + [LibraryImport(StdbNamespace10_3, EntryPoint = "procedure_commit_mut_tx")] + public static partial CheckedStatus procedure_commit_mut_tx(); + + [LibraryImport(StdbNamespace10_3, EntryPoint = "procedure_abort_mut_tx")] + public static partial CheckedStatus procedure_abort_mut_tx(); + + [LibraryImport(StdbNamespace10_3, EntryPoint = "__take_procedure_tx_offset__")] + [return: MarshalAs(UnmanagedType.I1)] + public static partial bool take_procedure_tx_offset(out ulong offset); } diff --git a/crates/bindings-csharp/Runtime/Internal/IProcedure.cs b/crates/bindings-csharp/Runtime/Internal/IProcedure.cs index ba7e6f13540..f5cd96d81c9 100644 --- a/crates/bindings-csharp/Runtime/Internal/IProcedure.cs +++ b/crates/bindings-csharp/Runtime/Internal/IProcedure.cs @@ -32,3 +32,9 @@ public static void VolatileNonatomicScheduleImmediate(string name, MemoryStream ); } } + +public interface IInternalProcedureContext : IProcedureContext +{ + bool TryTakeTransactionOffset(out TransactionOffset offset); + void SetTransactionOffset(TransactionOffset offset); +} diff --git a/crates/bindings-csharp/Runtime/Internal/Module.cs b/crates/bindings-csharp/Runtime/Internal/Module.cs index 46157d9308b..274a87c3fdf 100644 --- a/crates/bindings-csharp/Runtime/Internal/Module.cs +++ b/crates/bindings-csharp/Runtime/Internal/Module.cs @@ -65,6 +65,7 @@ public static class Module private static readonly List> viewDefs = []; private static readonly List viewDispatchers = []; private static readonly List anonymousViewDispatchers = []; + private static TransactionOffset? lastProcedureTxOffset; private static Func< Identity, @@ -180,6 +181,16 @@ public static void RegisterClientVisibilityFilter(Filter rlsFilter) } } + public static void RecordProcedureTxOffset(TransactionOffset offset) => + lastProcedureTxOffset = offset; + + public static TransactionOffset? TakeProcedureTxOffset() + { + var tmp = lastProcedureTxOffset; + lastProcedureTxOffset = null; + return tmp; + } + public static void RegisterTableDefaultValue(string table, ushort colId, byte[] value) => moduleDef.RegisterTableDefaultValue(table, colId, value); @@ -347,12 +358,20 @@ BytesSink resultSink using var stream = new MemoryStream(args.Consume()); using var reader = new BinaryReader(stream); + using var scope = Procedure.PushContext(ctx); var bytes = procedures[(int)id].Invoke(reader, ctx); if (stream.Position != stream.Length) { throw new Exception("Unrecognised extra bytes in the procedure arguments"); } resultSink.Write(bytes); + if (ctx is IInternalProcedureContext internalCtx) + { + if (internalCtx.TryTakeTransactionOffset(out var offset)) + { + RecordProcedureTxOffset(offset); + } + } return Errno.OK; } catch (Exception e) @@ -362,6 +381,18 @@ BytesSink resultSink return Errno.HOST_CALL_FAILURE; } } + + public static bool __take_procedure_tx_offset__(out ulong offset) + { + if (TakeProcedureTxOffset() is { } tx) + { + offset = tx.Value; + return true; + } + + offset = 0; + return false; + } public static Errno __call_view__( uint id, diff --git a/crates/bindings-csharp/Runtime/Internal/Procedure.cs b/crates/bindings-csharp/Runtime/Internal/Procedure.cs new file mode 100644 index 00000000000..f82a3bcbc8b --- /dev/null +++ b/crates/bindings-csharp/Runtime/Internal/Procedure.cs @@ -0,0 +1,136 @@ +using System.Threading; + +namespace SpacetimeDB.Internal; + +public static class Procedure +{ + private static readonly AsyncLocal current = new(); + + private readonly struct ContextScope : IDisposable + { + private readonly IInternalProcedureContext? previous; + + public ContextScope(IInternalProcedureContext? next) + { + previous = current.Value; + current.Value = next; + } + + public void Dispose() => current.Value = previous; + } + + internal static IDisposable PushContext(IProcedureContext ctx) => + new ContextScope(ctx as IInternalProcedureContext); + + private static IInternalProcedureContext RequireContext() => + current.Value ?? throw new InvalidOperationException( + "Transaction syscalls require a procedure context." + ); + + public static long StartMutTx() + { + var status = FFI.procedure_start_mut_tx(out var micros); + FFI.ErrnoHelpers.ThrowIfError(status); + return micros; + } + + public static void CommitMutTx() + { + FFI.procedure_commit_mut_tx(); // throws on error + if (RequireContext() is IInternalProcedureContext ctx && + TryTakeOffsetFromHost(out var offset)) + { + ctx.SetTransactionOffset(offset); + Module.RecordProcedureTxOffset(offset); + } + } + + public static void AbortMutTx() + { + FFI.procedure_abort_mut_tx(); // throws on error + if (RequireContext() is IInternalProcedureContext ctx && + TryTakeOffsetFromHost(out var offset)) + { + ctx.SetTransactionOffset(offset); + Module.RecordProcedureTxOffset(offset); + } + } + + private static bool TryTakeOffsetFromHost(out TransactionOffset offset) + { + if (FFI.take_procedure_tx_offset(out var rawOffset)) + { + offset = TransactionOffset.FromRaw(unchecked((long)rawOffset)); + return true; + } + + offset = default; + return false; + } + + public static bool CommitMutTxWithRetry(Func retryBody) + { + try + { + CommitMutTx(); + return true; + } + catch (TransactionNotAnonymousException) + { + // reducer misuse, abort immediately + return false; + } + catch (StdbException) + { + if (retryBody()) { + CommitMutTx(); + return true; + } + return false; + } + } + + public static async Task CommitMutTxWithRetryAsync(Func> retryBody) + { + try + { + await CommitMutTxAsync().ConfigureAwait(false); + return true; + } + catch (TransactionNotAnonymousException) + { + return false; + } + catch (StdbException) + { + if (await retryBody().ConfigureAwait(false)) + { + await CommitMutTxAsync().ConfigureAwait(false); + return true; + } + return false; + } + } + + public static Task CommitMutTxAsync() + { + CommitMutTx(); // existing sync path + return Task.CompletedTask; + } + + public static Task AbortMutTxAsync() + { + AbortMutTx(); // existing sync path + return Task.CompletedTask; + } +} + +public readonly struct TransactionOffset +{ + public ulong Value { get; } + + private TransactionOffset(ulong value) => Value = value; + + public static TransactionOffset FromRaw(long raw) => + new(unchecked((ulong)raw)); +} diff --git a/crates/bindings-csharp/Runtime/bindings.c b/crates/bindings-csharp/Runtime/bindings.c index be12f438959..0a42a6d64ea 100644 --- a/crates/bindings-csharp/Runtime/bindings.c +++ b/crates/bindings-csharp/Runtime/bindings.c @@ -1,6 +1,7 @@ #include // #include // #include +#include #include #include @@ -108,6 +109,12 @@ IMPORT(int16_t, bytes_source_remaining_length, (BytesSource source, uint32_t* ou IMPORT(int16_t, get_jwt, (const uint8_t* connection_id_ptr, BytesSource* bytes_ptr), (connection_id_ptr, bytes_ptr)); #undef SPACETIME_MODULE_VERSION +#define SPACETIME_MODULE_VERSION "spacetime_10.3" +IMPORT(uint16_t, procedure_start_mut_tx, (int64_t* micros), (micros)); +IMPORT(uint16_t, procedure_commit_mut_tx, (void), ()); +IMPORT(uint16_t, procedure_abort_mut_tx, (void), ()); +#undef SPACETIME_MODULE_VERSION + #ifndef EXPERIMENTAL_WASM_AOT static MonoClass* ffi_class; @@ -170,6 +177,9 @@ EXPORT(int16_t, __call_procedure__, &conn_id_0, &conn_id_1, ×tamp, &args, &result_sink); +EXPORT(bool, __take_procedure_tx_offset__, + (uint64_t* offset), offset); + EXPORT(int16_t, __call_view__, (uint32_t id, uint64_t sender_0, uint64_t sender_1, uint64_t sender_2, uint64_t sender_3, diff --git a/sdks/csharp/examples~/regression-tests/server/Lib.cs b/sdks/csharp/examples~/regression-tests/server/Lib.cs index b6f0294a454..bd5fbca25c0 100644 --- a/sdks/csharp/examples~/regression-tests/server/Lib.cs +++ b/sdks/csharp/examples~/regression-tests/server/Lib.cs @@ -36,7 +36,7 @@ public partial class MyTable public static partial class Module { - [SpacetimeDB.Table(Name = "ExampleData", Public = true)] + [SpacetimeDB.Table(Name = "example_data", Public = true)] public partial struct ExampleData { [SpacetimeDB.PrimaryKey] @@ -46,7 +46,7 @@ public partial struct ExampleData public uint Indexed; } - [SpacetimeDB.Table(Name = "Player", Public = true)] + [SpacetimeDB.Table(Name = "player", Public = true)] public partial struct Player { [SpacetimeDB.PrimaryKey] @@ -59,7 +59,7 @@ public partial struct Player public string Name; } - [SpacetimeDB.Table(Name = "PlayerLevel", Public = true)] + [SpacetimeDB.Table(Name = "player_level", Public = true)] public partial struct PlayerLevel { [SpacetimeDB.Unique] @@ -79,20 +79,20 @@ public partial struct PlayerAndLevel } // At-most-one row: return T? - [SpacetimeDB.View(Name = "MyPlayer", Public = true)] + [SpacetimeDB.View(Name = "my_player", Public = true)] public static Player? MyPlayer(ViewContext ctx) { - return ctx.Db.Player.Identity.Find(ctx.Sender) as Player?; + return ctx.Db.player.Identity.Find(ctx.Sender) as Player?; } // Multiple rows: return a list - [SpacetimeDB.View(Name = "PlayersForLevel", Public = true)] + [SpacetimeDB.View(Name = "players_for_level", Public = true)] public static List PlayersForLevel(AnonymousViewContext ctx) { var rows = new List(); - foreach (var player in ctx.Db.PlayerLevel.Level.Filter(1)) + foreach (var player in ctx.Db.player_level.Level.Filter(1)) { - if (ctx.Db.Player.Id.Find(player.PlayerId) is Player p) + if (ctx.Db.player.Id.Find(player.PlayerId) is Player p) { var row = new PlayerAndLevel { @@ -110,13 +110,14 @@ public static List PlayersForLevel(AnonymousViewContext ctx) [SpacetimeDB.Reducer] public static void Delete(ReducerContext ctx, uint id) { - ctx.Db.ExampleData.Id.Delete(id); + LogStopwatch sw = new("Delete"); + ctx.Db.example_data.Id.Delete(id); } [SpacetimeDB.Reducer] public static void Add(ReducerContext ctx, uint id, uint indexed) { - ctx.Db.ExampleData.Insert(new ExampleData { Id = id, Indexed = indexed }); + ctx.Db.example_data.Insert(new ExampleData { Id = id, Indexed = indexed }); } [SpacetimeDB.Reducer] @@ -130,16 +131,16 @@ public static void ClientConnected(ReducerContext ctx) { Log.Info($"Connect {ctx.Sender}"); - if (ctx.Db.Player.Identity.Find(ctx.Sender) is Player player) + if (ctx.Db.player.Identity.Find(ctx.Sender) is Player player) { // We are not logging player login status, so do nothing } else { // Lets setup a new player with a level of 1 - ctx.Db.Player.Insert(new Player { Identity = ctx.Sender, Name = "NewPlayer" }); - var playerId = (ctx.Db.Player.Identity.Find(ctx.Sender)!).Value.Id; - ctx.Db.PlayerLevel.Insert(new PlayerLevel { PlayerId = playerId, Level = 1 }); + ctx.Db.player.Insert(new Player { Identity = ctx.Sender, Name = "NewPlayer" }); + var playerId = (ctx.Db.player.Identity.Find(ctx.Sender)!).Value.Id; + ctx.Db.player_level.Insert(new PlayerLevel { PlayerId = playerId, Level = 1 }); } } @@ -172,4 +173,53 @@ public static SpacetimeDB.Unit WillPanic(ProcedureContext ctx) { throw new InvalidOperationException("This procedure is expected to panic"); } + +#pragma warning disable STDB_UNSTABLE + [SpacetimeDB.Procedure] + public static void InsertWithTxCommit(ProcedureContext ctx) + { + ctx.WithTx(tx => + { + tx.Db.my_table.Insert(new MyTable + { + Field = new ReturnStruct(a: 42, b: "magic") + }); + return 0; // discard result + }); + + AssertRowCount(ctx, 1); + } + + [SpacetimeDB.Procedure] + public static void InsertWithTxRollback(ProcedureContext ctx) + { + var _ = ctx.TryWithTx(tx => + { + tx.Db.my_table.Insert(new MyTable + { + Field = new ReturnStruct(a: 42, b: "magic") + }); + + return SpacetimeDB.ProcedureContext.TxResult.Failure( + new InvalidOperationException("rollback")); + }); + + AssertRowCount(ctx, 0); + } + + private static void AssertRowCount(ProcedureContext ctx, ulong expected) + { + ctx.WithTx(tx => + { + ulong actual = tx.Db.my_table.Count; + if (actual != expected) + { + throw new InvalidOperationException( + $"Expected {expected} MyTable rows but found {actual}." + ); + } + return 0; + }); + } +#pragma warning restore STDB_UNSTABLE } From 3132d1fe97a57c7323e1c9645d6b8ff00ed7c568 Mon Sep 17 00:00:00 2001 From: rekhoff Date: Wed, 3 Dec 2025 17:41:20 -0800 Subject: [PATCH 2/4] Added a TxContext and pulled out ProcedureContext to the Runtime --- crates/bindings-csharp/Codegen/Module.cs | 449 +++++++----------- .../Runtime/Internal/IProcedure.cs | 2 + .../Runtime/Internal/Module.cs | 11 +- .../Runtime/Internal/Procedure.cs | 14 +- .../Runtime/Internal/TxContext.cs | 30 ++ .../Runtime/ProcedureContext.cs | 286 +++++++++++ 6 files changed, 495 insertions(+), 297 deletions(-) create mode 100644 crates/bindings-csharp/Runtime/Internal/TxContext.cs create mode 100644 crates/bindings-csharp/Runtime/ProcedureContext.cs diff --git a/crates/bindings-csharp/Codegen/Module.cs b/crates/bindings-csharp/Codegen/Module.cs index 79617a0646e..bc31b94c6bf 100644 --- a/crates/bindings-csharp/Codegen/Module.cs +++ b/crates/bindings-csharp/Codegen/Module.cs @@ -1190,6 +1190,9 @@ record ProcedureDeclaration public readonly Scope Scope; private readonly bool HasWrongSignature; public readonly TypeUse ReturnType; + private readonly IMethodSymbol _methodSymbol; + private readonly ITypeSymbol _returnTypeSymbol; + private readonly DiagReporter _diag; public ProcedureDeclaration(GeneratorAttributeSyntaxContext context, DiagReporter diag) { @@ -1197,6 +1200,10 @@ public ProcedureDeclaration(GeneratorAttributeSyntaxContext context, DiagReporte var method = (IMethodSymbol)context.TargetSymbol; var attr = context.Attributes.Single().ParseAs(); + _methodSymbol = method; + _returnTypeSymbol = method.ReturnType; + _diag = diag; + if ( method.Parameters.FirstOrDefault()?.Type is not INamedTypeSymbol { Name: "ProcedureContext" } @@ -1234,6 +1241,12 @@ public string GenerateClass() Args.Length == 0 ? "" : ", " + string.Join(", ", Args.Select(a => a.Name)); var invocation = $"{FullName}((SpacetimeDB.ProcedureContext)ctx{invocationArgs})"; + var hasTxOutcome = TryGetTxOutcomeType(out var txOutcomePayload); + var hasTxResult = TryGetTxResultTypes(out var txResultPayload, out _); + var hasTxWrapper = hasTxOutcome || hasTxResult; + var txPayload = hasTxOutcome ? txOutcomePayload : txResultPayload; + var txPayloadIsUnit = hasTxWrapper && txPayload.BSATNName == "SpacetimeDB.BSATN.Unit"; + string[] bodyLines; if (HasWrongSignature) @@ -1243,6 +1256,30 @@ public string GenerateClass() "throw new System.InvalidOperationException(\"Invalid procedure signature.\");", }; } + else if (hasTxWrapper) + { + var successLines = txPayloadIsUnit + ? new[] { "return System.Array.Empty();" } + : new[] + { + "using var output = new MemoryStream();", + "using var writer = new BinaryWriter(output);", + "__txReturnRW.Write(writer, outcome.Value!);", + "return output.ToArray();", + }; + + bodyLines = + new[] + { + $"var outcome = {invocation};", + "if (!outcome.IsSuccess)", + "{", + " throw outcome.Error ?? new System.InvalidOperationException(\"Transaction failed.\");", + "}", + } + .Concat(successLines) + .ToArray(); + } else if (ReturnType.IsVoid) { bodyLines = new[] @@ -1268,30 +1305,46 @@ public string GenerateClass() var paramReads = Args.Length == 0 ? string.Empty : string.Join( - "\n", - Args.Select(a => - $" var {a.Name} = {a.Name}{TypeUse.BsatnFieldSuffix}.Read(reader);" - ) - ) + "\n"; - var returnTypeExpr = ReturnType.IsVoid - ? "SpacetimeDB.BSATN.AlgebraicType.Unit" - : $"new {ReturnType.BSATNName}().GetAlgebraicType(registrar)"; + "\n", + Args.Select(a => + $" var {a.Name} = {a.Name}{TypeUse.BsatnFieldSuffix}.Read(reader);" + ) + ) + "\n"; - return $$$""" - class {{{Name}}} : SpacetimeDB.Internal.IProcedure { - {{{MemberDeclaration.GenerateBsatnFields(Accessibility.Private, Args)}}} + var returnTypeExpr = hasTxWrapper + ? ( + txPayloadIsUnit + ? "SpacetimeDB.BSATN.AlgebraicType.Unit" + : $"new {txPayload.BSATNName}().GetAlgebraicType(registrar)" + ) + : ( + ReturnType.IsVoid + ? "SpacetimeDB.BSATN.AlgebraicType.Unit" + : $"new {ReturnType.BSATNName}().GetAlgebraicType(registrar)" + ); - public SpacetimeDB.Internal.RawProcedureDefV9 MakeProcedureDef(SpacetimeDB.BSATN.ITypeRegistrar registrar) => new( - nameof({{{Name}}}), - [{{{MemberDeclaration.GenerateDefs(Args)}}}], - {{{returnTypeExpr}}} - ); + var classFields = MemberDeclaration.GenerateBsatnFields(Accessibility.Private, Args); + if (hasTxWrapper && !txPayloadIsUnit) + { + classFields += + $"\n private {txPayload.BSATNName} __txReturnRW = new {txPayload.BSATNName}();"; + } - public byte[] Invoke(BinaryReader reader, SpacetimeDB.Internal.IProcedureContext ctx) { - {{{paramReads}}}{{{invokeBody}}} - } - } - """; + return $$$""" + class {{{Name}}} : SpacetimeDB.Internal.IProcedure { + {{{classFields}}} + + public SpacetimeDB.Internal.RawProcedureDefV9 MakeProcedureDef(SpacetimeDB.BSATN.ITypeRegistrar registrar) => new( + nameof({{{Name}}}), + [{{{MemberDeclaration.GenerateDefs(Args)}}}], + {{{returnTypeExpr}}} + ); + + public byte[] Invoke(BinaryReader reader, SpacetimeDB.Internal.IProcedureContext ctx) { + {{{paramReads}}}{{{invokeBody}}} + } + } + """; } public Scope.Extensions GenerateSchedule() @@ -1322,6 +1375,46 @@ public Scope.Extensions GenerateSchedule() return extensions; } + + private bool TryGetTxOutcomeType(out TypeUse payloadType) + { + if ( + _returnTypeSymbol is INamedTypeSymbol + { + Name: "TxOutcome", + ContainingType: { Name: "ProcedureContext" } + } named && + named.TypeArguments.Length == 1 + ) + { + payloadType = TypeUse.Parse(_methodSymbol, named.TypeArguments[0], _diag); + return true; + } + + payloadType = default!; + return false; + } + + private bool TryGetTxResultTypes(out TypeUse payloadType, out TypeUse errorType) + { + if ( + _returnTypeSymbol is INamedTypeSymbol + { + Name: "TxResult", + ContainingType: { Name: "ProcedureContext" } + } named && + named.TypeArguments.Length == 2 + ) + { + payloadType = TypeUse.Parse(_methodSymbol, named.TypeArguments[0], _diag); + errorType = TypeUse.Parse(_methodSymbol, named.TypeArguments[1], _diag); + return true; + } + + payloadType = default!; + errorType = default!; + return false; + } } record ClientVisibilityFilterDeclaration @@ -1626,6 +1719,8 @@ public void Initialize(IncrementalGeneratorInitializationContext context) using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + using Internal = SpacetimeDB.Internal; + using TxContext = SpacetimeDB.Internal.TxContext; namespace SpacetimeDB { public sealed record ReducerContext : DbContext, Internal.IReducerContext { @@ -1649,280 +1744,60 @@ internal ReducerContext(Identity identity, ConnectionId? connectionId, Random ra } } - public sealed record ProcedureContext : Internal.IInternalProcedureContext { - public readonly Identity Sender; - public readonly ConnectionId? ConnectionId; - public readonly Random Rng; - public Timestamp Timestamp { get; private set; } - public readonly AuthCtx SenderAuth; - - // We need this property to be non-static for parity with client SDK. - public Identity Identity => Internal.IProcedureContext.GetIdentity(); - - internal ProcedureContext(Identity identity, ConnectionId? connectionId, Random random, Timestamp time) { - Sender = identity; - ConnectionId = connectionId; - Rng = random; - Timestamp = time; - SenderAuth = AuthCtx.BuildFromSystemTables(connectionId, identity); - } - - private Internal.TransactionOffset? pendingTxOffset; - - public bool TryTakeTransactionOffset(out Internal.TransactionOffset offset) - { - if (pendingTxOffset is { } value) - { - pendingTxOffset = null; - offset = value; - return true; - } - offset = default; - return false; - } - - public void SetTransactionOffset(Internal.TransactionOffset offset) => - pendingTxOffset = offset; - - [Experimental("STDB_UNSTABLE")] - public sealed record TxContext(Local Db, ReducerContext Reducer) : DbContext(Db) - { - public Identity Sender => Reducer.Sender; - public ConnectionId? ConnectionId => Reducer.ConnectionId; - public Timestamp Timestamp => Reducer.Timestamp; - public Random Rng => Reducer.Rng; - public AuthCtx SenderAuth => Reducer.SenderAuth; - } - - private sealed class AbortGuard : IDisposable - { - private readonly Action abort; - private bool disarmed; - public AbortGuard(Action abort) => this.abort = abort; - public void Disarm() => disarmed = true; - public void Dispose() { if (!disarmed) abort(); } - } - - [Experimental("STDB_UNSTABLE")] - public TxOutcome TryWithTx( - Func> body) - where TError : Exception - { - try - { - var result = RunWithRetry(body); - return result.IsSuccess - ? TxOutcome.Success(result.Value!) - : TxOutcome.Failure(result.Error!); - } - catch (Exception ex) - { - return TxOutcome.Failure(ex); - } - } - - [Experimental("STDB_UNSTABLE")] - public T WithTx(Func body) - { - var outcome = TryWithTx(ctx => - TxResult.Success(body(ctx))); - if (outcome.IsSuccess) return outcome.Value!; - throw outcome.Error!; - } - + public sealed class ProcedureContext : global::SpacetimeDB.ProcedureContextBase { + private readonly Local _db = new(); + + internal ProcedureContext(Identity identity, ConnectionId? connectionId, Random random, Timestamp time) + : base(identity, connectionId, random, time) {} + + protected override global::SpacetimeDB.LocalBase CreateLocal() => _db; + protected override global::SpacetimeDB.ProcedureTxContextBase CreateTxContext(Internal.TxContext inner) => + _cached ??= new ProcedureTxContext(inner); + + private ProcedureTxContext? _cached; + [Experimental("STDB_UNSTABLE")] - public readonly record struct TxOutcome(bool IsSuccess, T? Value, Exception? Error) - { - public static TxOutcome Success(T value) => new(true, value, null); - public static TxOutcome Failure(Exception error) => new(false, default, error); - - public TxOutcome Map(Func mapper) => - IsSuccess ? TxOutcome.Success(mapper(Value!)) : TxOutcome.Failure(Error!); - } - - private TxResult RunWithRetry( - Func> body) - where TError : Exception - { - var result = RunOnce(body); - - bool retry() - { - result = RunOnce(body); - return true; - } - - if (!SpacetimeDB.Internal.Procedure.CommitMutTxWithRetry(retry)) - { - SpacetimeDB.Internal.Procedure.AbortMutTx(); - } - - if (TryTakeTransactionOffset(out var offset)) - { - SpacetimeDB.Internal.Module.RecordProcedureTxOffset(offset); - } - return result; - } + public Local Db => _db; [Experimental("STDB_UNSTABLE")] - public async Task WithTxAsync(Func> body) - { - var outcome = await TryWithTxAsync(async ctx => - TxResult.Success(await body(ctx).ConfigureAwait(false))).ConfigureAwait(false); - if (outcome.IsSuccess) return outcome.Value!; - throw outcome.Error!; - } - - public async Task> TryWithTxAsync( - Func>> body) - where TError : Exception - { - try - { - return (await RunWithRetryAsync(body).ConfigureAwait(false)).Match( - onSuccess: TxOutcome.Success, - onError: TxOutcome.Failure); - } - catch (Exception ex) - { - return TxOutcome.Failure(ex); - } - } + public TResult WithTx(Func body) => + base.WithTx(tx => body((ProcedureTxContext)tx)); [Experimental("STDB_UNSTABLE")] - public readonly record struct TxResult - where TError : Exception - { - public bool IsSuccess { get; } - public TSuccess? Value { get; } - public TError? Error { get; } - - private TxResult(bool isSuccess, TSuccess? value, TError? error) - { - IsSuccess = isSuccess; - Value = value; - Error = error; - } - - public static TxResult Success(TSuccess value) => - new(true, value, default); - - public static TxResult Failure(TError error) => - new(false, default, error); - - public TResult Match( - Func onSuccess, - Func onError) - { - if (onSuccess is null) throw new ArgumentNullException(nameof(onSuccess)); - if (onError is null) throw new ArgumentNullException(nameof(onError)); - return IsSuccess ? onSuccess(Value!) : onError(Error!); - } - } - - private async Task> RunWithRetryAsync( - Func>> body) - where TError : Exception - { - var result = await RunOnceAsync(body).ConfigureAwait(false); - - async Task Retry() - { - result = await RunOnceAsync(body).ConfigureAwait(false); - return true; - } - - if (!await SpacetimeDB.Internal.Procedure.CommitMutTxWithRetryAsync(Retry).ConfigureAwait(false)) - { - await SpacetimeDB.Internal.Procedure.AbortMutTxAsync().ConfigureAwait(false); - } - if (TryTakeTransactionOffset(out var offset)) { - SpacetimeDB.Internal.Module.RecordProcedureTxOffset(offset); - } - - return result; - } - - private async Task> RunOnceAsync( - Func>> body) - where TError : Exception - { - var micros = SpacetimeDB.Internal.Procedure.StartMutTx(); - await using var guard = new AsyncAbortGuard(SpacetimeDB.Internal.Procedure.AbortMutTxAsync); - var txCtx = MakeTxContext(micros); - var output = await body(txCtx).ConfigureAwait(false); - await guard.DisarmAsync().ConfigureAwait(false); - return output; - } - - private sealed class AsyncAbortGuard : IAsyncDisposable - { - private readonly Func abort; - private bool disarmed; - public AsyncAbortGuard(Func abort) => this.abort = abort; - public Task DisarmAsync() { disarmed = true; return Task.CompletedTask; } - public async ValueTask DisposeAsync() - { - if (!disarmed) await abort().ConfigureAwait(false); - } - } - - private bool RetryOnce( - Func> body, - out TxResult result) - where TError : Exception - { - result = RunOnce(body); - return true; - } - - private TxResult RunOnce( - Func> body) - where TError : Exception - { - var micros = SpacetimeDB.Internal.Procedure.StartMutTx(); - using var guard = new AbortGuard(SpacetimeDB.Internal.Procedure.AbortMutTx); - var txCtx = MakeTxContext(micros); - var output = body(txCtx); - guard.Disarm(); - return output; - } - - private TxContext MakeTxContext(long micros) - { - var txTimestamp = new Timestamp(micros); - Timestamp = txTimestamp; - var reducerCtx = new ReducerContext( - Sender, ConnectionId, new Random(unchecked((int)micros)), - txTimestamp, SenderAuth); - return new TxContext(new Local(), reducerCtx); - } + public TxOutcome TryWithTx( + Func> body) + where TError : Exception => + base.TryWithTx(tx => body((ProcedureTxContext)tx)); + } + + [Experimental("STDB_UNSTABLE")] + public sealed class ProcedureTxContext : global::SpacetimeDB.ProcedureTxContextBase { + internal ProcedureTxContext(Internal.TxContext inner) : base(inner) {} + + public new Local Db => (Local)base.Db; + } + + public sealed class Local : global::SpacetimeDB.LocalBase { + {{string.Join("\n", tableAccessors.Select(v => v.getter))}} + } + + public sealed class LocalReadOnly : global::SpacetimeDB.LocalReadOnlyBase { + {{string.Join("\n", readOnlyAccessors.Select(v => v.readOnlyGetter))}} } - public sealed record ViewContext : DbContext, Internal.IViewContext + public sealed record ViewContext : DbContext, Internal.IViewContext { public Identity Sender { get; } - - internal ViewContext(Identity sender, Internal.LocalReadOnly db) - : base(db) - { - Sender = sender; - } + internal ViewContext(Identity sender, LocalReadOnly db) : base(db) => Sender = sender; } - public sealed record AnonymousViewContext : DbContext, Internal.IAnonymousViewContext - { - internal AnonymousViewContext(Internal.LocalReadOnly db) - : base(db) { } + public sealed record AnonymousViewContext : DbContext, Internal.IAnonymousViewContext { + internal AnonymousViewContext(LocalReadOnly db) : base(db) { } } + } - namespace Internal.TableHandles { - {{string.Join("\n", tableAccessors.Select(v => v.tableAccessor))}} - } - - public sealed class Local { - {{string.Join("\n", tableAccessors.Select(v => v.getter))}} - } + namespace SpacetimeDB.Internal.TableHandles { + {{string.Join("\n", tableAccessors.Select(v => v.tableAccessor))}} } {{string.Join("\n", @@ -1938,12 +1813,6 @@ namespace SpacetimeDB.Internal.ViewHandles { {{string.Join("\n", readOnlyAccessors.Array.Select(v => v.readOnlyAccessor))}} } - namespace SpacetimeDB.Internal { - public sealed partial class LocalReadOnly { - {{string.Join("\n", readOnlyAccessors.Select(v => v.readOnlyGetter))}} - } - } - static class ModuleRegistration { {{string.Join("\n", addReducers.Select(r => r.Class))}} @@ -1962,8 +1831,8 @@ public static List ToListOrEmpty(T? value) where T : struct #endif public static void Main() { SpacetimeDB.Internal.Module.SetReducerContextConstructor((identity, connectionId, random, time) => new SpacetimeDB.ReducerContext(identity, connectionId, random, time)); - SpacetimeDB.Internal.Module.SetViewContextConstructor(identity => new SpacetimeDB.ViewContext(identity, new SpacetimeDB.Internal.LocalReadOnly())); - SpacetimeDB.Internal.Module.SetAnonymousViewContextConstructor(() => new SpacetimeDB.AnonymousViewContext(new SpacetimeDB.Internal.LocalReadOnly())); + SpacetimeDB.Internal.Module.SetViewContextConstructor(identity => new SpacetimeDB.ViewContext(identity, new SpacetimeDB.LocalReadOnly())); + SpacetimeDB.Internal.Module.SetAnonymousViewContextConstructor(() => new SpacetimeDB.AnonymousViewContext(new SpacetimeDB.LocalReadOnly())); SpacetimeDB.Internal.Module.SetProcedureContextConstructor((identity, connectionId, random, time) => new SpacetimeDB.ProcedureContext(identity, connectionId, random, time)); var __memoryStream = new MemoryStream(); var __writer = new BinaryWriter(__memoryStream); diff --git a/crates/bindings-csharp/Runtime/Internal/IProcedure.cs b/crates/bindings-csharp/Runtime/Internal/IProcedure.cs index f5cd96d81c9..7b055c65048 100644 --- a/crates/bindings-csharp/Runtime/Internal/IProcedure.cs +++ b/crates/bindings-csharp/Runtime/Internal/IProcedure.cs @@ -37,4 +37,6 @@ public interface IInternalProcedureContext : IProcedureContext { bool TryTakeTransactionOffset(out TransactionOffset offset); void SetTransactionOffset(TransactionOffset offset); + TxContext EnterTxContext(long timestampMicros); + void ExitTxContext(); } diff --git a/crates/bindings-csharp/Runtime/Internal/Module.cs b/crates/bindings-csharp/Runtime/Internal/Module.cs index 274a87c3fdf..b2937db24ed 100644 --- a/crates/bindings-csharp/Runtime/Internal/Module.cs +++ b/crates/bindings-csharp/Runtime/Internal/Module.cs @@ -442,11 +442,20 @@ public static Errno __call_view_anon__(uint id, BytesSource args, BytesSink rows } } +/// +/// Read-write database access for procedure contexts. +/// The code generator will extend this partial class with table accessors. +/// +public partial class Local +{ + // Intentionally empty – generated code adds table handles here. +} + /// /// Read-only database access for view contexts. /// The code generator will extend this partial class to add table accessors. /// -public sealed partial class LocalReadOnly +public partial class LocalReadOnly { // This class is intentionally empty - the code generator will add // read-only table accessors for each table in the module. diff --git a/crates/bindings-csharp/Runtime/Internal/Procedure.cs b/crates/bindings-csharp/Runtime/Internal/Procedure.cs index f82a3bcbc8b..a11b7ff96ab 100644 --- a/crates/bindings-csharp/Runtime/Internal/Procedure.cs +++ b/crates/bindings-csharp/Runtime/Internal/Procedure.cs @@ -1,5 +1,3 @@ -using System.Threading; - namespace SpacetimeDB.Internal; public static class Procedure @@ -31,14 +29,17 @@ public static long StartMutTx() { var status = FFI.procedure_start_mut_tx(out var micros); FFI.ErrnoHelpers.ThrowIfError(status); + var ctx = RequireContext(); + ctx.EnterTxContext(micros); return micros; } public static void CommitMutTx() { FFI.procedure_commit_mut_tx(); // throws on error - if (RequireContext() is IInternalProcedureContext ctx && - TryTakeOffsetFromHost(out var offset)) + var ctx = RequireContext(); + ctx.ExitTxContext(); + if (TryTakeOffsetFromHost(out var offset)) { ctx.SetTransactionOffset(offset); Module.RecordProcedureTxOffset(offset); @@ -48,8 +49,9 @@ public static void CommitMutTx() public static void AbortMutTx() { FFI.procedure_abort_mut_tx(); // throws on error - if (RequireContext() is IInternalProcedureContext ctx && - TryTakeOffsetFromHost(out var offset)) + var ctx = RequireContext(); + ctx.ExitTxContext(); + if (TryTakeOffsetFromHost(out var offset)) { ctx.SetTransactionOffset(offset); Module.RecordProcedureTxOffset(offset); diff --git a/crates/bindings-csharp/Runtime/Internal/TxContext.cs b/crates/bindings-csharp/Runtime/Internal/TxContext.cs new file mode 100644 index 00000000000..db2589ee0cd --- /dev/null +++ b/crates/bindings-csharp/Runtime/Internal/TxContext.cs @@ -0,0 +1,30 @@ +namespace SpacetimeDB.Internal; + +public sealed class TxContext +{ + public TxContext( + Local db, + Identity sender, + ConnectionId? connectionId, + Timestamp timestamp, + AuthCtx senderAuth, + Random rng) + { + Db = db; + Sender = sender; + ConnectionId = connectionId; + Timestamp = timestamp; + SenderAuth = senderAuth; + Rng = rng; + } + + public Local Db { get; } + public Identity Sender { get; } + public ConnectionId? ConnectionId { get; } + public Timestamp Timestamp { get; } + public AuthCtx SenderAuth { get; } + public Random Rng { get; } + + public TxContext WithTimestamp(Timestamp ts) => + new(Db, Sender, ConnectionId, ts, SenderAuth, Rng); +} \ No newline at end of file diff --git a/crates/bindings-csharp/Runtime/ProcedureContext.cs b/crates/bindings-csharp/Runtime/ProcedureContext.cs new file mode 100644 index 00000000000..e9d6c006d44 --- /dev/null +++ b/crates/bindings-csharp/Runtime/ProcedureContext.cs @@ -0,0 +1,286 @@ +namespace SpacetimeDB; + +using System.Diagnostics.CodeAnalysis; + +#pragma warning disable STDB_UNSTABLE +public abstract class ProcedureContextBase : Internal.IInternalProcedureContext +{ + protected ProcedureContextBase( + Identity sender, + ConnectionId? connectionId, + Random random, + Timestamp time) + { + Sender = sender; + ConnectionId = connectionId; + Rng = random; + Timestamp = time; + SenderAuth = AuthCtx.BuildFromSystemTables(connectionId, sender); + } + + public Identity Identity => Internal.IProcedureContext.GetIdentity(); + public Identity Sender { get; } + public ConnectionId? ConnectionId { get; } + public Random Rng { get; } + public Timestamp Timestamp { get; private set; } + public AuthCtx SenderAuth { get; } + + private Internal.TransactionOffset? pendingTxOffset; + private Internal.TxContext? txContext; + private ProcedureTxContextBase? cachedUserTxContext; + + protected abstract ProcedureTxContextBase CreateTxContext(Internal.TxContext inner); + protected internal abstract LocalBase CreateLocal(); + + private protected ProcedureTxContextBase RequireTxContext() + { + var inner = txContext ?? throw new InvalidOperationException("Transaction context was not initialised."); + cachedUserTxContext ??= CreateTxContext(inner); + cachedUserTxContext.Refresh(inner); + return cachedUserTxContext; + } + + public Internal.TxContext EnterTxContext(long timestampMicros) + { + var timestamp = new Timestamp(timestampMicros); + Timestamp = timestamp; + txContext = txContext?.WithTimestamp(timestamp) + ?? new Internal.TxContext(CreateLocal(), Sender, ConnectionId, timestamp, SenderAuth, Rng); + return txContext; + } + + public void ExitTxContext() => txContext = null; + + public void SetTransactionOffset(Internal.TransactionOffset offset) => + pendingTxOffset = offset; + + public bool TryTakeTransactionOffset(out Internal.TransactionOffset offset) + { + if (pendingTxOffset is { } value) + { + pendingTxOffset = null; + offset = value; + return true; + } + + offset = default; + return false; + } + + public readonly struct TxOutcome + { + public TxOutcome(bool isSuccess, TResult? value, Exception? error) + { + IsSuccess = isSuccess; + Value = value; + Error = error; + } + + public bool IsSuccess { get; } + public TResult? Value { get; } + public Exception? Error { get; } + + public static TxOutcome Success(TResult value) => + new(true, value, null); + + public static TxOutcome Failure(Exception error) => + new(false, default, error); + + public TResult UnwrapOrThrow() => + IsSuccess ? Value! : throw (Error ?? new InvalidOperationException("Transaction failed without an error object.")); + + public TResult UnwrapOrThrow(Func fallbackFactory) => + IsSuccess ? Value! : throw (Error ?? fallbackFactory()); + } + + public readonly struct TxResult + where TError : Exception + { + public TxResult(bool isSuccess, TResult? value, TError? error) + { + IsSuccess = isSuccess; + Value = value; + Error = error; + } + + public bool IsSuccess { get; } + public TResult? Value { get; } + public TError? Error { get; } + + public static TxResult Success(TResult value) => + new(true, value, null); + + public static TxResult Failure(TError error) => + new(false, default, error); + + public TResult UnwrapOrThrow() + { + if (IsSuccess) + { + return Value!; + } + + if (Error is not null) + { + throw Error; + } + + throw new InvalidOperationException("Transaction failed without an error object."); + } + } + + [Experimental("STDB_UNSTABLE")] + public TResult WithTx(Func body) => + TryWithTx(tx => TxResult.Success(body(tx))).UnwrapOrThrow(); + + [Experimental("STDB_UNSTABLE")] + public TxOutcome TryWithTx( + Func> body) + where TError : Exception + { + try + { + var result = RunWithRetry(body); + return result.IsSuccess + ? TxOutcome.Success(result.Value!) + : TxOutcome.Failure(result.Error!); + } + catch (Exception ex) + { + return TxOutcome.Failure(ex); + } + } + + private TxResult RunWithRetry( + Func> body) + where TError : Exception + { + var result = RunOnce(body); + if (!result.IsSuccess) + { + return result; + } + + bool Retry() + { + result = RunOnce(body); + return result.IsSuccess; + } + + if (!SpacetimeDB.Internal.Procedure.CommitMutTxWithRetry(Retry)) + { + return result; + } + + if (TryTakeTransactionOffset(out var offset)) + { + SetTransactionOffset(offset); + SpacetimeDB.Internal.Module.RecordProcedureTxOffset(offset); + } + + return result; + } + + private TxResult RunOnce( + Func> body) + where TError : Exception + { + _ = SpacetimeDB.Internal.Procedure.StartMutTx(); + using var guard = new AbortGuard(SpacetimeDB.Internal.Procedure.AbortMutTx); + var txCtx = RequireTxContext(); + var result = body(txCtx); + if (result.IsSuccess) + { + guard.Disarm(); + return result; + } + + SpacetimeDB.Internal.Procedure.AbortMutTx(); + guard.Disarm(); + return result; + } + + private sealed class AbortGuard : IDisposable + { + private readonly Action abort; + private bool disarmed; + + public AbortGuard(Action abort) => this.abort = abort; + + public void Disarm() => disarmed = true; + + public void Dispose() + { + if (!disarmed) + { + abort(); + } + } + } +} + +public abstract class ProcedureTxContextBase +{ + protected ProcedureTxContextBase(Internal.TxContext inner) + { + Inner = inner; + } + + internal Internal.TxContext Inner { get; private set; } + + internal void Refresh(Internal.TxContext inner) => Inner = inner; + + public LocalBase Db => (LocalBase)Inner.Db; + public Identity Sender => Inner.Sender; + public ConnectionId? ConnectionId => Inner.ConnectionId; + public Timestamp Timestamp => Inner.Timestamp; + public AuthCtx SenderAuth => Inner.SenderAuth; + public Random Rng => Inner.Rng; +} + +public abstract class LocalBase : Internal.Local +{ +} + +public abstract class LocalReadOnlyBase : Internal.LocalReadOnly +{ +} + +public sealed class ProcedureContext : ProcedureContextBase +{ + private readonly Local _db = new(); + + public ProcedureContext( + Identity sender, + ConnectionId? connectionId, + Random random, + Timestamp timestamp) + : base(sender, connectionId, random, timestamp) + { + } + + protected internal override LocalBase CreateLocal() => _db; + protected override ProcedureTxContextBase CreateTxContext(Internal.TxContext inner) => + _cached ??= new ProcedureTxContext(inner); + + private ProcedureTxContext? _cached; +} + +public sealed class ProcedureTxContext : ProcedureTxContextBase +{ + internal ProcedureTxContext(Internal.TxContext inner) + : base(inner) + { + } + + public new Local Db => (Local)base.Db; +} + +public sealed class Local : LocalBase +{ +} + +public sealed class LocalReadOnly : LocalReadOnlyBase +{ +} +#pragma warning restore STDB_UNSTABLE \ No newline at end of file From 758bd23e0984bf1bc98ddbc3308374924ec8d489 Mon Sep 17 00:00:00 2001 From: rekhoff Date: Thu, 4 Dec 2025 08:55:10 -0800 Subject: [PATCH 3/4] Updated C# formatting and snapshots --- .../BSATN.Codegen/BSATN.Codegen.csproj | 2 - crates/bindings-csharp/BSATN.Codegen/Diag.cs | 99 +- crates/bindings-csharp/BSATN.Codegen/Type.cs | 4 +- .../BSATN.Runtime.Tests.csproj | 8 +- .../BSATN.Runtime.Tests/Tests.cs | 29 +- .../BSATN.Runtime/BSATN.Runtime.csproj | 14 +- .../BSATN.Runtime/BSATN/I256.cs | 1 - .../BSATN.Runtime/BSATN/Runtime.cs | 5 +- .../bindings-csharp/BSATN.Runtime/Builtins.cs | 46 +- .../Codegen.Tests/Codegen.Tests.csproj | 2 - .../fixtures/client/client.csproj | 2 - .../Codegen.Tests/fixtures/diag/diag.csproj | 2 - .../diag/snapshots/Module#FFI.verified.cs | 1792 ++++++++-------- .../fixtures/server/server.csproj | 2 - .../server/snapshots/Module#FFI.verified.cs | 1843 ++++++++--------- crates/bindings-csharp/Codegen/Codegen.csproj | 7 +- crates/bindings-csharp/Codegen/Diag.cs | 343 ++- crates/bindings-csharp/Codegen/Module.cs | 98 +- .../Runtime.Tests/Runtime.Tests.csproj | 6 +- crates/bindings-csharp/Runtime/Exceptions.cs | 6 +- .../bindings-csharp/Runtime/Internal/FFI.cs | 53 +- .../Runtime/Internal/ITable.cs | 16 +- .../Runtime/Internal/Module.cs | 2 +- .../Runtime/Internal/Procedure.cs | 17 +- .../Runtime/Internal/TxContext.cs | 5 +- .../Runtime/ProcedureContext.cs | 130 +- crates/bindings-csharp/Runtime/Runtime.csproj | 14 +- .../Runtime/build/SpacetimeDB.Runtime.props | 2 - .../Runtime/build/SpacetimeDB.Runtime.targets | 43 +- .../examples~/regression-tests/server/Lib.cs | 4 +- 30 files changed, 2277 insertions(+), 2320 deletions(-) diff --git a/crates/bindings-csharp/BSATN.Codegen/BSATN.Codegen.csproj b/crates/bindings-csharp/BSATN.Codegen/BSATN.Codegen.csproj index 0884890a939..f3aea963486 100644 --- a/crates/bindings-csharp/BSATN.Codegen/BSATN.Codegen.csproj +++ b/crates/bindings-csharp/BSATN.Codegen/BSATN.Codegen.csproj @@ -1,5 +1,4 @@ - SpacetimeDB.BSATN.Codegen 1.11.0 @@ -27,5 +26,4 @@ - diff --git a/crates/bindings-csharp/BSATN.Codegen/Diag.cs b/crates/bindings-csharp/BSATN.Codegen/Diag.cs index 2ae3b2513ba..53d0d7f2432 100644 --- a/crates/bindings-csharp/BSATN.Codegen/Diag.cs +++ b/crates/bindings-csharp/BSATN.Codegen/Diag.cs @@ -134,61 +134,55 @@ internal static class ErrorDescriptor ISymbol member, ITypeSymbol type, Exception e - )> UnsupportedType = - new( - group, - "Unsupported type", - ctx => $"BSATN implementation for {ctx.type} is not found: {ctx.e.Message}", - ctx => ctx.member - ); + )> UnsupportedType = new( + group, + "Unsupported type", + ctx => $"BSATN implementation for {ctx.type} is not found: {ctx.e.Message}", + ctx => ctx.member + ); public static readonly ErrorDescriptor<( EqualsValueClauseSyntax equalsValue, EnumMemberDeclarationSyntax enumMember, EnumDeclarationSyntax @enum - )> EnumWithExplicitValues = - new( - group, - "[SpacetimeDB.Type] enums cannot have explicit values", - ctx => - $"{ctx.@enum.Identifier}.{ctx.enumMember.Identifier} has an explicit value {ctx.equalsValue.Value} which is not allowed in SpacetimeDB enums.", - ctx => ctx.equalsValue - ); + )> EnumWithExplicitValues = new( + group, + "[SpacetimeDB.Type] enums cannot have explicit values", + ctx => + $"{ctx.@enum.Identifier}.{ctx.enumMember.Identifier} has an explicit value {ctx.equalsValue.Value} which is not allowed in SpacetimeDB enums.", + ctx => ctx.equalsValue + ); - public static readonly ErrorDescriptor EnumTooManyVariants = - new( - group, - "[SpacetimeDB.Type] enums are limited to 256 variants", - @enum => - $"{@enum.Identifier} has {@enum.Members.Count} variants which is more than the allowed 256 variants for SpacetimeDB enums.", - @enum => @enum.Members[256] - ); + public static readonly ErrorDescriptor EnumTooManyVariants = new( + group, + "[SpacetimeDB.Type] enums are limited to 256 variants", + @enum => + $"{@enum.Identifier} has {@enum.Members.Count} variants which is more than the allowed 256 variants for SpacetimeDB enums.", + @enum => @enum.Members[256] + ); - public static readonly ErrorDescriptor TaggedEnumInlineTuple = - new( - group, - "Tagged enum variants must be declared with inline tuples", - baseType => - $"{baseType} does not have the expected format SpacetimeDB.TaggedEnum<(TVariant1 v1, ..., TVariantN vN)>.", - baseType => baseType - ); + public static readonly ErrorDescriptor TaggedEnumInlineTuple = new( + group, + "Tagged enum variants must be declared with inline tuples", + baseType => + $"{baseType} does not have the expected format SpacetimeDB.TaggedEnum<(TVariant1 v1, ..., TVariantN vN)>.", + baseType => baseType + ); - public static readonly ErrorDescriptor TaggedEnumField = - new( - group, - "Tagged enums cannot have instance fields", - field => - $"{field.Name} is an instance field, which are not permitted inside SpacetimeDB tagged enums.", - field => field - ); + public static readonly ErrorDescriptor TaggedEnumField = new( + group, + "Tagged enums cannot have instance fields", + field => + $"{field.Name} is an instance field, which are not permitted inside SpacetimeDB tagged enums.", + field => field + ); - public static readonly ErrorDescriptor TypeParams = - new( - group, - "Type parameters are not yet supported", - typeParams => $"Type parameters {typeParams} are not supported in SpacetimeDB types.", - typeParams => typeParams - ); + public static readonly ErrorDescriptor TypeParams = new( + group, + "Type parameters are not yet supported", + typeParams => $"Type parameters {typeParams} are not supported in SpacetimeDB types.", + typeParams => typeParams + ); } // This class is used to collect diagnostics during parsing and return them as a combined result. @@ -214,13 +208,12 @@ public void Report(ErrorDescriptor descriptor, TContext ctx) private DiagReporter() { } - private static readonly ErrorDescriptor<(Location location, Exception e)> InternalError = - new( - new("STDBINT", "SpacetimeDB.Internal"), - "Internal SpacetimeDB codegen error", - ctx => $"An internal error occurred during codegen: {ctx.e.Message}", - ctx => ctx.location - ); + private static readonly ErrorDescriptor<(Location location, Exception e)> InternalError = new( + new("STDBINT", "SpacetimeDB.Internal"), + "Internal SpacetimeDB codegen error", + ctx => $"An internal error occurred during codegen: {ctx.e.Message}", + ctx => ctx.location + ); public static ParseResult With(Location location, Func build) where T : IEquatable diff --git a/crates/bindings-csharp/BSATN.Codegen/Type.cs b/crates/bindings-csharp/BSATN.Codegen/Type.cs index 56c4af41f07..9d8ad56f26f 100644 --- a/crates/bindings-csharp/BSATN.Codegen/Type.cs +++ b/crates/bindings-csharp/BSATN.Codegen/Type.cs @@ -516,7 +516,7 @@ public sealed record {{m.Name}}({{m.Type.Name}} {{m.Name}}_) : {{ShortName}} public override string ToString() => $"{{m.Name}}({ SpacetimeDB.BSATN.StringUtil.GenericToString({{m.Name}}_) })"; } - + """ ) ) @@ -659,7 +659,7 @@ public override int GetHashCode() { {{getHashCode}} } - + """ ); diff --git a/crates/bindings-csharp/BSATN.Runtime.Tests/BSATN.Runtime.Tests.csproj b/crates/bindings-csharp/BSATN.Runtime.Tests/BSATN.Runtime.Tests.csproj index 5bb0e2c30a6..b4bdf12f40e 100644 --- a/crates/bindings-csharp/BSATN.Runtime.Tests/BSATN.Runtime.Tests.csproj +++ b/crates/bindings-csharp/BSATN.Runtime.Tests/BSATN.Runtime.Tests.csproj @@ -1,5 +1,4 @@ - false true @@ -20,7 +19,10 @@ - + - diff --git a/crates/bindings-csharp/BSATN.Runtime.Tests/Tests.cs b/crates/bindings-csharp/BSATN.Runtime.Tests/Tests.cs index c22879a596c..bee26979774 100644 --- a/crates/bindings-csharp/BSATN.Runtime.Tests/Tests.cs +++ b/crates/bindings-csharp/BSATN.Runtime.Tests/Tests.cs @@ -137,8 +137,8 @@ public static void IdentityLengthCheck() public static void NonHexStrings() { // n.b. 32 chars long - Assert.ThrowsAny( - () => ConnectionId.FromHexString("these are not hex characters....") + Assert.ThrowsAny(() => + ConnectionId.FromHexString("these are not hex characters....") ); } @@ -626,7 +626,6 @@ public static void GeneratedNestedListRoundTrip() .Select(list => new ContainsNestedList(list)); #pragma warning restore CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types. - static readonly Gen<(ContainsNestedList e1, ContainsNestedList e2)> GenTwoContainsNestedList = Gen.Select(GenContainsNestedList, GenContainsNestedList, (e1, e2) => (e1, e2)); @@ -797,26 +796,22 @@ public static void GeneratedToString() ); Assert.Equal( "ContainsList { TheList = [ X(1), Y(\"hi\"), W(BasicDataRecord { X = 1, Y = \"hi\", Z = null, W = null }) ] }", - new ContainsList( - [ - new BasicEnum.X(1), - new BasicEnum.Y("hi"), - new BasicEnum.W(new BasicDataRecord((1, "hi", null, null))), - ] - ).ToString() + new ContainsList([ + new BasicEnum.X(1), + new BasicEnum.Y("hi"), + new BasicEnum.W(new BasicDataRecord((1, "hi", null, null))), + ]).ToString() ); #pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. Assert.Equal( "ContainsNestedList { TheList = [ [ [ X(1), null ], null ], null ] }", - new ContainsNestedList( + new ContainsNestedList([ [ - [ - [new BasicEnum.X(1), null], - null, - ], + [new BasicEnum.X(1), null], null, - ] - ).ToString() + ], + null, + ]).ToString() ); #pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type. } diff --git a/crates/bindings-csharp/BSATN.Runtime/BSATN.Runtime.csproj b/crates/bindings-csharp/BSATN.Runtime/BSATN.Runtime.csproj index b781668147d..c12bad75129 100644 --- a/crates/bindings-csharp/BSATN.Runtime/BSATN.Runtime.csproj +++ b/crates/bindings-csharp/BSATN.Runtime/BSATN.Runtime.csproj @@ -1,5 +1,4 @@ - SpacetimeDB.BSATN.Runtime 1.11.0 @@ -18,18 +17,25 @@ - + - + - diff --git a/crates/bindings-csharp/BSATN.Runtime/BSATN/I256.cs b/crates/bindings-csharp/BSATN.Runtime/BSATN/I256.cs index b217944f3bd..f4bdd40cf32 100644 --- a/crates/bindings-csharp/BSATN.Runtime/BSATN/I256.cs +++ b/crates/bindings-csharp/BSATN.Runtime/BSATN/I256.cs @@ -97,7 +97,6 @@ public int CompareTo(I256 value) } /// - public static bool IsNegative(I256 value) => (long)value._upper.Upper < 0; private BigInteger AsBigInt() => diff --git a/crates/bindings-csharp/BSATN.Runtime/BSATN/Runtime.cs b/crates/bindings-csharp/BSATN.Runtime/BSATN/Runtime.cs index 9a7a617a2ab..bde8ac8bbd7 100644 --- a/crates/bindings-csharp/BSATN.Runtime/BSATN/Runtime.cs +++ b/crates/bindings-csharp/BSATN.Runtime/BSATN/Runtime.cs @@ -577,8 +577,9 @@ public AlgebraicType GetAlgebraicType(ITypeRegistrar registrar) => // reduce amount of noisy compilation errors when a used type is not supported by BSATN. public readonly struct Unsupported : IReadWrite { - private static readonly NotSupportedException Exception = - new($"Type {typeof(T)} is not supported by BSATN."); + private static readonly NotSupportedException Exception = new( + $"Type {typeof(T)} is not supported by BSATN." + ); public T Read(BinaryReader reader) => throw Exception; diff --git a/crates/bindings-csharp/BSATN.Runtime/Builtins.cs b/crates/bindings-csharp/BSATN.Runtime/Builtins.cs index a3478d18023..d2ba774bd1c 100644 --- a/crates/bindings-csharp/BSATN.Runtime/Builtins.cs +++ b/crates/bindings-csharp/BSATN.Runtime/Builtins.cs @@ -191,12 +191,10 @@ public void Write(BinaryWriter writer, ConnectionId value) => // --- customized --- public AlgebraicType GetAlgebraicType(ITypeRegistrar registrar) => // Return a Product directly, not a Ref, because this is a special type. - new AlgebraicType.Product( - [ - // Using this specific name here is important. - new("__connection_id__", new AlgebraicType.U128(default)), - ] - ); + new AlgebraicType.Product([ + // Using this specific name here is important. + new("__connection_id__", new AlgebraicType.U128(default)), + ]); // --- / customized --- } @@ -283,12 +281,10 @@ public void Write(BinaryWriter writer, Identity value) => // --- customized --- public AlgebraicType GetAlgebraicType(ITypeRegistrar registrar) => // Return a Product directly, not a Ref, because this is a special type. - new AlgebraicType.Product( - [ - // Using this specific name here is important. - new("__identity__", new AlgebraicType.U256(default)), - ] - ); + new AlgebraicType.Product([ + // Using this specific name here is important. + new("__identity__", new AlgebraicType.U256(default)), + ]); // --- / customized --- } @@ -414,9 +410,10 @@ public void Write(BinaryWriter writer, Timestamp value) public AlgebraicType GetAlgebraicType(ITypeRegistrar registrar) => // Return a Product directly, not a Ref, because this is a special type. new AlgebraicType.Product( - // Using this specific name here is important. - [new("__timestamp_micros_since_unix_epoch__", new AlgebraicType.I64(default))] - ); + // Using this specific name here is important. + [ + new("__timestamp_micros_since_unix_epoch__", new AlgebraicType.I64(default)), + ]); // --- / customized --- } } @@ -516,9 +513,10 @@ public void Write(BinaryWriter writer, TimeDuration value) public AlgebraicType GetAlgebraicType(ITypeRegistrar registrar) => // Return a Product directly, not a Ref, because this is a special type. new AlgebraicType.Product( - // Using this specific name here is important. - [new("__time_duration_micros__", new AlgebraicType.I64(default))] - ); + // Using this specific name here is important. + [ + new("__time_duration_micros__", new AlgebraicType.I64(default)), + ]); // --- / customized --- } } @@ -595,13 +593,11 @@ public void Write(BinaryWriter writer, ScheduleAt value) // --- customized --- public AlgebraicType GetAlgebraicType(ITypeRegistrar registrar) => // Return a Sum directly, not a Ref, because this is a special type. - new AlgebraicType.Sum( - [ - // Using these specific names here is important. - new("Interval", Interval.GetAlgebraicType(registrar)), - new("Time", Time.GetAlgebraicType(registrar)), - ] - ); + new AlgebraicType.Sum([ + // Using these specific names here is important. + new("Interval", Interval.GetAlgebraicType(registrar)), + new("Time", Time.GetAlgebraicType(registrar)), + ]); // --- / customized --- } } diff --git a/crates/bindings-csharp/Codegen.Tests/Codegen.Tests.csproj b/crates/bindings-csharp/Codegen.Tests/Codegen.Tests.csproj index 5f02268f537..50adc298107 100644 --- a/crates/bindings-csharp/Codegen.Tests/Codegen.Tests.csproj +++ b/crates/bindings-csharp/Codegen.Tests/Codegen.Tests.csproj @@ -1,5 +1,4 @@ - false true @@ -32,5 +31,4 @@ - diff --git a/crates/bindings-csharp/Codegen.Tests/fixtures/client/client.csproj b/crates/bindings-csharp/Codegen.Tests/fixtures/client/client.csproj index 8f25982a1d2..3867044feac 100644 --- a/crates/bindings-csharp/Codegen.Tests/fixtures/client/client.csproj +++ b/crates/bindings-csharp/Codegen.Tests/fixtures/client/client.csproj @@ -1,5 +1,4 @@  - @@ -10,5 +9,4 @@ - diff --git a/crates/bindings-csharp/Codegen.Tests/fixtures/diag/diag.csproj b/crates/bindings-csharp/Codegen.Tests/fixtures/diag/diag.csproj index 426f04d2bc6..66830dc463c 100644 --- a/crates/bindings-csharp/Codegen.Tests/fixtures/diag/diag.csproj +++ b/crates/bindings-csharp/Codegen.Tests/fixtures/diag/diag.csproj @@ -1,5 +1,4 @@  - net8.0 enable @@ -9,5 +8,4 @@ - diff --git a/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module#FFI.verified.cs b/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module#FFI.verified.cs index 42936be56cd..dccfa6caedc 100644 --- a/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module#FFI.verified.cs +++ b/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module#FFI.verified.cs @@ -5,10 +5,13 @@ // This is needed so every module build doesn't generate a full LocalReadOnly type, but just adds on to the existing. // We extend it here with generated table accessors, and just need to suppress the duplicate-type warning. #pragma warning disable CS0436 +#pragma warning disable STDB_UNSTABLE using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using Internal = SpacetimeDB.Internal; +using TxContext = SpacetimeDB.Internal.TxContext; namespace SpacetimeDB { @@ -27,27 +30,21 @@ internal ReducerContext( Identity identity, ConnectionId? connectionId, Random random, - Timestamp time + Timestamp time, + AuthCtx? senderAuth = null ) { Sender = identity; ConnectionId = connectionId; Rng = random; Timestamp = time; - SenderAuth = AuthCtx.BuildFromSystemTables(connectionId, identity); + SenderAuth = senderAuth ?? AuthCtx.BuildFromSystemTables(connectionId, identity); } } - public sealed record ProcedureContext : Internal.IProcedureContext + public sealed class ProcedureContext : global::SpacetimeDB.ProcedureContextBase { - public readonly Identity Sender; - public readonly ConnectionId? ConnectionId; - public readonly Random Rng; - public readonly Timestamp Timestamp; - public readonly AuthCtx SenderAuth; - - // We need this property to be non-static for parity with client SDK. - public Identity Identity => Internal.IProcedureContext.GetIdentity(); + private readonly Local _db = new(); internal ProcedureContext( Identity identity, @@ -55,1004 +52,1041 @@ internal ProcedureContext( Random random, Timestamp time ) - { - Sender = identity; - ConnectionId = connectionId; - Rng = random; - Timestamp = time; - SenderAuth = AuthCtx.BuildFromSystemTables(connectionId, identity); - } + : base(identity, connectionId, random, time) { } + + protected override global::SpacetimeDB.LocalBase CreateLocal() => _db; + + protected override global::SpacetimeDB.ProcedureTxContextBase CreateTxContext( + Internal.TxContext inner + ) => _cached ??= new ProcedureTxContext(inner); + + private ProcedureTxContext? _cached; + + [Experimental("STDB_UNSTABLE")] + public Local Db => _db; + + [Experimental("STDB_UNSTABLE")] + public TResult WithTx(Func body) => + base.WithTx(tx => body((ProcedureTxContext)tx)); + + [Experimental("STDB_UNSTABLE")] + public TxOutcome TryWithTx( + Func> body + ) + where TError : Exception => base.TryWithTx(tx => body((ProcedureTxContext)tx)); + } + + [Experimental("STDB_UNSTABLE")] + public sealed class ProcedureTxContext : global::SpacetimeDB.ProcedureTxContextBase + { + internal ProcedureTxContext(Internal.TxContext inner) + : base(inner) { } + + public new Local Db => (Local)base.Db; + } + + public sealed class Local : global::SpacetimeDB.LocalBase + { + public global::SpacetimeDB.Internal.TableHandles.Player Player => new(); + public global::SpacetimeDB.Internal.TableHandles.TestAutoIncNotInteger TestAutoIncNotInteger => + new(); + public global::SpacetimeDB.Internal.TableHandles.TestDefaultFieldValues TestDefaultFieldValues => + new(); + public global::SpacetimeDB.Internal.TableHandles.TestDuplicateTableName TestDuplicateTableName => + new(); + public global::SpacetimeDB.Internal.TableHandles.TestIndexIssues TestIndexIssues => new(); + public global::SpacetimeDB.Internal.TableHandles.TestScheduleWithMissingScheduleAtField TestScheduleWithMissingScheduleAtField => + new(); + public global::SpacetimeDB.Internal.TableHandles.TestScheduleWithoutPrimaryKey TestScheduleWithoutPrimaryKey => + new(); + public global::SpacetimeDB.Internal.TableHandles.TestScheduleWithoutScheduleAt TestScheduleWithoutScheduleAt => + new(); + public global::SpacetimeDB.Internal.TableHandles.TestScheduleWithWrongPrimaryKeyType TestScheduleWithWrongPrimaryKeyType => + new(); + public global::SpacetimeDB.Internal.TableHandles.TestScheduleWithWrongScheduleAtType TestScheduleWithWrongScheduleAtType => + new(); + public global::SpacetimeDB.Internal.TableHandles.TestUniqueNotEquatable TestUniqueNotEquatable => + new(); + } + + public sealed class LocalReadOnly : global::SpacetimeDB.LocalReadOnlyBase + { + public global::SpacetimeDB.Internal.ViewHandles.PlayerReadOnly Player => new(); + public global::SpacetimeDB.Internal.ViewHandles.TestAutoIncNotIntegerReadOnly TestAutoIncNotInteger => + new(); + public global::SpacetimeDB.Internal.ViewHandles.TestDefaultFieldValuesReadOnly TestDefaultFieldValues => + new(); + public global::SpacetimeDB.Internal.ViewHandles.TestDuplicateTableNameReadOnly TestDuplicateTableName => + new(); + public global::SpacetimeDB.Internal.ViewHandles.TestIndexIssuesReadOnly TestIndexIssues => + new(); + public global::SpacetimeDB.Internal.ViewHandles.TestScheduleWithMissingScheduleAtFieldReadOnly TestScheduleWithMissingScheduleAtField => + new(); + public global::SpacetimeDB.Internal.ViewHandles.TestScheduleWithoutPrimaryKeyReadOnly TestScheduleWithoutPrimaryKey => + new(); + public global::SpacetimeDB.Internal.ViewHandles.TestScheduleWithoutScheduleAtReadOnly TestScheduleWithoutScheduleAt => + new(); + public global::SpacetimeDB.Internal.ViewHandles.TestScheduleWithWrongPrimaryKeyTypeReadOnly TestScheduleWithWrongPrimaryKeyType => + new(); + public global::SpacetimeDB.Internal.ViewHandles.TestScheduleWithWrongScheduleAtTypeReadOnly TestScheduleWithWrongScheduleAtType => + new(); + public global::SpacetimeDB.Internal.ViewHandles.TestUniqueNotEquatableReadOnly TestUniqueNotEquatable => + new(); } - public sealed record ViewContext : DbContext, Internal.IViewContext + public sealed record ViewContext : DbContext, Internal.IViewContext { public Identity Sender { get; } - internal ViewContext(Identity sender, Internal.LocalReadOnly db) - : base(db) - { - Sender = sender; - } + internal ViewContext(Identity sender, LocalReadOnly db) + : base(db) => Sender = sender; } public sealed record AnonymousViewContext - : DbContext, + : DbContext, Internal.IAnonymousViewContext { - internal AnonymousViewContext(Internal.LocalReadOnly db) + internal AnonymousViewContext(LocalReadOnly db) : base(db) { } } +} - namespace Internal.TableHandles +namespace SpacetimeDB.Internal.TableHandles +{ + public readonly struct Player : global::SpacetimeDB.Internal.ITableView { - public readonly struct Player - : global::SpacetimeDB.Internal.ITableView + static global::Player global::SpacetimeDB.Internal.ITableView< + Player, + global::Player + >.ReadGenFields(System.IO.BinaryReader reader, global::Player row) { - static global::Player global::SpacetimeDB.Internal.ITableView< - Player, - global::Player - >.ReadGenFields(System.IO.BinaryReader reader, global::Player row) - { - return row; - } + return row; + } - static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< - Player, - global::Player - >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => - new( - Name: nameof(Player), - ProductTypeRef: (uint) - new global::Player.BSATN().GetAlgebraicType(registrar).Ref_, - PrimaryKey: [], - Indexes: - [ - new( - Name: null, - AccessorName: "Identity", - Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([0]) - ) - ], - Constraints: - [ - global::SpacetimeDB.Internal.ITableView< - Player, - global::Player - >.MakeUniqueConstraint(0) - ], - Sequences: [], - Schedule: null, - TableType: SpacetimeDB.Internal.TableType.User, - TableAccess: SpacetimeDB.Internal.TableAccess.Private - ); + static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< + Player, + global::Player + >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => + new( + Name: nameof(Player), + ProductTypeRef: (uint)new global::Player.BSATN().GetAlgebraicType(registrar).Ref_, + PrimaryKey: [], + Indexes: + [ + new( + Name: null, + AccessorName: "Identity", + Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([0]) + ) + ], + Constraints: + [ + global::SpacetimeDB.Internal.ITableView< + Player, + global::Player + >.MakeUniqueConstraint(0) + ], + Sequences: [], + Schedule: null, + TableType: SpacetimeDB.Internal.TableType.User, + TableAccess: SpacetimeDB.Internal.TableAccess.Private + ); - public ulong Count => - global::SpacetimeDB.Internal.ITableView.DoCount(); + public ulong Count => + global::SpacetimeDB.Internal.ITableView.DoCount(); - public IEnumerable Iter() => - global::SpacetimeDB.Internal.ITableView.DoIter(); + public IEnumerable Iter() => + global::SpacetimeDB.Internal.ITableView.DoIter(); - public global::Player Insert(global::Player row) => - global::SpacetimeDB.Internal.ITableView.DoInsert(row); + public global::Player Insert(global::Player row) => + global::SpacetimeDB.Internal.ITableView.DoInsert(row); - public bool Delete(global::Player row) => - global::SpacetimeDB.Internal.ITableView.DoDelete(row); + public bool Delete(global::Player row) => + global::SpacetimeDB.Internal.ITableView.DoDelete(row); - public sealed class IdentityUniqueIndex - : UniqueIndex< - Player, - global::Player, - SpacetimeDB.Identity, - SpacetimeDB.Identity.BSATN - > - { - internal IdentityUniqueIndex() - : base("Player_Identity_idx_btree") { } + public sealed class IdentityUniqueIndex + : UniqueIndex + { + internal IdentityUniqueIndex() + : base("Player_Identity_idx_btree") { } - // Important: don't move this to the base class. - // C# generics don't play well with nullable types and can't accept both struct-type-based and class-type-based - // `globalName` in one generic definition, leading to buggy `Row?` expansion for either one or another. - public global::Player? Find(SpacetimeDB.Identity key) => - DoFilter(key).Cast().SingleOrDefault(); + // Important: don't move this to the base class. + // C# generics don't play well with nullable types and can't accept both struct-type-based and class-type-based + // `globalName` in one generic definition, leading to buggy `Row?` expansion for either one or another. + public global::Player? Find(SpacetimeDB.Identity key) => + DoFilter(key).Cast().SingleOrDefault(); - public global::Player Update(global::Player row) => DoUpdate(row); - } + public global::Player Update(global::Player row) => DoUpdate(row); + } - public IdentityUniqueIndex Identity => new(); + public IdentityUniqueIndex Identity => new(); + } + + public readonly struct TestAutoIncNotInteger + : global::SpacetimeDB.Internal.ITableView< + TestAutoIncNotInteger, + global::TestAutoIncNotInteger + > + { + static global::TestAutoIncNotInteger global::SpacetimeDB.Internal.ITableView< + TestAutoIncNotInteger, + global::TestAutoIncNotInteger + >.ReadGenFields(System.IO.BinaryReader reader, global::TestAutoIncNotInteger row) + { + if (row.AutoIncField == default) + { + row.AutoIncField = global::TestAutoIncNotInteger.BSATN.AutoIncFieldRW.Read(reader); + } + if (row.IdentityField == default) + { + row.IdentityField = global::TestAutoIncNotInteger.BSATN.IdentityFieldRW.Read( + reader + ); + } + return row; } - public readonly struct TestAutoIncNotInteger - : global::SpacetimeDB.Internal.ITableView< + static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< + TestAutoIncNotInteger, + global::TestAutoIncNotInteger + >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => + new( + Name: nameof(TestAutoIncNotInteger), + ProductTypeRef: (uint) + new global::TestAutoIncNotInteger.BSATN().GetAlgebraicType(registrar).Ref_, + PrimaryKey: [], + Indexes: + [ + new( + Name: null, + AccessorName: "IdentityField", + Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([1]) + ) + ], + Constraints: + [ + global::SpacetimeDB.Internal.ITableView< + TestAutoIncNotInteger, + global::TestAutoIncNotInteger + >.MakeUniqueConstraint(1) + ], + Sequences: + [ + global::SpacetimeDB.Internal.ITableView< + TestAutoIncNotInteger, + global::TestAutoIncNotInteger + >.MakeSequence(0), + global::SpacetimeDB.Internal.ITableView< + TestAutoIncNotInteger, + global::TestAutoIncNotInteger + >.MakeSequence(1) + ], + Schedule: null, + TableType: SpacetimeDB.Internal.TableType.User, + TableAccess: SpacetimeDB.Internal.TableAccess.Private + ); + + public ulong Count => + global::SpacetimeDB.Internal.ITableView< TestAutoIncNotInteger, global::TestAutoIncNotInteger - > - { - static global::TestAutoIncNotInteger global::SpacetimeDB.Internal.ITableView< + >.DoCount(); + + public IEnumerable Iter() => + global::SpacetimeDB.Internal.ITableView< TestAutoIncNotInteger, global::TestAutoIncNotInteger - >.ReadGenFields(System.IO.BinaryReader reader, global::TestAutoIncNotInteger row) - { - if (row.AutoIncField == default) - { - row.AutoIncField = global::TestAutoIncNotInteger.BSATN.AutoIncFieldRW.Read( - reader - ); - } - if (row.IdentityField == default) - { - row.IdentityField = global::TestAutoIncNotInteger.BSATN.IdentityFieldRW.Read( - reader - ); - } - return row; - } + >.DoIter(); - static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< + public global::TestAutoIncNotInteger Insert(global::TestAutoIncNotInteger row) => + global::SpacetimeDB.Internal.ITableView< TestAutoIncNotInteger, global::TestAutoIncNotInteger - >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => - new( - Name: nameof(TestAutoIncNotInteger), - ProductTypeRef: (uint) - new global::TestAutoIncNotInteger.BSATN().GetAlgebraicType(registrar).Ref_, - PrimaryKey: [], - Indexes: - [ - new( - Name: null, - AccessorName: "IdentityField", - Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([1]) - ) - ], - Constraints: - [ - global::SpacetimeDB.Internal.ITableView< - TestAutoIncNotInteger, - global::TestAutoIncNotInteger - >.MakeUniqueConstraint(1) - ], - Sequences: - [ - global::SpacetimeDB.Internal.ITableView< - TestAutoIncNotInteger, - global::TestAutoIncNotInteger - >.MakeSequence(0), - global::SpacetimeDB.Internal.ITableView< - TestAutoIncNotInteger, - global::TestAutoIncNotInteger - >.MakeSequence(1) - ], - Schedule: null, - TableType: SpacetimeDB.Internal.TableType.User, - TableAccess: SpacetimeDB.Internal.TableAccess.Private - ); + >.DoInsert(row); - public ulong Count => - global::SpacetimeDB.Internal.ITableView< - TestAutoIncNotInteger, - global::TestAutoIncNotInteger - >.DoCount(); - - public IEnumerable Iter() => - global::SpacetimeDB.Internal.ITableView< - TestAutoIncNotInteger, - global::TestAutoIncNotInteger - >.DoIter(); - - public global::TestAutoIncNotInteger Insert(global::TestAutoIncNotInteger row) => - global::SpacetimeDB.Internal.ITableView< - TestAutoIncNotInteger, - global::TestAutoIncNotInteger - >.DoInsert(row); - - public bool Delete(global::TestAutoIncNotInteger row) => - global::SpacetimeDB.Internal.ITableView< - TestAutoIncNotInteger, - global::TestAutoIncNotInteger - >.DoDelete(row); - - public sealed class IdentityFieldUniqueIndex - : UniqueIndex< - TestAutoIncNotInteger, - global::TestAutoIncNotInteger, - string, - SpacetimeDB.BSATN.String - > - { - internal IdentityFieldUniqueIndex() - : base("TestAutoIncNotInteger_IdentityField_idx_btree") { } + public bool Delete(global::TestAutoIncNotInteger row) => + global::SpacetimeDB.Internal.ITableView< + TestAutoIncNotInteger, + global::TestAutoIncNotInteger + >.DoDelete(row); + + public sealed class IdentityFieldUniqueIndex + : UniqueIndex< + TestAutoIncNotInteger, + global::TestAutoIncNotInteger, + string, + SpacetimeDB.BSATN.String + > + { + internal IdentityFieldUniqueIndex() + : base("TestAutoIncNotInteger_IdentityField_idx_btree") { } - // Important: don't move this to the base class. - // C# generics don't play well with nullable types and can't accept both struct-type-based and class-type-based - // `globalName` in one generic definition, leading to buggy `Row?` expansion for either one or another. - public global::TestAutoIncNotInteger? Find(string key) => - DoFilter(key).Cast().SingleOrDefault(); + // Important: don't move this to the base class. + // C# generics don't play well with nullable types and can't accept both struct-type-based and class-type-based + // `globalName` in one generic definition, leading to buggy `Row?` expansion for either one or another. + public global::TestAutoIncNotInteger? Find(string key) => + DoFilter(key).Cast().SingleOrDefault(); - public global::TestAutoIncNotInteger Update(global::TestAutoIncNotInteger row) => - DoUpdate(row); - } + public global::TestAutoIncNotInteger Update(global::TestAutoIncNotInteger row) => + DoUpdate(row); + } + + public IdentityFieldUniqueIndex IdentityField => new(); + } - public IdentityFieldUniqueIndex IdentityField => new(); + public readonly struct TestDefaultFieldValues + : global::SpacetimeDB.Internal.ITableView< + TestDefaultFieldValues, + global::TestDefaultFieldValues + > + { + static global::TestDefaultFieldValues global::SpacetimeDB.Internal.ITableView< + TestDefaultFieldValues, + global::TestDefaultFieldValues + >.ReadGenFields(System.IO.BinaryReader reader, global::TestDefaultFieldValues row) + { + return row; } - public readonly struct TestDefaultFieldValues - : global::SpacetimeDB.Internal.ITableView< + static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< + TestDefaultFieldValues, + global::TestDefaultFieldValues + >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => + new( + Name: nameof(TestDefaultFieldValues), + ProductTypeRef: (uint) + new global::TestDefaultFieldValues.BSATN().GetAlgebraicType(registrar).Ref_, + PrimaryKey: [], + Indexes: + [ + new( + Name: null, + AccessorName: "UniqueField", + Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([0]) + ) + ], + Constraints: + [ + global::SpacetimeDB.Internal.ITableView< + TestDefaultFieldValues, + global::TestDefaultFieldValues + >.MakeUniqueConstraint(0) + ], + Sequences: [], + Schedule: null, + TableType: SpacetimeDB.Internal.TableType.User, + TableAccess: SpacetimeDB.Internal.TableAccess.Private + ); + + public ulong Count => + global::SpacetimeDB.Internal.ITableView< TestDefaultFieldValues, global::TestDefaultFieldValues - > - { - static global::TestDefaultFieldValues global::SpacetimeDB.Internal.ITableView< + >.DoCount(); + + public IEnumerable Iter() => + global::SpacetimeDB.Internal.ITableView< TestDefaultFieldValues, global::TestDefaultFieldValues - >.ReadGenFields(System.IO.BinaryReader reader, global::TestDefaultFieldValues row) - { - return row; - } + >.DoIter(); - static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< + public global::TestDefaultFieldValues Insert(global::TestDefaultFieldValues row) => + global::SpacetimeDB.Internal.ITableView< TestDefaultFieldValues, global::TestDefaultFieldValues - >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => - new( - Name: nameof(TestDefaultFieldValues), - ProductTypeRef: (uint) - new global::TestDefaultFieldValues.BSATN().GetAlgebraicType(registrar).Ref_, - PrimaryKey: [], - Indexes: - [ - new( - Name: null, - AccessorName: "UniqueField", - Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([0]) - ) - ], - Constraints: - [ - global::SpacetimeDB.Internal.ITableView< - TestDefaultFieldValues, - global::TestDefaultFieldValues - >.MakeUniqueConstraint(0) - ], - Sequences: [], - Schedule: null, - TableType: SpacetimeDB.Internal.TableType.User, - TableAccess: SpacetimeDB.Internal.TableAccess.Private - ); + >.DoInsert(row); - public ulong Count => - global::SpacetimeDB.Internal.ITableView< - TestDefaultFieldValues, - global::TestDefaultFieldValues - >.DoCount(); - - public IEnumerable Iter() => - global::SpacetimeDB.Internal.ITableView< - TestDefaultFieldValues, - global::TestDefaultFieldValues - >.DoIter(); - - public global::TestDefaultFieldValues Insert(global::TestDefaultFieldValues row) => - global::SpacetimeDB.Internal.ITableView< - TestDefaultFieldValues, - global::TestDefaultFieldValues - >.DoInsert(row); - - public bool Delete(global::TestDefaultFieldValues row) => - global::SpacetimeDB.Internal.ITableView< - TestDefaultFieldValues, - global::TestDefaultFieldValues - >.DoDelete(row); - } - - public readonly struct TestDuplicateTableName - : global::SpacetimeDB.Internal.ITableView< + public bool Delete(global::TestDefaultFieldValues row) => + global::SpacetimeDB.Internal.ITableView< + TestDefaultFieldValues, + global::TestDefaultFieldValues + >.DoDelete(row); + } + + public readonly struct TestDuplicateTableName + : global::SpacetimeDB.Internal.ITableView< + TestDuplicateTableName, + global::TestDuplicateTableName + > + { + static global::TestDuplicateTableName global::SpacetimeDB.Internal.ITableView< + TestDuplicateTableName, + global::TestDuplicateTableName + >.ReadGenFields(System.IO.BinaryReader reader, global::TestDuplicateTableName row) + { + return row; + } + + static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< + TestDuplicateTableName, + global::TestDuplicateTableName + >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => + new( + Name: nameof(TestDuplicateTableName), + ProductTypeRef: (uint) + new global::TestDuplicateTableName.BSATN().GetAlgebraicType(registrar).Ref_, + PrimaryKey: [], + Indexes: [], + Constraints: [], + Sequences: [], + Schedule: null, + TableType: SpacetimeDB.Internal.TableType.User, + TableAccess: SpacetimeDB.Internal.TableAccess.Private + ); + + public ulong Count => + global::SpacetimeDB.Internal.ITableView< TestDuplicateTableName, global::TestDuplicateTableName - > - { - static global::TestDuplicateTableName global::SpacetimeDB.Internal.ITableView< + >.DoCount(); + + public IEnumerable Iter() => + global::SpacetimeDB.Internal.ITableView< TestDuplicateTableName, global::TestDuplicateTableName - >.ReadGenFields(System.IO.BinaryReader reader, global::TestDuplicateTableName row) - { - return row; - } + >.DoIter(); - static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< + public global::TestDuplicateTableName Insert(global::TestDuplicateTableName row) => + global::SpacetimeDB.Internal.ITableView< TestDuplicateTableName, global::TestDuplicateTableName - >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => - new( - Name: nameof(TestDuplicateTableName), - ProductTypeRef: (uint) - new global::TestDuplicateTableName.BSATN().GetAlgebraicType(registrar).Ref_, - PrimaryKey: [], - Indexes: [], - Constraints: [], - Sequences: [], - Schedule: null, - TableType: SpacetimeDB.Internal.TableType.User, - TableAccess: SpacetimeDB.Internal.TableAccess.Private - ); + >.DoInsert(row); - public ulong Count => - global::SpacetimeDB.Internal.ITableView< - TestDuplicateTableName, - global::TestDuplicateTableName - >.DoCount(); + public bool Delete(global::TestDuplicateTableName row) => + global::SpacetimeDB.Internal.ITableView< + TestDuplicateTableName, + global::TestDuplicateTableName + >.DoDelete(row); + } - public IEnumerable Iter() => - global::SpacetimeDB.Internal.ITableView< - TestDuplicateTableName, - global::TestDuplicateTableName - >.DoIter(); + public readonly struct TestIndexIssues + : global::SpacetimeDB.Internal.ITableView + { + static global::TestIndexIssues global::SpacetimeDB.Internal.ITableView< + TestIndexIssues, + global::TestIndexIssues + >.ReadGenFields(System.IO.BinaryReader reader, global::TestIndexIssues row) + { + return row; + } - public global::TestDuplicateTableName Insert(global::TestDuplicateTableName row) => - global::SpacetimeDB.Internal.ITableView< - TestDuplicateTableName, - global::TestDuplicateTableName - >.DoInsert(row); + static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< + TestIndexIssues, + global::TestIndexIssues + >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => + new( + Name: nameof(TestIndexIssues), + ProductTypeRef: (uint) + new global::TestIndexIssues.BSATN().GetAlgebraicType(registrar).Ref_, + PrimaryKey: [], + Indexes: + [ + new( + Name: null, + AccessorName: "TestIndexWithoutColumns", + Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([]) + ), + new( + Name: null, + AccessorName: "TestIndexWithEmptyColumns", + Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([]) + ), + new( + Name: null, + AccessorName: "TestUnknownColumns", + Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([]) + ), + new( + Name: null, + AccessorName: "TestUnexpectedColumns", + Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([0]) + ) + ], + Constraints: [], + Sequences: [], + Schedule: null, + TableType: SpacetimeDB.Internal.TableType.User, + TableAccess: SpacetimeDB.Internal.TableAccess.Private + ); - public bool Delete(global::TestDuplicateTableName row) => - global::SpacetimeDB.Internal.ITableView< - TestDuplicateTableName, - global::TestDuplicateTableName - >.DoDelete(row); - } + public ulong Count => + global::SpacetimeDB.Internal.ITableView< + TestIndexIssues, + global::TestIndexIssues + >.DoCount(); - public readonly struct TestIndexIssues - : global::SpacetimeDB.Internal.ITableView - { - static global::TestIndexIssues global::SpacetimeDB.Internal.ITableView< + public IEnumerable Iter() => + global::SpacetimeDB.Internal.ITableView< TestIndexIssues, global::TestIndexIssues - >.ReadGenFields(System.IO.BinaryReader reader, global::TestIndexIssues row) - { - return row; - } + >.DoIter(); - static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< + public global::TestIndexIssues Insert(global::TestIndexIssues row) => + global::SpacetimeDB.Internal.ITableView< TestIndexIssues, global::TestIndexIssues - >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => - new( - Name: nameof(TestIndexIssues), - ProductTypeRef: (uint) - new global::TestIndexIssues.BSATN().GetAlgebraicType(registrar).Ref_, - PrimaryKey: [], - Indexes: - [ - new( - Name: null, - AccessorName: "TestIndexWithoutColumns", - Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([]) - ), - new( - Name: null, - AccessorName: "TestIndexWithEmptyColumns", - Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([]) - ), - new( - Name: null, - AccessorName: "TestUnknownColumns", - Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([]) - ), - new( - Name: null, - AccessorName: "TestUnexpectedColumns", - Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([0]) - ) - ], - Constraints: [], - Sequences: [], - Schedule: null, - TableType: SpacetimeDB.Internal.TableType.User, - TableAccess: SpacetimeDB.Internal.TableAccess.Private + >.DoInsert(row); + + public bool Delete(global::TestIndexIssues row) => + global::SpacetimeDB.Internal.ITableView< + TestIndexIssues, + global::TestIndexIssues + >.DoDelete(row); + + public sealed class TestIndexWithoutColumnsIndex() + : SpacetimeDB.Internal.IndexBase( + "TestIndexIssues__idx_btree" + ) { } + + public TestIndexWithoutColumnsIndex TestIndexWithoutColumns => new(); + + public sealed class TestIndexWithEmptyColumnsIndex() + : SpacetimeDB.Internal.IndexBase( + "TestIndexIssues__idx_btree" + ) { } + + public TestIndexWithEmptyColumnsIndex TestIndexWithEmptyColumns => new(); + + public sealed class TestUnknownColumnsIndex() + : SpacetimeDB.Internal.IndexBase( + "TestIndexIssues__idx_btree" + ) { } + + public TestUnknownColumnsIndex TestUnknownColumns => new(); + + public sealed class TestUnexpectedColumnsIndex() + : SpacetimeDB.Internal.IndexBase( + "TestIndexIssues_SelfIndexingColumn_idx_btree" + ) + { + public IEnumerable Filter(int SelfIndexingColumn) => + DoFilter( + new SpacetimeDB.Internal.BTreeIndexBounds( + SelfIndexingColumn + ) ); - public ulong Count => - global::SpacetimeDB.Internal.ITableView< - TestIndexIssues, - global::TestIndexIssues - >.DoCount(); - - public IEnumerable Iter() => - global::SpacetimeDB.Internal.ITableView< - TestIndexIssues, - global::TestIndexIssues - >.DoIter(); - - public global::TestIndexIssues Insert(global::TestIndexIssues row) => - global::SpacetimeDB.Internal.ITableView< - TestIndexIssues, - global::TestIndexIssues - >.DoInsert(row); - - public bool Delete(global::TestIndexIssues row) => - global::SpacetimeDB.Internal.ITableView< - TestIndexIssues, - global::TestIndexIssues - >.DoDelete(row); - - public sealed class TestIndexWithoutColumnsIndex() - : SpacetimeDB.Internal.IndexBase( - "TestIndexIssues__idx_btree" - ) { } - - public TestIndexWithoutColumnsIndex TestIndexWithoutColumns => new(); - - public sealed class TestIndexWithEmptyColumnsIndex() - : SpacetimeDB.Internal.IndexBase( - "TestIndexIssues__idx_btree" - ) { } - - public TestIndexWithEmptyColumnsIndex TestIndexWithEmptyColumns => new(); - - public sealed class TestUnknownColumnsIndex() - : SpacetimeDB.Internal.IndexBase( - "TestIndexIssues__idx_btree" - ) { } - - public TestUnknownColumnsIndex TestUnknownColumns => new(); - - public sealed class TestUnexpectedColumnsIndex() - : SpacetimeDB.Internal.IndexBase( - "TestIndexIssues_SelfIndexingColumn_idx_btree" - ) - { - public IEnumerable Filter(int SelfIndexingColumn) => - DoFilter( - new SpacetimeDB.Internal.BTreeIndexBounds( - SelfIndexingColumn - ) - ); - - public ulong Delete(int SelfIndexingColumn) => - DoDelete( - new SpacetimeDB.Internal.BTreeIndexBounds( - SelfIndexingColumn - ) - ); - - public IEnumerable Filter(Bound SelfIndexingColumn) => - DoFilter( - new SpacetimeDB.Internal.BTreeIndexBounds( - SelfIndexingColumn - ) - ); - - public ulong Delete(Bound SelfIndexingColumn) => - DoDelete( - new SpacetimeDB.Internal.BTreeIndexBounds( - SelfIndexingColumn - ) - ); - } + public ulong Delete(int SelfIndexingColumn) => + DoDelete( + new SpacetimeDB.Internal.BTreeIndexBounds( + SelfIndexingColumn + ) + ); - public TestUnexpectedColumnsIndex TestUnexpectedColumns => new(); + public IEnumerable Filter(Bound SelfIndexingColumn) => + DoFilter( + new SpacetimeDB.Internal.BTreeIndexBounds( + SelfIndexingColumn + ) + ); + + public ulong Delete(Bound SelfIndexingColumn) => + DoDelete( + new SpacetimeDB.Internal.BTreeIndexBounds( + SelfIndexingColumn + ) + ); } - public readonly struct TestScheduleWithMissingScheduleAtField - : global::SpacetimeDB.Internal.ITableView< - TestScheduleWithMissingScheduleAtField, - global::TestScheduleIssues - > + public TestUnexpectedColumnsIndex TestUnexpectedColumns => new(); + } + + public readonly struct TestScheduleWithMissingScheduleAtField + : global::SpacetimeDB.Internal.ITableView< + TestScheduleWithMissingScheduleAtField, + global::TestScheduleIssues + > + { + static global::TestScheduleIssues global::SpacetimeDB.Internal.ITableView< + TestScheduleWithMissingScheduleAtField, + global::TestScheduleIssues + >.ReadGenFields(System.IO.BinaryReader reader, global::TestScheduleIssues row) { - static global::TestScheduleIssues global::SpacetimeDB.Internal.ITableView< + return row; + } + + static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< + TestScheduleWithMissingScheduleAtField, + global::TestScheduleIssues + >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => + new( + Name: nameof(TestScheduleWithMissingScheduleAtField), + ProductTypeRef: (uint) + new global::TestScheduleIssues.BSATN().GetAlgebraicType(registrar).Ref_, + PrimaryKey: [], + Indexes: [], + Constraints: [], + Sequences: [], + Schedule: null, + TableType: SpacetimeDB.Internal.TableType.User, + TableAccess: SpacetimeDB.Internal.TableAccess.Private + ); + + public ulong Count => + global::SpacetimeDB.Internal.ITableView< TestScheduleWithMissingScheduleAtField, global::TestScheduleIssues - >.ReadGenFields(System.IO.BinaryReader reader, global::TestScheduleIssues row) - { - return row; - } + >.DoCount(); - static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< + public IEnumerable Iter() => + global::SpacetimeDB.Internal.ITableView< TestScheduleWithMissingScheduleAtField, global::TestScheduleIssues - >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => - new( - Name: nameof(TestScheduleWithMissingScheduleAtField), - ProductTypeRef: (uint) - new global::TestScheduleIssues.BSATN().GetAlgebraicType(registrar).Ref_, - PrimaryKey: [], - Indexes: [], - Constraints: [], - Sequences: [], - Schedule: null, - TableType: SpacetimeDB.Internal.TableType.User, - TableAccess: SpacetimeDB.Internal.TableAccess.Private - ); + >.DoIter(); - public ulong Count => - global::SpacetimeDB.Internal.ITableView< - TestScheduleWithMissingScheduleAtField, - global::TestScheduleIssues - >.DoCount(); + public global::TestScheduleIssues Insert(global::TestScheduleIssues row) => + global::SpacetimeDB.Internal.ITableView< + TestScheduleWithMissingScheduleAtField, + global::TestScheduleIssues + >.DoInsert(row); - public IEnumerable Iter() => - global::SpacetimeDB.Internal.ITableView< - TestScheduleWithMissingScheduleAtField, - global::TestScheduleIssues - >.DoIter(); + public bool Delete(global::TestScheduleIssues row) => + global::SpacetimeDB.Internal.ITableView< + TestScheduleWithMissingScheduleAtField, + global::TestScheduleIssues + >.DoDelete(row); + } - public global::TestScheduleIssues Insert(global::TestScheduleIssues row) => - global::SpacetimeDB.Internal.ITableView< - TestScheduleWithMissingScheduleAtField, - global::TestScheduleIssues - >.DoInsert(row); + public readonly struct TestScheduleWithoutPrimaryKey + : global::SpacetimeDB.Internal.ITableView< + TestScheduleWithoutPrimaryKey, + global::TestScheduleIssues + > + { + static global::TestScheduleIssues global::SpacetimeDB.Internal.ITableView< + TestScheduleWithoutPrimaryKey, + global::TestScheduleIssues + >.ReadGenFields(System.IO.BinaryReader reader, global::TestScheduleIssues row) + { + return row; + } - public bool Delete(global::TestScheduleIssues row) => - global::SpacetimeDB.Internal.ITableView< - TestScheduleWithMissingScheduleAtField, + static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< + TestScheduleWithoutPrimaryKey, + global::TestScheduleIssues + >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => + new( + Name: nameof(TestScheduleWithoutPrimaryKey), + ProductTypeRef: (uint) + new global::TestScheduleIssues.BSATN().GetAlgebraicType(registrar).Ref_, + PrimaryKey: [], + Indexes: [], + Constraints: [], + Sequences: [], + Schedule: global::SpacetimeDB.Internal.ITableView< + TestScheduleWithoutPrimaryKey, global::TestScheduleIssues - >.DoDelete(row); - } + >.MakeSchedule("DummyScheduledReducer", 3), + TableType: SpacetimeDB.Internal.TableType.User, + TableAccess: SpacetimeDB.Internal.TableAccess.Private + ); - public readonly struct TestScheduleWithoutPrimaryKey - : global::SpacetimeDB.Internal.ITableView< + public ulong Count => + global::SpacetimeDB.Internal.ITableView< TestScheduleWithoutPrimaryKey, global::TestScheduleIssues - > - { - static global::TestScheduleIssues global::SpacetimeDB.Internal.ITableView< + >.DoCount(); + + public IEnumerable Iter() => + global::SpacetimeDB.Internal.ITableView< TestScheduleWithoutPrimaryKey, global::TestScheduleIssues - >.ReadGenFields(System.IO.BinaryReader reader, global::TestScheduleIssues row) - { - return row; - } + >.DoIter(); - static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< + public global::TestScheduleIssues Insert(global::TestScheduleIssues row) => + global::SpacetimeDB.Internal.ITableView< TestScheduleWithoutPrimaryKey, global::TestScheduleIssues - >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => - new( - Name: nameof(TestScheduleWithoutPrimaryKey), - ProductTypeRef: (uint) - new global::TestScheduleIssues.BSATN().GetAlgebraicType(registrar).Ref_, - PrimaryKey: [], - Indexes: [], - Constraints: [], - Sequences: [], - Schedule: global::SpacetimeDB.Internal.ITableView< - TestScheduleWithoutPrimaryKey, - global::TestScheduleIssues - >.MakeSchedule("DummyScheduledReducer", 3), - TableType: SpacetimeDB.Internal.TableType.User, - TableAccess: SpacetimeDB.Internal.TableAccess.Private - ); - - public ulong Count => - global::SpacetimeDB.Internal.ITableView< - TestScheduleWithoutPrimaryKey, - global::TestScheduleIssues - >.DoCount(); - - public IEnumerable Iter() => - global::SpacetimeDB.Internal.ITableView< - TestScheduleWithoutPrimaryKey, - global::TestScheduleIssues - >.DoIter(); + >.DoInsert(row); - public global::TestScheduleIssues Insert(global::TestScheduleIssues row) => - global::SpacetimeDB.Internal.ITableView< - TestScheduleWithoutPrimaryKey, - global::TestScheduleIssues - >.DoInsert(row); + public bool Delete(global::TestScheduleIssues row) => + global::SpacetimeDB.Internal.ITableView< + TestScheduleWithoutPrimaryKey, + global::TestScheduleIssues + >.DoDelete(row); + } - public bool Delete(global::TestScheduleIssues row) => - global::SpacetimeDB.Internal.ITableView< - TestScheduleWithoutPrimaryKey, - global::TestScheduleIssues - >.DoDelete(row); + public readonly struct TestScheduleWithoutScheduleAt + : global::SpacetimeDB.Internal.ITableView< + TestScheduleWithoutScheduleAt, + global::TestScheduleIssues + > + { + static global::TestScheduleIssues global::SpacetimeDB.Internal.ITableView< + TestScheduleWithoutScheduleAt, + global::TestScheduleIssues + >.ReadGenFields(System.IO.BinaryReader reader, global::TestScheduleIssues row) + { + return row; } - public readonly struct TestScheduleWithoutScheduleAt - : global::SpacetimeDB.Internal.ITableView< + static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< + TestScheduleWithoutScheduleAt, + global::TestScheduleIssues + >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => + new( + Name: nameof(TestScheduleWithoutScheduleAt), + ProductTypeRef: (uint) + new global::TestScheduleIssues.BSATN().GetAlgebraicType(registrar).Ref_, + PrimaryKey: [1], + Indexes: + [ + new( + Name: null, + AccessorName: "IdCorrectType", + Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([1]) + ) + ], + Constraints: + [ + global::SpacetimeDB.Internal.ITableView< + TestScheduleWithoutScheduleAt, + global::TestScheduleIssues + >.MakeUniqueConstraint(1) + ], + Sequences: [], + Schedule: null, + TableType: SpacetimeDB.Internal.TableType.User, + TableAccess: SpacetimeDB.Internal.TableAccess.Private + ); + + public ulong Count => + global::SpacetimeDB.Internal.ITableView< TestScheduleWithoutScheduleAt, global::TestScheduleIssues - > - { - static global::TestScheduleIssues global::SpacetimeDB.Internal.ITableView< + >.DoCount(); + + public IEnumerable Iter() => + global::SpacetimeDB.Internal.ITableView< TestScheduleWithoutScheduleAt, global::TestScheduleIssues - >.ReadGenFields(System.IO.BinaryReader reader, global::TestScheduleIssues row) - { - return row; - } + >.DoIter(); - static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< + public global::TestScheduleIssues Insert(global::TestScheduleIssues row) => + global::SpacetimeDB.Internal.ITableView< TestScheduleWithoutScheduleAt, global::TestScheduleIssues - >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => - new( - Name: nameof(TestScheduleWithoutScheduleAt), - ProductTypeRef: (uint) - new global::TestScheduleIssues.BSATN().GetAlgebraicType(registrar).Ref_, - PrimaryKey: [1], - Indexes: - [ - new( - Name: null, - AccessorName: "IdCorrectType", - Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([1]) - ) - ], - Constraints: - [ - global::SpacetimeDB.Internal.ITableView< - TestScheduleWithoutScheduleAt, - global::TestScheduleIssues - >.MakeUniqueConstraint(1) - ], - Sequences: [], - Schedule: null, - TableType: SpacetimeDB.Internal.TableType.User, - TableAccess: SpacetimeDB.Internal.TableAccess.Private - ); - - public ulong Count => - global::SpacetimeDB.Internal.ITableView< - TestScheduleWithoutScheduleAt, - global::TestScheduleIssues - >.DoCount(); + >.DoInsert(row); - public IEnumerable Iter() => - global::SpacetimeDB.Internal.ITableView< - TestScheduleWithoutScheduleAt, - global::TestScheduleIssues - >.DoIter(); + public bool Delete(global::TestScheduleIssues row) => + global::SpacetimeDB.Internal.ITableView< + TestScheduleWithoutScheduleAt, + global::TestScheduleIssues + >.DoDelete(row); - public global::TestScheduleIssues Insert(global::TestScheduleIssues row) => - global::SpacetimeDB.Internal.ITableView< - TestScheduleWithoutScheduleAt, - global::TestScheduleIssues - >.DoInsert(row); + public sealed class IdCorrectTypeUniqueIndex + : UniqueIndex< + TestScheduleWithoutScheduleAt, + global::TestScheduleIssues, + int, + SpacetimeDB.BSATN.I32 + > + { + internal IdCorrectTypeUniqueIndex() + : base("TestScheduleWithoutScheduleAt_IdCorrectType_idx_btree") { } - public bool Delete(global::TestScheduleIssues row) => - global::SpacetimeDB.Internal.ITableView< - TestScheduleWithoutScheduleAt, - global::TestScheduleIssues - >.DoDelete(row); - - public sealed class IdCorrectTypeUniqueIndex - : UniqueIndex< - TestScheduleWithoutScheduleAt, - global::TestScheduleIssues, - int, - SpacetimeDB.BSATN.I32 - > - { - internal IdCorrectTypeUniqueIndex() - : base("TestScheduleWithoutScheduleAt_IdCorrectType_idx_btree") { } + // Important: don't move this to the base class. + // C# generics don't play well with nullable types and can't accept both struct-type-based and class-type-based + // `globalName` in one generic definition, leading to buggy `Row?` expansion for either one or another. + public global::TestScheduleIssues? Find(int key) => + DoFilter(key).Cast().SingleOrDefault(); - // Important: don't move this to the base class. - // C# generics don't play well with nullable types and can't accept both struct-type-based and class-type-based - // `globalName` in one generic definition, leading to buggy `Row?` expansion for either one or another. - public global::TestScheduleIssues? Find(int key) => - DoFilter(key).Cast().SingleOrDefault(); + public global::TestScheduleIssues Update(global::TestScheduleIssues row) => + DoUpdate(row); + } - public global::TestScheduleIssues Update(global::TestScheduleIssues row) => - DoUpdate(row); - } + public IdCorrectTypeUniqueIndex IdCorrectType => new(); + } - public IdCorrectTypeUniqueIndex IdCorrectType => new(); + public readonly struct TestScheduleWithWrongPrimaryKeyType + : global::SpacetimeDB.Internal.ITableView< + TestScheduleWithWrongPrimaryKeyType, + global::TestScheduleIssues + > + { + static global::TestScheduleIssues global::SpacetimeDB.Internal.ITableView< + TestScheduleWithWrongPrimaryKeyType, + global::TestScheduleIssues + >.ReadGenFields(System.IO.BinaryReader reader, global::TestScheduleIssues row) + { + return row; } - public readonly struct TestScheduleWithWrongPrimaryKeyType - : global::SpacetimeDB.Internal.ITableView< + static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< + TestScheduleWithWrongPrimaryKeyType, + global::TestScheduleIssues + >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => + new( + Name: nameof(TestScheduleWithWrongPrimaryKeyType), + ProductTypeRef: (uint) + new global::TestScheduleIssues.BSATN().GetAlgebraicType(registrar).Ref_, + PrimaryKey: [0], + Indexes: + [ + new( + Name: null, + AccessorName: "IdWrongType", + Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([0]) + ) + ], + Constraints: + [ + global::SpacetimeDB.Internal.ITableView< + TestScheduleWithWrongPrimaryKeyType, + global::TestScheduleIssues + >.MakeUniqueConstraint(0) + ], + Sequences: [], + Schedule: global::SpacetimeDB.Internal.ITableView< + TestScheduleWithWrongPrimaryKeyType, + global::TestScheduleIssues + >.MakeSchedule("DummyScheduledReducer", 3), + TableType: SpacetimeDB.Internal.TableType.User, + TableAccess: SpacetimeDB.Internal.TableAccess.Private + ); + + public ulong Count => + global::SpacetimeDB.Internal.ITableView< TestScheduleWithWrongPrimaryKeyType, global::TestScheduleIssues - > - { - static global::TestScheduleIssues global::SpacetimeDB.Internal.ITableView< + >.DoCount(); + + public IEnumerable Iter() => + global::SpacetimeDB.Internal.ITableView< TestScheduleWithWrongPrimaryKeyType, global::TestScheduleIssues - >.ReadGenFields(System.IO.BinaryReader reader, global::TestScheduleIssues row) - { - return row; - } + >.DoIter(); - static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< + public global::TestScheduleIssues Insert(global::TestScheduleIssues row) => + global::SpacetimeDB.Internal.ITableView< TestScheduleWithWrongPrimaryKeyType, global::TestScheduleIssues - >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => - new( - Name: nameof(TestScheduleWithWrongPrimaryKeyType), - ProductTypeRef: (uint) - new global::TestScheduleIssues.BSATN().GetAlgebraicType(registrar).Ref_, - PrimaryKey: [0], - Indexes: - [ - new( - Name: null, - AccessorName: "IdWrongType", - Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([0]) - ) - ], - Constraints: - [ - global::SpacetimeDB.Internal.ITableView< - TestScheduleWithWrongPrimaryKeyType, - global::TestScheduleIssues - >.MakeUniqueConstraint(0) - ], - Sequences: [], - Schedule: global::SpacetimeDB.Internal.ITableView< - TestScheduleWithWrongPrimaryKeyType, - global::TestScheduleIssues - >.MakeSchedule("DummyScheduledReducer", 3), - TableType: SpacetimeDB.Internal.TableType.User, - TableAccess: SpacetimeDB.Internal.TableAccess.Private - ); + >.DoInsert(row); - public ulong Count => - global::SpacetimeDB.Internal.ITableView< - TestScheduleWithWrongPrimaryKeyType, - global::TestScheduleIssues - >.DoCount(); - - public IEnumerable Iter() => - global::SpacetimeDB.Internal.ITableView< - TestScheduleWithWrongPrimaryKeyType, - global::TestScheduleIssues - >.DoIter(); - - public global::TestScheduleIssues Insert(global::TestScheduleIssues row) => - global::SpacetimeDB.Internal.ITableView< - TestScheduleWithWrongPrimaryKeyType, - global::TestScheduleIssues - >.DoInsert(row); + public bool Delete(global::TestScheduleIssues row) => + global::SpacetimeDB.Internal.ITableView< + TestScheduleWithWrongPrimaryKeyType, + global::TestScheduleIssues + >.DoDelete(row); - public bool Delete(global::TestScheduleIssues row) => - global::SpacetimeDB.Internal.ITableView< - TestScheduleWithWrongPrimaryKeyType, - global::TestScheduleIssues - >.DoDelete(row); + public sealed class IdWrongTypeUniqueIndex + : UniqueIndex< + TestScheduleWithWrongPrimaryKeyType, + global::TestScheduleIssues, + string, + SpacetimeDB.BSATN.String + > + { + internal IdWrongTypeUniqueIndex() + : base("TestScheduleWithWrongPrimaryKeyType_IdWrongType_idx_btree") { } - public sealed class IdWrongTypeUniqueIndex - : UniqueIndex< - TestScheduleWithWrongPrimaryKeyType, - global::TestScheduleIssues, - string, - SpacetimeDB.BSATN.String - > - { - internal IdWrongTypeUniqueIndex() - : base("TestScheduleWithWrongPrimaryKeyType_IdWrongType_idx_btree") { } + // Important: don't move this to the base class. + // C# generics don't play well with nullable types and can't accept both struct-type-based and class-type-based + // `globalName` in one generic definition, leading to buggy `Row?` expansion for either one or another. + public global::TestScheduleIssues? Find(string key) => + DoFilter(key).Cast().SingleOrDefault(); - // Important: don't move this to the base class. - // C# generics don't play well with nullable types and can't accept both struct-type-based and class-type-based - // `globalName` in one generic definition, leading to buggy `Row?` expansion for either one or another. - public global::TestScheduleIssues? Find(string key) => - DoFilter(key).Cast().SingleOrDefault(); + public global::TestScheduleIssues Update(global::TestScheduleIssues row) => + DoUpdate(row); + } - public global::TestScheduleIssues Update(global::TestScheduleIssues row) => - DoUpdate(row); - } + public IdWrongTypeUniqueIndex IdWrongType => new(); + } - public IdWrongTypeUniqueIndex IdWrongType => new(); + public readonly struct TestScheduleWithWrongScheduleAtType + : global::SpacetimeDB.Internal.ITableView< + TestScheduleWithWrongScheduleAtType, + global::TestScheduleIssues + > + { + static global::TestScheduleIssues global::SpacetimeDB.Internal.ITableView< + TestScheduleWithWrongScheduleAtType, + global::TestScheduleIssues + >.ReadGenFields(System.IO.BinaryReader reader, global::TestScheduleIssues row) + { + return row; } - public readonly struct TestScheduleWithWrongScheduleAtType - : global::SpacetimeDB.Internal.ITableView< + static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< + TestScheduleWithWrongScheduleAtType, + global::TestScheduleIssues + >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => + new( + Name: nameof(TestScheduleWithWrongScheduleAtType), + ProductTypeRef: (uint) + new global::TestScheduleIssues.BSATN().GetAlgebraicType(registrar).Ref_, + PrimaryKey: [1], + Indexes: + [ + new( + Name: null, + AccessorName: "IdCorrectType", + Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([1]) + ) + ], + Constraints: + [ + global::SpacetimeDB.Internal.ITableView< + TestScheduleWithWrongScheduleAtType, + global::TestScheduleIssues + >.MakeUniqueConstraint(1) + ], + Sequences: [], + Schedule: global::SpacetimeDB.Internal.ITableView< + TestScheduleWithWrongScheduleAtType, + global::TestScheduleIssues + >.MakeSchedule("DummyScheduledReducer", 2), + TableType: SpacetimeDB.Internal.TableType.User, + TableAccess: SpacetimeDB.Internal.TableAccess.Private + ); + + public ulong Count => + global::SpacetimeDB.Internal.ITableView< TestScheduleWithWrongScheduleAtType, global::TestScheduleIssues - > - { - static global::TestScheduleIssues global::SpacetimeDB.Internal.ITableView< + >.DoCount(); + + public IEnumerable Iter() => + global::SpacetimeDB.Internal.ITableView< TestScheduleWithWrongScheduleAtType, global::TestScheduleIssues - >.ReadGenFields(System.IO.BinaryReader reader, global::TestScheduleIssues row) - { - return row; - } + >.DoIter(); - static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< + public global::TestScheduleIssues Insert(global::TestScheduleIssues row) => + global::SpacetimeDB.Internal.ITableView< TestScheduleWithWrongScheduleAtType, global::TestScheduleIssues - >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => - new( - Name: nameof(TestScheduleWithWrongScheduleAtType), - ProductTypeRef: (uint) - new global::TestScheduleIssues.BSATN().GetAlgebraicType(registrar).Ref_, - PrimaryKey: [1], - Indexes: - [ - new( - Name: null, - AccessorName: "IdCorrectType", - Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([1]) - ) - ], - Constraints: - [ - global::SpacetimeDB.Internal.ITableView< - TestScheduleWithWrongScheduleAtType, - global::TestScheduleIssues - >.MakeUniqueConstraint(1) - ], - Sequences: [], - Schedule: global::SpacetimeDB.Internal.ITableView< - TestScheduleWithWrongScheduleAtType, - global::TestScheduleIssues - >.MakeSchedule("DummyScheduledReducer", 2), - TableType: SpacetimeDB.Internal.TableType.User, - TableAccess: SpacetimeDB.Internal.TableAccess.Private - ); - - public ulong Count => - global::SpacetimeDB.Internal.ITableView< - TestScheduleWithWrongScheduleAtType, - global::TestScheduleIssues - >.DoCount(); + >.DoInsert(row); - public IEnumerable Iter() => - global::SpacetimeDB.Internal.ITableView< - TestScheduleWithWrongScheduleAtType, - global::TestScheduleIssues - >.DoIter(); - - public global::TestScheduleIssues Insert(global::TestScheduleIssues row) => - global::SpacetimeDB.Internal.ITableView< - TestScheduleWithWrongScheduleAtType, - global::TestScheduleIssues - >.DoInsert(row); + public bool Delete(global::TestScheduleIssues row) => + global::SpacetimeDB.Internal.ITableView< + TestScheduleWithWrongScheduleAtType, + global::TestScheduleIssues + >.DoDelete(row); - public bool Delete(global::TestScheduleIssues row) => - global::SpacetimeDB.Internal.ITableView< - TestScheduleWithWrongScheduleAtType, - global::TestScheduleIssues - >.DoDelete(row); + public sealed class IdCorrectTypeUniqueIndex + : UniqueIndex< + TestScheduleWithWrongScheduleAtType, + global::TestScheduleIssues, + int, + SpacetimeDB.BSATN.I32 + > + { + internal IdCorrectTypeUniqueIndex() + : base("TestScheduleWithWrongScheduleAtType_IdCorrectType_idx_btree") { } - public sealed class IdCorrectTypeUniqueIndex - : UniqueIndex< - TestScheduleWithWrongScheduleAtType, - global::TestScheduleIssues, - int, - SpacetimeDB.BSATN.I32 - > - { - internal IdCorrectTypeUniqueIndex() - : base("TestScheduleWithWrongScheduleAtType_IdCorrectType_idx_btree") { } + // Important: don't move this to the base class. + // C# generics don't play well with nullable types and can't accept both struct-type-based and class-type-based + // `globalName` in one generic definition, leading to buggy `Row?` expansion for either one or another. + public global::TestScheduleIssues? Find(int key) => + DoFilter(key).Cast().SingleOrDefault(); - // Important: don't move this to the base class. - // C# generics don't play well with nullable types and can't accept both struct-type-based and class-type-based - // `globalName` in one generic definition, leading to buggy `Row?` expansion for either one or another. - public global::TestScheduleIssues? Find(int key) => - DoFilter(key).Cast().SingleOrDefault(); + public global::TestScheduleIssues Update(global::TestScheduleIssues row) => + DoUpdate(row); + } - public global::TestScheduleIssues Update(global::TestScheduleIssues row) => - DoUpdate(row); - } + public IdCorrectTypeUniqueIndex IdCorrectType => new(); + } - public IdCorrectTypeUniqueIndex IdCorrectType => new(); + public readonly struct TestUniqueNotEquatable + : global::SpacetimeDB.Internal.ITableView< + TestUniqueNotEquatable, + global::TestUniqueNotEquatable + > + { + static global::TestUniqueNotEquatable global::SpacetimeDB.Internal.ITableView< + TestUniqueNotEquatable, + global::TestUniqueNotEquatable + >.ReadGenFields(System.IO.BinaryReader reader, global::TestUniqueNotEquatable row) + { + return row; } - public readonly struct TestUniqueNotEquatable - : global::SpacetimeDB.Internal.ITableView< + static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< + TestUniqueNotEquatable, + global::TestUniqueNotEquatable + >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => + new( + Name: nameof(TestUniqueNotEquatable), + ProductTypeRef: (uint) + new global::TestUniqueNotEquatable.BSATN().GetAlgebraicType(registrar).Ref_, + PrimaryKey: [1], + Indexes: + [ + new( + Name: null, + AccessorName: "UniqueField", + Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([0]) + ), + new( + Name: null, + AccessorName: "PrimaryKeyField", + Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([1]) + ) + ], + Constraints: + [ + global::SpacetimeDB.Internal.ITableView< + TestUniqueNotEquatable, + global::TestUniqueNotEquatable + >.MakeUniqueConstraint(0), + global::SpacetimeDB.Internal.ITableView< + TestUniqueNotEquatable, + global::TestUniqueNotEquatable + >.MakeUniqueConstraint(1) + ], + Sequences: [], + Schedule: null, + TableType: SpacetimeDB.Internal.TableType.User, + TableAccess: SpacetimeDB.Internal.TableAccess.Private + ); + + public ulong Count => + global::SpacetimeDB.Internal.ITableView< TestUniqueNotEquatable, global::TestUniqueNotEquatable - > - { - static global::TestUniqueNotEquatable global::SpacetimeDB.Internal.ITableView< + >.DoCount(); + + public IEnumerable Iter() => + global::SpacetimeDB.Internal.ITableView< TestUniqueNotEquatable, global::TestUniqueNotEquatable - >.ReadGenFields(System.IO.BinaryReader reader, global::TestUniqueNotEquatable row) - { - return row; - } + >.DoIter(); - static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< + public global::TestUniqueNotEquatable Insert(global::TestUniqueNotEquatable row) => + global::SpacetimeDB.Internal.ITableView< TestUniqueNotEquatable, global::TestUniqueNotEquatable - >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => - new( - Name: nameof(TestUniqueNotEquatable), - ProductTypeRef: (uint) - new global::TestUniqueNotEquatable.BSATN().GetAlgebraicType(registrar).Ref_, - PrimaryKey: [1], - Indexes: - [ - new( - Name: null, - AccessorName: "UniqueField", - Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([0]) - ), - new( - Name: null, - AccessorName: "PrimaryKeyField", - Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([1]) - ) - ], - Constraints: - [ - global::SpacetimeDB.Internal.ITableView< - TestUniqueNotEquatable, - global::TestUniqueNotEquatable - >.MakeUniqueConstraint(0), - global::SpacetimeDB.Internal.ITableView< - TestUniqueNotEquatable, - global::TestUniqueNotEquatable - >.MakeUniqueConstraint(1) - ], - Sequences: [], - Schedule: null, - TableType: SpacetimeDB.Internal.TableType.User, - TableAccess: SpacetimeDB.Internal.TableAccess.Private - ); + >.DoInsert(row); - public ulong Count => - global::SpacetimeDB.Internal.ITableView< - TestUniqueNotEquatable, - global::TestUniqueNotEquatable - >.DoCount(); - - public IEnumerable Iter() => - global::SpacetimeDB.Internal.ITableView< - TestUniqueNotEquatable, - global::TestUniqueNotEquatable - >.DoIter(); - - public global::TestUniqueNotEquatable Insert(global::TestUniqueNotEquatable row) => - global::SpacetimeDB.Internal.ITableView< - TestUniqueNotEquatable, - global::TestUniqueNotEquatable - >.DoInsert(row); - - public bool Delete(global::TestUniqueNotEquatable row) => - global::SpacetimeDB.Internal.ITableView< - TestUniqueNotEquatable, - global::TestUniqueNotEquatable - >.DoDelete(row); - - public sealed class PrimaryKeyFieldUniqueIndex - : UniqueIndex< - TestUniqueNotEquatable, - global::TestUniqueNotEquatable, - TestEnumWithExplicitValues, - SpacetimeDB.BSATN.Enum - > - { - internal PrimaryKeyFieldUniqueIndex() - : base("TestUniqueNotEquatable_PrimaryKeyField_idx_btree") { } + public bool Delete(global::TestUniqueNotEquatable row) => + global::SpacetimeDB.Internal.ITableView< + TestUniqueNotEquatable, + global::TestUniqueNotEquatable + >.DoDelete(row); - // Important: don't move this to the base class. - // C# generics don't play well with nullable types and can't accept both struct-type-based and class-type-based - // `globalName` in one generic definition, leading to buggy `Row?` expansion for either one or another. - public global::TestUniqueNotEquatable? Find(TestEnumWithExplicitValues key) => - DoFilter(key).Cast().SingleOrDefault(); + public sealed class PrimaryKeyFieldUniqueIndex + : UniqueIndex< + TestUniqueNotEquatable, + global::TestUniqueNotEquatable, + TestEnumWithExplicitValues, + SpacetimeDB.BSATN.Enum + > + { + internal PrimaryKeyFieldUniqueIndex() + : base("TestUniqueNotEquatable_PrimaryKeyField_idx_btree") { } - public global::TestUniqueNotEquatable Update(global::TestUniqueNotEquatable row) => - DoUpdate(row); - } + // Important: don't move this to the base class. + // C# generics don't play well with nullable types and can't accept both struct-type-based and class-type-based + // `globalName` in one generic definition, leading to buggy `Row?` expansion for either one or another. + public global::TestUniqueNotEquatable? Find(TestEnumWithExplicitValues key) => + DoFilter(key).Cast().SingleOrDefault(); - public PrimaryKeyFieldUniqueIndex PrimaryKeyField => new(); + public global::TestUniqueNotEquatable Update(global::TestUniqueNotEquatable row) => + DoUpdate(row); } - } - public sealed class Local - { - public global::SpacetimeDB.Internal.TableHandles.Player Player => new(); - public global::SpacetimeDB.Internal.TableHandles.TestAutoIncNotInteger TestAutoIncNotInteger => - new(); - public global::SpacetimeDB.Internal.TableHandles.TestDefaultFieldValues TestDefaultFieldValues => - new(); - public global::SpacetimeDB.Internal.TableHandles.TestDuplicateTableName TestDuplicateTableName => - new(); - public global::SpacetimeDB.Internal.TableHandles.TestIndexIssues TestIndexIssues => new(); - public global::SpacetimeDB.Internal.TableHandles.TestScheduleWithMissingScheduleAtField TestScheduleWithMissingScheduleAtField => - new(); - public global::SpacetimeDB.Internal.TableHandles.TestScheduleWithoutPrimaryKey TestScheduleWithoutPrimaryKey => - new(); - public global::SpacetimeDB.Internal.TableHandles.TestScheduleWithoutScheduleAt TestScheduleWithoutScheduleAt => - new(); - public global::SpacetimeDB.Internal.TableHandles.TestScheduleWithWrongPrimaryKeyType TestScheduleWithWrongPrimaryKeyType => - new(); - public global::SpacetimeDB.Internal.TableHandles.TestScheduleWithWrongScheduleAtType TestScheduleWithWrongScheduleAtType => - new(); - public global::SpacetimeDB.Internal.TableHandles.TestUniqueNotEquatable TestUniqueNotEquatable => - new(); + public PrimaryKeyFieldUniqueIndex PrimaryKeyField => new(); } } @@ -1715,34 +1749,6 @@ internal PrimaryKeyFieldIndex() } } -namespace SpacetimeDB.Internal -{ - public sealed partial class LocalReadOnly - { - public global::SpacetimeDB.Internal.ViewHandles.PlayerReadOnly Player => new(); - public global::SpacetimeDB.Internal.ViewHandles.TestAutoIncNotIntegerReadOnly TestAutoIncNotInteger => - new(); - public global::SpacetimeDB.Internal.ViewHandles.TestDefaultFieldValuesReadOnly TestDefaultFieldValues => - new(); - public global::SpacetimeDB.Internal.ViewHandles.TestDuplicateTableNameReadOnly TestDuplicateTableName => - new(); - public global::SpacetimeDB.Internal.ViewHandles.TestIndexIssuesReadOnly TestIndexIssues => - new(); - public global::SpacetimeDB.Internal.ViewHandles.TestScheduleWithMissingScheduleAtFieldReadOnly TestScheduleWithMissingScheduleAtField => - new(); - public global::SpacetimeDB.Internal.ViewHandles.TestScheduleWithoutPrimaryKeyReadOnly TestScheduleWithoutPrimaryKey => - new(); - public global::SpacetimeDB.Internal.ViewHandles.TestScheduleWithoutScheduleAtReadOnly TestScheduleWithoutScheduleAt => - new(); - public global::SpacetimeDB.Internal.ViewHandles.TestScheduleWithWrongPrimaryKeyTypeReadOnly TestScheduleWithWrongPrimaryKeyType => - new(); - public global::SpacetimeDB.Internal.ViewHandles.TestScheduleWithWrongScheduleAtTypeReadOnly TestScheduleWithWrongScheduleAtType => - new(); - public global::SpacetimeDB.Internal.ViewHandles.TestUniqueNotEquatableReadOnly TestUniqueNotEquatable => - new(); - } -} - static class ModuleRegistration { class __ReducerWithReservedPrefix : SpacetimeDB.Internal.IReducer @@ -1872,13 +1878,10 @@ public static void Main() new SpacetimeDB.ReducerContext(identity, connectionId, random, time) ); SpacetimeDB.Internal.Module.SetViewContextConstructor( - identity => new SpacetimeDB.ViewContext( - identity, - new SpacetimeDB.Internal.LocalReadOnly() - ) + identity => new SpacetimeDB.ViewContext(identity, new SpacetimeDB.LocalReadOnly()) ); SpacetimeDB.Internal.Module.SetAnonymousViewContextConstructor( - () => new SpacetimeDB.AnonymousViewContext(new SpacetimeDB.Internal.LocalReadOnly()) + () => new SpacetimeDB.AnonymousViewContext(new SpacetimeDB.LocalReadOnly()) ); SpacetimeDB.Internal.Module.SetProcedureContextConstructor( (identity, connectionId, random, time) => @@ -2225,6 +2228,10 @@ SpacetimeDB.Internal.BytesSink result_sink result_sink ); + [UnmanagedCallersOnly(EntryPoint = "__take_procedure_tx_offset__")] + public static byte __take_procedure_tx_offset__(ulong* offset) => + SpacetimeDB.Internal.Module.__take_procedure_tx_offset__(out *offset) ? (byte)1 : (byte)0; + [UnmanagedCallersOnly(EntryPoint = "__call_view__")] public static SpacetimeDB.Internal.Errno __call_view__( uint id, @@ -2254,4 +2261,5 @@ SpacetimeDB.Internal.BytesSink sink #endif } +#pragma warning restore STDB_UNSTABLE #pragma warning restore CS0436 diff --git a/crates/bindings-csharp/Codegen.Tests/fixtures/server/server.csproj b/crates/bindings-csharp/Codegen.Tests/fixtures/server/server.csproj index 426f04d2bc6..66830dc463c 100644 --- a/crates/bindings-csharp/Codegen.Tests/fixtures/server/server.csproj +++ b/crates/bindings-csharp/Codegen.Tests/fixtures/server/server.csproj @@ -1,5 +1,4 @@  - net8.0 enable @@ -9,5 +8,4 @@ - diff --git a/crates/bindings-csharp/Codegen.Tests/fixtures/server/snapshots/Module#FFI.verified.cs b/crates/bindings-csharp/Codegen.Tests/fixtures/server/snapshots/Module#FFI.verified.cs index c69d4a151d3..0668b3d1281 100644 --- a/crates/bindings-csharp/Codegen.Tests/fixtures/server/snapshots/Module#FFI.verified.cs +++ b/crates/bindings-csharp/Codegen.Tests/fixtures/server/snapshots/Module#FFI.verified.cs @@ -5,10 +5,13 @@ // This is needed so every module build doesn't generate a full LocalReadOnly type, but just adds on to the existing. // We extend it here with generated table accessors, and just need to suppress the duplicate-type warning. #pragma warning disable CS0436 +#pragma warning disable STDB_UNSTABLE using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using Internal = SpacetimeDB.Internal; +using TxContext = SpacetimeDB.Internal.TxContext; namespace SpacetimeDB { @@ -27,27 +30,21 @@ internal ReducerContext( Identity identity, ConnectionId? connectionId, Random random, - Timestamp time + Timestamp time, + AuthCtx? senderAuth = null ) { Sender = identity; ConnectionId = connectionId; Rng = random; Timestamp = time; - SenderAuth = AuthCtx.BuildFromSystemTables(connectionId, identity); + SenderAuth = senderAuth ?? AuthCtx.BuildFromSystemTables(connectionId, identity); } } - public sealed record ProcedureContext : Internal.IProcedureContext + public sealed class ProcedureContext : global::SpacetimeDB.ProcedureContextBase { - public readonly Identity Sender; - public readonly ConnectionId? ConnectionId; - public readonly Random Rng; - public readonly Timestamp Timestamp; - public readonly AuthCtx SenderAuth; - - // We need this property to be non-static for parity with client SDK. - public Identity Identity => Internal.IProcedureContext.GetIdentity(); + private readonly Local _db = new(); internal ProcedureContext( Identity identity, @@ -55,1029 +52,1007 @@ internal ProcedureContext( Random random, Timestamp time ) - { - Sender = identity; - ConnectionId = connectionId; - Rng = random; - Timestamp = time; - SenderAuth = AuthCtx.BuildFromSystemTables(connectionId, identity); - } + : base(identity, connectionId, random, time) { } + + protected override global::SpacetimeDB.LocalBase CreateLocal() => _db; + + protected override global::SpacetimeDB.ProcedureTxContextBase CreateTxContext( + Internal.TxContext inner + ) => _cached ??= new ProcedureTxContext(inner); + + private ProcedureTxContext? _cached; + + [Experimental("STDB_UNSTABLE")] + public Local Db => _db; + + [Experimental("STDB_UNSTABLE")] + public TResult WithTx(Func body) => + base.WithTx(tx => body((ProcedureTxContext)tx)); + + [Experimental("STDB_UNSTABLE")] + public TxOutcome TryWithTx( + Func> body + ) + where TError : Exception => base.TryWithTx(tx => body((ProcedureTxContext)tx)); + } + + [Experimental("STDB_UNSTABLE")] + public sealed class ProcedureTxContext : global::SpacetimeDB.ProcedureTxContextBase + { + internal ProcedureTxContext(Internal.TxContext inner) + : base(inner) { } + + public new Local Db => (Local)base.Db; + } + + public sealed class Local : global::SpacetimeDB.LocalBase + { + internal global::SpacetimeDB.Internal.TableHandles.BTreeMultiColumn BTreeMultiColumn => + new(); + internal global::SpacetimeDB.Internal.TableHandles.BTreeViews BTreeViews => new(); + public global::SpacetimeDB.Internal.TableHandles.MultiTable1 MultiTable1 => new(); + public global::SpacetimeDB.Internal.TableHandles.MultiTable2 MultiTable2 => new(); + public global::SpacetimeDB.Internal.TableHandles.PrivateTable PrivateTable => new(); + public global::SpacetimeDB.Internal.TableHandles.PublicTable PublicTable => new(); + internal global::SpacetimeDB.Internal.TableHandles.RegressionMultipleUniqueIndexesHadSameName RegressionMultipleUniqueIndexesHadSameName => + new(); + public global::SpacetimeDB.Internal.TableHandles.SendMessageTimer SendMessageTimer => new(); } - public sealed record ViewContext : DbContext, Internal.IViewContext + public sealed class LocalReadOnly : global::SpacetimeDB.LocalReadOnlyBase + { + internal global::SpacetimeDB.Internal.ViewHandles.BTreeMultiColumnReadOnly BTreeMultiColumn => + new(); + internal global::SpacetimeDB.Internal.ViewHandles.BTreeViewsReadOnly BTreeViews => new(); + public global::SpacetimeDB.Internal.ViewHandles.MultiTable1ReadOnly MultiTable1 => new(); + public global::SpacetimeDB.Internal.ViewHandles.MultiTable2ReadOnly MultiTable2 => new(); + public global::SpacetimeDB.Internal.ViewHandles.PrivateTableReadOnly PrivateTable => new(); + public global::SpacetimeDB.Internal.ViewHandles.PublicTableReadOnly PublicTable => new(); + internal global::SpacetimeDB.Internal.ViewHandles.RegressionMultipleUniqueIndexesHadSameNameReadOnly RegressionMultipleUniqueIndexesHadSameName => + new(); + public global::SpacetimeDB.Internal.ViewHandles.SendMessageTimerReadOnly SendMessageTimer => + new(); + } + + public sealed record ViewContext : DbContext, Internal.IViewContext { public Identity Sender { get; } - internal ViewContext(Identity sender, Internal.LocalReadOnly db) - : base(db) - { - Sender = sender; - } + internal ViewContext(Identity sender, LocalReadOnly db) + : base(db) => Sender = sender; } public sealed record AnonymousViewContext - : DbContext, + : DbContext, Internal.IAnonymousViewContext { - internal AnonymousViewContext(Internal.LocalReadOnly db) + internal AnonymousViewContext(LocalReadOnly db) : base(db) { } } +} - namespace Internal.TableHandles +namespace SpacetimeDB.Internal.TableHandles +{ + internal readonly struct BTreeMultiColumn + : global::SpacetimeDB.Internal.ITableView { - internal readonly struct BTreeMultiColumn - : global::SpacetimeDB.Internal.ITableView + static global::BTreeMultiColumn global::SpacetimeDB.Internal.ITableView< + BTreeMultiColumn, + global::BTreeMultiColumn + >.ReadGenFields(System.IO.BinaryReader reader, global::BTreeMultiColumn row) { - static global::BTreeMultiColumn global::SpacetimeDB.Internal.ITableView< + return row; + } + + static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< + BTreeMultiColumn, + global::BTreeMultiColumn + >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => + new( + Name: nameof(BTreeMultiColumn), + ProductTypeRef: (uint) + new global::BTreeMultiColumn.BSATN().GetAlgebraicType(registrar).Ref_, + PrimaryKey: [], + Indexes: + [ + new( + Name: null, + AccessorName: "Location", + Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([0, 1, 2]) + ) + ], + Constraints: [], + Sequences: [], + Schedule: null, + TableType: SpacetimeDB.Internal.TableType.User, + TableAccess: SpacetimeDB.Internal.TableAccess.Private + ); + + public ulong Count => + global::SpacetimeDB.Internal.ITableView< BTreeMultiColumn, global::BTreeMultiColumn - >.ReadGenFields(System.IO.BinaryReader reader, global::BTreeMultiColumn row) - { - return row; - } + >.DoCount(); - static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< + public IEnumerable Iter() => + global::SpacetimeDB.Internal.ITableView< BTreeMultiColumn, global::BTreeMultiColumn - >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => - new( - Name: nameof(BTreeMultiColumn), - ProductTypeRef: (uint) - new global::BTreeMultiColumn.BSATN().GetAlgebraicType(registrar).Ref_, - PrimaryKey: [], - Indexes: - [ - new( - Name: null, - AccessorName: "Location", - Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([0, 1, 2]) - ) - ], - Constraints: [], - Sequences: [], - Schedule: null, - TableType: SpacetimeDB.Internal.TableType.User, - TableAccess: SpacetimeDB.Internal.TableAccess.Private - ); + >.DoIter(); - public ulong Count => - global::SpacetimeDB.Internal.ITableView< - BTreeMultiColumn, - global::BTreeMultiColumn - >.DoCount(); - - public IEnumerable Iter() => - global::SpacetimeDB.Internal.ITableView< - BTreeMultiColumn, - global::BTreeMultiColumn - >.DoIter(); - - public global::BTreeMultiColumn Insert(global::BTreeMultiColumn row) => - global::SpacetimeDB.Internal.ITableView< - BTreeMultiColumn, - global::BTreeMultiColumn - >.DoInsert(row); - - public bool Delete(global::BTreeMultiColumn row) => - global::SpacetimeDB.Internal.ITableView< - BTreeMultiColumn, - global::BTreeMultiColumn - >.DoDelete(row); - - internal sealed class LocationIndex() - : SpacetimeDB.Internal.IndexBase( - "BTreeMultiColumn_X_Y_Z_idx_btree" - ) - { - public IEnumerable Filter(uint X) => - DoFilter( - new SpacetimeDB.Internal.BTreeIndexBounds(X) - ); - - public ulong Delete(uint X) => - DoDelete( - new SpacetimeDB.Internal.BTreeIndexBounds(X) - ); - - public IEnumerable Filter(Bound X) => - DoFilter( - new SpacetimeDB.Internal.BTreeIndexBounds(X) - ); - - public ulong Delete(Bound X) => - DoDelete( - new SpacetimeDB.Internal.BTreeIndexBounds(X) - ); - - public IEnumerable Filter((uint X, uint Y) f) => - DoFilter( - new SpacetimeDB.Internal.BTreeIndexBounds< - uint, - SpacetimeDB.BSATN.U32, - uint, - SpacetimeDB.BSATN.U32 - >(f) - ); - - public ulong Delete((uint X, uint Y) f) => - DoDelete( - new SpacetimeDB.Internal.BTreeIndexBounds< - uint, - SpacetimeDB.BSATN.U32, - uint, - SpacetimeDB.BSATN.U32 - >(f) - ); - - public IEnumerable Filter((uint X, Bound Y) f) => - DoFilter( - new SpacetimeDB.Internal.BTreeIndexBounds< - uint, - SpacetimeDB.BSATN.U32, - uint, - SpacetimeDB.BSATN.U32 - >(f) - ); - - public ulong Delete((uint X, Bound Y) f) => - DoDelete( - new SpacetimeDB.Internal.BTreeIndexBounds< - uint, - SpacetimeDB.BSATN.U32, - uint, - SpacetimeDB.BSATN.U32 - >(f) - ); - - public IEnumerable Filter((uint X, uint Y, uint Z) f) => - DoFilter( - new SpacetimeDB.Internal.BTreeIndexBounds< - uint, - SpacetimeDB.BSATN.U32, - uint, - SpacetimeDB.BSATN.U32, - uint, - SpacetimeDB.BSATN.U32 - >(f) - ); - - public ulong Delete((uint X, uint Y, uint Z) f) => - DoDelete( - new SpacetimeDB.Internal.BTreeIndexBounds< - uint, - SpacetimeDB.BSATN.U32, - uint, - SpacetimeDB.BSATN.U32, - uint, - SpacetimeDB.BSATN.U32 - >(f) - ); - - public IEnumerable Filter( - (uint X, uint Y, Bound Z) f - ) => - DoFilter( - new SpacetimeDB.Internal.BTreeIndexBounds< - uint, - SpacetimeDB.BSATN.U32, - uint, - SpacetimeDB.BSATN.U32, - uint, - SpacetimeDB.BSATN.U32 - >(f) - ); - - public ulong Delete((uint X, uint Y, Bound Z) f) => - DoDelete( - new SpacetimeDB.Internal.BTreeIndexBounds< - uint, - SpacetimeDB.BSATN.U32, - uint, - SpacetimeDB.BSATN.U32, - uint, - SpacetimeDB.BSATN.U32 - >(f) - ); - } + public global::BTreeMultiColumn Insert(global::BTreeMultiColumn row) => + global::SpacetimeDB.Internal.ITableView< + BTreeMultiColumn, + global::BTreeMultiColumn + >.DoInsert(row); - internal LocationIndex Location => new(); - } + public bool Delete(global::BTreeMultiColumn row) => + global::SpacetimeDB.Internal.ITableView< + BTreeMultiColumn, + global::BTreeMultiColumn + >.DoDelete(row); - internal readonly struct BTreeViews - : global::SpacetimeDB.Internal.ITableView + internal sealed class LocationIndex() + : SpacetimeDB.Internal.IndexBase( + "BTreeMultiColumn_X_Y_Z_idx_btree" + ) { - static global::BTreeViews global::SpacetimeDB.Internal.ITableView< - BTreeViews, - global::BTreeViews - >.ReadGenFields(System.IO.BinaryReader reader, global::BTreeViews row) - { - return row; - } + public IEnumerable Filter(uint X) => + DoFilter(new SpacetimeDB.Internal.BTreeIndexBounds(X)); - static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< - BTreeViews, - global::BTreeViews - >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => - new( - Name: nameof(BTreeViews), - ProductTypeRef: (uint) - new global::BTreeViews.BSATN().GetAlgebraicType(registrar).Ref_, - PrimaryKey: [0], - Indexes: - [ - new( - Name: null, - AccessorName: "Id", - Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([0]) - ), - new( - Name: null, - AccessorName: "Location", - Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([1, 2]) - ), - new( - Name: null, - AccessorName: "Faction", - Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([3]) - ) - ], - Constraints: - [ - global::SpacetimeDB.Internal.ITableView< - BTreeViews, - global::BTreeViews - >.MakeUniqueConstraint(0) - ], - Sequences: [], - Schedule: null, - TableType: SpacetimeDB.Internal.TableType.User, - TableAccess: SpacetimeDB.Internal.TableAccess.Private + public ulong Delete(uint X) => + DoDelete(new SpacetimeDB.Internal.BTreeIndexBounds(X)); + + public IEnumerable Filter(Bound X) => + DoFilter(new SpacetimeDB.Internal.BTreeIndexBounds(X)); + + public ulong Delete(Bound X) => + DoDelete(new SpacetimeDB.Internal.BTreeIndexBounds(X)); + + public IEnumerable Filter((uint X, uint Y) f) => + DoFilter( + new SpacetimeDB.Internal.BTreeIndexBounds< + uint, + SpacetimeDB.BSATN.U32, + uint, + SpacetimeDB.BSATN.U32 + >(f) + ); + + public ulong Delete((uint X, uint Y) f) => + DoDelete( + new SpacetimeDB.Internal.BTreeIndexBounds< + uint, + SpacetimeDB.BSATN.U32, + uint, + SpacetimeDB.BSATN.U32 + >(f) + ); + + public IEnumerable Filter((uint X, Bound Y) f) => + DoFilter( + new SpacetimeDB.Internal.BTreeIndexBounds< + uint, + SpacetimeDB.BSATN.U32, + uint, + SpacetimeDB.BSATN.U32 + >(f) + ); + + public ulong Delete((uint X, Bound Y) f) => + DoDelete( + new SpacetimeDB.Internal.BTreeIndexBounds< + uint, + SpacetimeDB.BSATN.U32, + uint, + SpacetimeDB.BSATN.U32 + >(f) ); - public ulong Count => - global::SpacetimeDB.Internal.ITableView.DoCount(); + public IEnumerable Filter((uint X, uint Y, uint Z) f) => + DoFilter( + new SpacetimeDB.Internal.BTreeIndexBounds< + uint, + SpacetimeDB.BSATN.U32, + uint, + SpacetimeDB.BSATN.U32, + uint, + SpacetimeDB.BSATN.U32 + >(f) + ); - public IEnumerable Iter() => - global::SpacetimeDB.Internal.ITableView.DoIter(); + public ulong Delete((uint X, uint Y, uint Z) f) => + DoDelete( + new SpacetimeDB.Internal.BTreeIndexBounds< + uint, + SpacetimeDB.BSATN.U32, + uint, + SpacetimeDB.BSATN.U32, + uint, + SpacetimeDB.BSATN.U32 + >(f) + ); - public global::BTreeViews Insert(global::BTreeViews row) => - global::SpacetimeDB.Internal.ITableView.DoInsert( - row + public IEnumerable Filter( + (uint X, uint Y, Bound Z) f + ) => + DoFilter( + new SpacetimeDB.Internal.BTreeIndexBounds< + uint, + SpacetimeDB.BSATN.U32, + uint, + SpacetimeDB.BSATN.U32, + uint, + SpacetimeDB.BSATN.U32 + >(f) ); - public bool Delete(global::BTreeViews row) => - global::SpacetimeDB.Internal.ITableView.DoDelete( - row + public ulong Delete((uint X, uint Y, Bound Z) f) => + DoDelete( + new SpacetimeDB.Internal.BTreeIndexBounds< + uint, + SpacetimeDB.BSATN.U32, + uint, + SpacetimeDB.BSATN.U32, + uint, + SpacetimeDB.BSATN.U32 + >(f) ); + } - internal sealed class IdUniqueIndex - : UniqueIndex< - BTreeViews, - global::BTreeViews, - SpacetimeDB.Identity, - SpacetimeDB.Identity.BSATN - > - { - internal IdUniqueIndex() - : base("BTreeViews_Id_idx_btree") { } + internal LocationIndex Location => new(); + } - // Important: don't move this to the base class. - // C# generics don't play well with nullable types and can't accept both struct-type-based and class-type-based - // `globalName` in one generic definition, leading to buggy `Row?` expansion for either one or another. - public global::BTreeViews? Find(SpacetimeDB.Identity key) => - DoFilter(key).Cast().SingleOrDefault(); + internal readonly struct BTreeViews + : global::SpacetimeDB.Internal.ITableView + { + static global::BTreeViews global::SpacetimeDB.Internal.ITableView< + BTreeViews, + global::BTreeViews + >.ReadGenFields(System.IO.BinaryReader reader, global::BTreeViews row) + { + return row; + } - public global::BTreeViews Update(global::BTreeViews row) => DoUpdate(row); - } + static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< + BTreeViews, + global::BTreeViews + >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => + new( + Name: nameof(BTreeViews), + ProductTypeRef: (uint) + new global::BTreeViews.BSATN().GetAlgebraicType(registrar).Ref_, + PrimaryKey: [0], + Indexes: + [ + new( + Name: null, + AccessorName: "Id", + Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([0]) + ), + new( + Name: null, + AccessorName: "Location", + Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([1, 2]) + ), + new( + Name: null, + AccessorName: "Faction", + Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([3]) + ) + ], + Constraints: + [ + global::SpacetimeDB.Internal.ITableView< + BTreeViews, + global::BTreeViews + >.MakeUniqueConstraint(0) + ], + Sequences: [], + Schedule: null, + TableType: SpacetimeDB.Internal.TableType.User, + TableAccess: SpacetimeDB.Internal.TableAccess.Private + ); - internal IdUniqueIndex Id => new(); + public ulong Count => + global::SpacetimeDB.Internal.ITableView.DoCount(); - internal sealed class LocationIndex() - : SpacetimeDB.Internal.IndexBase("BTreeViews_X_Y_idx_btree") - { - public IEnumerable Filter(uint X) => - DoFilter( - new SpacetimeDB.Internal.BTreeIndexBounds(X) - ); - - public ulong Delete(uint X) => - DoDelete( - new SpacetimeDB.Internal.BTreeIndexBounds(X) - ); - - public IEnumerable Filter(Bound X) => - DoFilter( - new SpacetimeDB.Internal.BTreeIndexBounds(X) - ); - - public ulong Delete(Bound X) => - DoDelete( - new SpacetimeDB.Internal.BTreeIndexBounds(X) - ); - - public IEnumerable Filter((uint X, uint Y) f) => - DoFilter( - new SpacetimeDB.Internal.BTreeIndexBounds< - uint, - SpacetimeDB.BSATN.U32, - uint, - SpacetimeDB.BSATN.U32 - >(f) - ); - - public ulong Delete((uint X, uint Y) f) => - DoDelete( - new SpacetimeDB.Internal.BTreeIndexBounds< - uint, - SpacetimeDB.BSATN.U32, - uint, - SpacetimeDB.BSATN.U32 - >(f) - ); - - public IEnumerable Filter((uint X, Bound Y) f) => - DoFilter( - new SpacetimeDB.Internal.BTreeIndexBounds< - uint, - SpacetimeDB.BSATN.U32, - uint, - SpacetimeDB.BSATN.U32 - >(f) - ); - - public ulong Delete((uint X, Bound Y) f) => - DoDelete( - new SpacetimeDB.Internal.BTreeIndexBounds< - uint, - SpacetimeDB.BSATN.U32, - uint, - SpacetimeDB.BSATN.U32 - >(f) - ); - } + public IEnumerable Iter() => + global::SpacetimeDB.Internal.ITableView.DoIter(); - internal LocationIndex Location => new(); + public global::BTreeViews Insert(global::BTreeViews row) => + global::SpacetimeDB.Internal.ITableView.DoInsert(row); - internal sealed class FactionIndex() - : SpacetimeDB.Internal.IndexBase("BTreeViews_Faction_idx_btree") - { - public IEnumerable Filter(string Faction) => - DoFilter( - new SpacetimeDB.Internal.BTreeIndexBounds( - Faction - ) - ); - - public ulong Delete(string Faction) => - DoDelete( - new SpacetimeDB.Internal.BTreeIndexBounds( - Faction - ) - ); - - public IEnumerable Filter(Bound Faction) => - DoFilter( - new SpacetimeDB.Internal.BTreeIndexBounds( - Faction - ) - ); - - public ulong Delete(Bound Faction) => - DoDelete( - new SpacetimeDB.Internal.BTreeIndexBounds( - Faction - ) - ); - } + public bool Delete(global::BTreeViews row) => + global::SpacetimeDB.Internal.ITableView.DoDelete(row); - internal FactionIndex Faction => new(); + internal sealed class IdUniqueIndex + : UniqueIndex< + BTreeViews, + global::BTreeViews, + SpacetimeDB.Identity, + SpacetimeDB.Identity.BSATN + > + { + internal IdUniqueIndex() + : base("BTreeViews_Id_idx_btree") { } + + // Important: don't move this to the base class. + // C# generics don't play well with nullable types and can't accept both struct-type-based and class-type-based + // `globalName` in one generic definition, leading to buggy `Row?` expansion for either one or another. + public global::BTreeViews? Find(SpacetimeDB.Identity key) => + DoFilter(key).Cast().SingleOrDefault(); + + public global::BTreeViews Update(global::BTreeViews row) => DoUpdate(row); } - public readonly struct MultiTable1 - : global::SpacetimeDB.Internal.ITableView + internal IdUniqueIndex Id => new(); + + internal sealed class LocationIndex() + : SpacetimeDB.Internal.IndexBase("BTreeViews_X_Y_idx_btree") { - static global::MultiTableRow global::SpacetimeDB.Internal.ITableView< - MultiTable1, - global::MultiTableRow - >.ReadGenFields(System.IO.BinaryReader reader, global::MultiTableRow row) - { - if (row.Foo == default) - { - row.Foo = global::MultiTableRow.BSATN.FooRW.Read(reader); - } - return row; - } + public IEnumerable Filter(uint X) => + DoFilter(new SpacetimeDB.Internal.BTreeIndexBounds(X)); + + public ulong Delete(uint X) => + DoDelete(new SpacetimeDB.Internal.BTreeIndexBounds(X)); + + public IEnumerable Filter(Bound X) => + DoFilter(new SpacetimeDB.Internal.BTreeIndexBounds(X)); - static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< - MultiTable1, - global::MultiTableRow - >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => - new( - Name: nameof(MultiTable1), - ProductTypeRef: (uint) - new global::MultiTableRow.BSATN().GetAlgebraicType(registrar).Ref_, - PrimaryKey: [1], - Indexes: - [ - new( - Name: null, - AccessorName: "Foo", - Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([1]) - ), - new( - Name: null, - AccessorName: "Name", - Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([0]) - ) - ], - Constraints: - [ - global::SpacetimeDB.Internal.ITableView< - MultiTable1, - global::MultiTableRow - >.MakeUniqueConstraint(1) - ], - Sequences: - [ - global::SpacetimeDB.Internal.ITableView< - MultiTable1, - global::MultiTableRow - >.MakeSequence(1) - ], - Schedule: null, - TableType: SpacetimeDB.Internal.TableType.User, - TableAccess: SpacetimeDB.Internal.TableAccess.Public + public ulong Delete(Bound X) => + DoDelete(new SpacetimeDB.Internal.BTreeIndexBounds(X)); + + public IEnumerable Filter((uint X, uint Y) f) => + DoFilter( + new SpacetimeDB.Internal.BTreeIndexBounds< + uint, + SpacetimeDB.BSATN.U32, + uint, + SpacetimeDB.BSATN.U32 + >(f) ); - public ulong Count => - global::SpacetimeDB.Internal.ITableView< - MultiTable1, - global::MultiTableRow - >.DoCount(); - - public IEnumerable Iter() => - global::SpacetimeDB.Internal.ITableView< - MultiTable1, - global::MultiTableRow - >.DoIter(); - - public global::MultiTableRow Insert(global::MultiTableRow row) => - global::SpacetimeDB.Internal.ITableView< - MultiTable1, - global::MultiTableRow - >.DoInsert(row); - - public bool Delete(global::MultiTableRow row) => - global::SpacetimeDB.Internal.ITableView< - MultiTable1, - global::MultiTableRow - >.DoDelete(row); - - public sealed class FooUniqueIndex - : UniqueIndex - { - internal FooUniqueIndex() - : base("MultiTable1_Foo_idx_btree") { } + public ulong Delete((uint X, uint Y) f) => + DoDelete( + new SpacetimeDB.Internal.BTreeIndexBounds< + uint, + SpacetimeDB.BSATN.U32, + uint, + SpacetimeDB.BSATN.U32 + >(f) + ); - // Important: don't move this to the base class. - // C# generics don't play well with nullable types and can't accept both struct-type-based and class-type-based - // `globalName` in one generic definition, leading to buggy `Row?` expansion for either one or another. - public global::MultiTableRow? Find(uint key) => - DoFilter(key).Cast().SingleOrDefault(); + public IEnumerable Filter((uint X, Bound Y) f) => + DoFilter( + new SpacetimeDB.Internal.BTreeIndexBounds< + uint, + SpacetimeDB.BSATN.U32, + uint, + SpacetimeDB.BSATN.U32 + >(f) + ); - public global::MultiTableRow Update(global::MultiTableRow row) => DoUpdate(row); - } + public ulong Delete((uint X, Bound Y) f) => + DoDelete( + new SpacetimeDB.Internal.BTreeIndexBounds< + uint, + SpacetimeDB.BSATN.U32, + uint, + SpacetimeDB.BSATN.U32 + >(f) + ); + } - public FooUniqueIndex Foo => new(); + internal LocationIndex Location => new(); - public sealed class NameIndex() - : SpacetimeDB.Internal.IndexBase( - "MultiTable1_Name_idx_btree" - ) - { - public IEnumerable Filter(string Name) => - DoFilter( - new SpacetimeDB.Internal.BTreeIndexBounds( - Name - ) - ); - - public ulong Delete(string Name) => - DoDelete( - new SpacetimeDB.Internal.BTreeIndexBounds( - Name - ) - ); - - public IEnumerable Filter(Bound Name) => - DoFilter( - new SpacetimeDB.Internal.BTreeIndexBounds( - Name - ) - ); - - public ulong Delete(Bound Name) => - DoDelete( - new SpacetimeDB.Internal.BTreeIndexBounds( - Name - ) - ); - } + internal sealed class FactionIndex() + : SpacetimeDB.Internal.IndexBase("BTreeViews_Faction_idx_btree") + { + public IEnumerable Filter(string Faction) => + DoFilter( + new SpacetimeDB.Internal.BTreeIndexBounds( + Faction + ) + ); - public NameIndex Name => new(); + public ulong Delete(string Faction) => + DoDelete( + new SpacetimeDB.Internal.BTreeIndexBounds( + Faction + ) + ); + + public IEnumerable Filter(Bound Faction) => + DoFilter( + new SpacetimeDB.Internal.BTreeIndexBounds( + Faction + ) + ); + + public ulong Delete(Bound Faction) => + DoDelete( + new SpacetimeDB.Internal.BTreeIndexBounds( + Faction + ) + ); } - public readonly struct MultiTable2 - : global::SpacetimeDB.Internal.ITableView + internal FactionIndex Faction => new(); + } + + public readonly struct MultiTable1 + : global::SpacetimeDB.Internal.ITableView + { + static global::MultiTableRow global::SpacetimeDB.Internal.ITableView< + MultiTable1, + global::MultiTableRow + >.ReadGenFields(System.IO.BinaryReader reader, global::MultiTableRow row) { - static global::MultiTableRow global::SpacetimeDB.Internal.ITableView< - MultiTable2, - global::MultiTableRow - >.ReadGenFields(System.IO.BinaryReader reader, global::MultiTableRow row) + if (row.Foo == default) { - if (row.Foo == default) - { - row.Foo = global::MultiTableRow.BSATN.FooRW.Read(reader); - } - return row; + row.Foo = global::MultiTableRow.BSATN.FooRW.Read(reader); } + return row; + } - static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< - MultiTable2, - global::MultiTableRow - >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => - new( - Name: nameof(MultiTable2), - ProductTypeRef: (uint) - new global::MultiTableRow.BSATN().GetAlgebraicType(registrar).Ref_, - PrimaryKey: [], - Indexes: - [ - new( - Name: null, - AccessorName: "Bar", - Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([2]) - ) - ], - Constraints: - [ - global::SpacetimeDB.Internal.ITableView< - MultiTable2, - global::MultiTableRow - >.MakeUniqueConstraint(2) - ], - Sequences: - [ - global::SpacetimeDB.Internal.ITableView< - MultiTable2, - global::MultiTableRow - >.MakeSequence(1) - ], - Schedule: null, - TableType: SpacetimeDB.Internal.TableType.User, - TableAccess: SpacetimeDB.Internal.TableAccess.Private - ); + static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< + MultiTable1, + global::MultiTableRow + >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => + new( + Name: nameof(MultiTable1), + ProductTypeRef: (uint) + new global::MultiTableRow.BSATN().GetAlgebraicType(registrar).Ref_, + PrimaryKey: [1], + Indexes: + [ + new( + Name: null, + AccessorName: "Foo", + Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([1]) + ), + new( + Name: null, + AccessorName: "Name", + Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([0]) + ) + ], + Constraints: + [ + global::SpacetimeDB.Internal.ITableView< + MultiTable1, + global::MultiTableRow + >.MakeUniqueConstraint(1) + ], + Sequences: + [ + global::SpacetimeDB.Internal.ITableView< + MultiTable1, + global::MultiTableRow + >.MakeSequence(1) + ], + Schedule: null, + TableType: SpacetimeDB.Internal.TableType.User, + TableAccess: SpacetimeDB.Internal.TableAccess.Public + ); - public ulong Count => - global::SpacetimeDB.Internal.ITableView< - MultiTable2, - global::MultiTableRow - >.DoCount(); - - public IEnumerable Iter() => - global::SpacetimeDB.Internal.ITableView< - MultiTable2, - global::MultiTableRow - >.DoIter(); - - public global::MultiTableRow Insert(global::MultiTableRow row) => - global::SpacetimeDB.Internal.ITableView< - MultiTable2, - global::MultiTableRow - >.DoInsert(row); - - public bool Delete(global::MultiTableRow row) => - global::SpacetimeDB.Internal.ITableView< - MultiTable2, - global::MultiTableRow - >.DoDelete(row); - - public sealed class BarUniqueIndex - : UniqueIndex - { - internal BarUniqueIndex() - : base("MultiTable2_Bar_idx_btree") { } + public ulong Count => + global::SpacetimeDB.Internal.ITableView.DoCount(); - // Important: don't move this to the base class. - // C# generics don't play well with nullable types and can't accept both struct-type-based and class-type-based - // `globalName` in one generic definition, leading to buggy `Row?` expansion for either one or another. - public global::MultiTableRow? Find(uint key) => - DoFilter(key).Cast().SingleOrDefault(); + public IEnumerable Iter() => + global::SpacetimeDB.Internal.ITableView.DoIter(); - public global::MultiTableRow Update(global::MultiTableRow row) => DoUpdate(row); - } + public global::MultiTableRow Insert(global::MultiTableRow row) => + global::SpacetimeDB.Internal.ITableView.DoInsert( + row + ); - public BarUniqueIndex Bar => new(); + public bool Delete(global::MultiTableRow row) => + global::SpacetimeDB.Internal.ITableView.DoDelete( + row + ); + + public sealed class FooUniqueIndex + : UniqueIndex + { + internal FooUniqueIndex() + : base("MultiTable1_Foo_idx_btree") { } + + // Important: don't move this to the base class. + // C# generics don't play well with nullable types and can't accept both struct-type-based and class-type-based + // `globalName` in one generic definition, leading to buggy `Row?` expansion for either one or another. + public global::MultiTableRow? Find(uint key) => + DoFilter(key).Cast().SingleOrDefault(); + + public global::MultiTableRow Update(global::MultiTableRow row) => DoUpdate(row); } - public readonly struct PrivateTable - : global::SpacetimeDB.Internal.ITableView + public FooUniqueIndex Foo => new(); + + public sealed class NameIndex() + : SpacetimeDB.Internal.IndexBase("MultiTable1_Name_idx_btree") { - static global::PrivateTable global::SpacetimeDB.Internal.ITableView< - PrivateTable, - global::PrivateTable - >.ReadGenFields(System.IO.BinaryReader reader, global::PrivateTable row) - { - return row; - } + public IEnumerable Filter(string Name) => + DoFilter( + new SpacetimeDB.Internal.BTreeIndexBounds( + Name + ) + ); + + public ulong Delete(string Name) => + DoDelete( + new SpacetimeDB.Internal.BTreeIndexBounds( + Name + ) + ); - static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< - PrivateTable, - global::PrivateTable - >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => - new( - Name: nameof(PrivateTable), - ProductTypeRef: (uint) - new global::PrivateTable.BSATN().GetAlgebraicType(registrar).Ref_, - PrimaryKey: [], - Indexes: [], - Constraints: [], - Sequences: [], - Schedule: null, - TableType: SpacetimeDB.Internal.TableType.User, - TableAccess: SpacetimeDB.Internal.TableAccess.Private + public IEnumerable Filter(Bound Name) => + DoFilter( + new SpacetimeDB.Internal.BTreeIndexBounds( + Name + ) ); - public ulong Count => - global::SpacetimeDB.Internal.ITableView< - PrivateTable, - global::PrivateTable - >.DoCount(); - - public IEnumerable Iter() => - global::SpacetimeDB.Internal.ITableView< - PrivateTable, - global::PrivateTable - >.DoIter(); - - public global::PrivateTable Insert(global::PrivateTable row) => - global::SpacetimeDB.Internal.ITableView< - PrivateTable, - global::PrivateTable - >.DoInsert(row); - - public bool Delete(global::PrivateTable row) => - global::SpacetimeDB.Internal.ITableView< - PrivateTable, - global::PrivateTable - >.DoDelete(row); + public ulong Delete(Bound Name) => + DoDelete( + new SpacetimeDB.Internal.BTreeIndexBounds( + Name + ) + ); } - public readonly struct PublicTable - : global::SpacetimeDB.Internal.ITableView + public NameIndex Name => new(); + } + + public readonly struct MultiTable2 + : global::SpacetimeDB.Internal.ITableView + { + static global::MultiTableRow global::SpacetimeDB.Internal.ITableView< + MultiTable2, + global::MultiTableRow + >.ReadGenFields(System.IO.BinaryReader reader, global::MultiTableRow row) { - static global::PublicTable global::SpacetimeDB.Internal.ITableView< - PublicTable, - global::PublicTable - >.ReadGenFields(System.IO.BinaryReader reader, global::PublicTable row) + if (row.Foo == default) { - if (row.Id == default) - { - row.Id = global::PublicTable.BSATN.IdRW.Read(reader); - } - return row; + row.Foo = global::MultiTableRow.BSATN.FooRW.Read(reader); } + return row; + } - static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< - PublicTable, - global::PublicTable - >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => - new( - Name: nameof(PublicTable), - ProductTypeRef: (uint) - new global::PublicTable.BSATN().GetAlgebraicType(registrar).Ref_, - PrimaryKey: [0], - Indexes: - [ - new( - Name: null, - AccessorName: "Id", - Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([0]) - ) - ], - Constraints: - [ - global::SpacetimeDB.Internal.ITableView< - PublicTable, - global::PublicTable - >.MakeUniqueConstraint(0) - ], - Sequences: - [ - global::SpacetimeDB.Internal.ITableView< - PublicTable, - global::PublicTable - >.MakeSequence(0) - ], - Schedule: null, - TableType: SpacetimeDB.Internal.TableType.User, - TableAccess: SpacetimeDB.Internal.TableAccess.Public - ); + static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< + MultiTable2, + global::MultiTableRow + >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => + new( + Name: nameof(MultiTable2), + ProductTypeRef: (uint) + new global::MultiTableRow.BSATN().GetAlgebraicType(registrar).Ref_, + PrimaryKey: [], + Indexes: + [ + new( + Name: null, + AccessorName: "Bar", + Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([2]) + ) + ], + Constraints: + [ + global::SpacetimeDB.Internal.ITableView< + MultiTable2, + global::MultiTableRow + >.MakeUniqueConstraint(2) + ], + Sequences: + [ + global::SpacetimeDB.Internal.ITableView< + MultiTable2, + global::MultiTableRow + >.MakeSequence(1) + ], + Schedule: null, + TableType: SpacetimeDB.Internal.TableType.User, + TableAccess: SpacetimeDB.Internal.TableAccess.Private + ); - public ulong Count => - global::SpacetimeDB.Internal.ITableView.DoCount(); + public ulong Count => + global::SpacetimeDB.Internal.ITableView.DoCount(); - public IEnumerable Iter() => - global::SpacetimeDB.Internal.ITableView.DoIter(); + public IEnumerable Iter() => + global::SpacetimeDB.Internal.ITableView.DoIter(); - public global::PublicTable Insert(global::PublicTable row) => - global::SpacetimeDB.Internal.ITableView.DoInsert( - row - ); + public global::MultiTableRow Insert(global::MultiTableRow row) => + global::SpacetimeDB.Internal.ITableView.DoInsert( + row + ); - public bool Delete(global::PublicTable row) => - global::SpacetimeDB.Internal.ITableView.DoDelete( - row - ); + public bool Delete(global::MultiTableRow row) => + global::SpacetimeDB.Internal.ITableView.DoDelete( + row + ); - public sealed class IdUniqueIndex - : UniqueIndex - { - internal IdUniqueIndex() - : base("PublicTable_Id_idx_btree") { } + public sealed class BarUniqueIndex + : UniqueIndex + { + internal BarUniqueIndex() + : base("MultiTable2_Bar_idx_btree") { } + + // Important: don't move this to the base class. + // C# generics don't play well with nullable types and can't accept both struct-type-based and class-type-based + // `globalName` in one generic definition, leading to buggy `Row?` expansion for either one or another. + public global::MultiTableRow? Find(uint key) => + DoFilter(key).Cast().SingleOrDefault(); + + public global::MultiTableRow Update(global::MultiTableRow row) => DoUpdate(row); + } - // Important: don't move this to the base class. - // C# generics don't play well with nullable types and can't accept both struct-type-based and class-type-based - // `globalName` in one generic definition, leading to buggy `Row?` expansion for either one or another. - public global::PublicTable? Find(int key) => - DoFilter(key).Cast().SingleOrDefault(); + public BarUniqueIndex Bar => new(); + } - public global::PublicTable Update(global::PublicTable row) => DoUpdate(row); + public readonly struct PrivateTable + : global::SpacetimeDB.Internal.ITableView + { + static global::PrivateTable global::SpacetimeDB.Internal.ITableView< + PrivateTable, + global::PrivateTable + >.ReadGenFields(System.IO.BinaryReader reader, global::PrivateTable row) + { + return row; + } + + static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< + PrivateTable, + global::PrivateTable + >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => + new( + Name: nameof(PrivateTable), + ProductTypeRef: (uint) + new global::PrivateTable.BSATN().GetAlgebraicType(registrar).Ref_, + PrimaryKey: [], + Indexes: [], + Constraints: [], + Sequences: [], + Schedule: null, + TableType: SpacetimeDB.Internal.TableType.User, + TableAccess: SpacetimeDB.Internal.TableAccess.Private + ); + + public ulong Count => + global::SpacetimeDB.Internal.ITableView.DoCount(); + + public IEnumerable Iter() => + global::SpacetimeDB.Internal.ITableView.DoIter(); + + public global::PrivateTable Insert(global::PrivateTable row) => + global::SpacetimeDB.Internal.ITableView.DoInsert( + row + ); + + public bool Delete(global::PrivateTable row) => + global::SpacetimeDB.Internal.ITableView.DoDelete( + row + ); + } + + public readonly struct PublicTable + : global::SpacetimeDB.Internal.ITableView + { + static global::PublicTable global::SpacetimeDB.Internal.ITableView< + PublicTable, + global::PublicTable + >.ReadGenFields(System.IO.BinaryReader reader, global::PublicTable row) + { + if (row.Id == default) + { + row.Id = global::PublicTable.BSATN.IdRW.Read(reader); } + return row; + } - public IdUniqueIndex Id => new(); + static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< + PublicTable, + global::PublicTable + >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => + new( + Name: nameof(PublicTable), + ProductTypeRef: (uint) + new global::PublicTable.BSATN().GetAlgebraicType(registrar).Ref_, + PrimaryKey: [0], + Indexes: + [ + new( + Name: null, + AccessorName: "Id", + Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([0]) + ) + ], + Constraints: + [ + global::SpacetimeDB.Internal.ITableView< + PublicTable, + global::PublicTable + >.MakeUniqueConstraint(0) + ], + Sequences: + [ + global::SpacetimeDB.Internal.ITableView< + PublicTable, + global::PublicTable + >.MakeSequence(0) + ], + Schedule: null, + TableType: SpacetimeDB.Internal.TableType.User, + TableAccess: SpacetimeDB.Internal.TableAccess.Public + ); + + public ulong Count => + global::SpacetimeDB.Internal.ITableView.DoCount(); + + public IEnumerable Iter() => + global::SpacetimeDB.Internal.ITableView.DoIter(); + + public global::PublicTable Insert(global::PublicTable row) => + global::SpacetimeDB.Internal.ITableView.DoInsert(row); + + public bool Delete(global::PublicTable row) => + global::SpacetimeDB.Internal.ITableView.DoDelete(row); + + public sealed class IdUniqueIndex + : UniqueIndex + { + internal IdUniqueIndex() + : base("PublicTable_Id_idx_btree") { } + + // Important: don't move this to the base class. + // C# generics don't play well with nullable types and can't accept both struct-type-based and class-type-based + // `globalName` in one generic definition, leading to buggy `Row?` expansion for either one or another. + public global::PublicTable? Find(int key) => + DoFilter(key).Cast().SingleOrDefault(); + + public global::PublicTable Update(global::PublicTable row) => DoUpdate(row); + } + + public IdUniqueIndex Id => new(); + } + + internal readonly struct RegressionMultipleUniqueIndexesHadSameName + : global::SpacetimeDB.Internal.ITableView< + RegressionMultipleUniqueIndexesHadSameName, + global::RegressionMultipleUniqueIndexesHadSameName + > + { + static global::RegressionMultipleUniqueIndexesHadSameName global::SpacetimeDB.Internal.ITableView< + RegressionMultipleUniqueIndexesHadSameName, + global::RegressionMultipleUniqueIndexesHadSameName + >.ReadGenFields( + System.IO.BinaryReader reader, + global::RegressionMultipleUniqueIndexesHadSameName row + ) + { + return row; } - internal readonly struct RegressionMultipleUniqueIndexesHadSameName - : global::SpacetimeDB.Internal.ITableView< + static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< + RegressionMultipleUniqueIndexesHadSameName, + global::RegressionMultipleUniqueIndexesHadSameName + >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => + new( + Name: nameof(RegressionMultipleUniqueIndexesHadSameName), + ProductTypeRef: (uint) + new global::RegressionMultipleUniqueIndexesHadSameName.BSATN() + .GetAlgebraicType(registrar) + .Ref_, + PrimaryKey: [], + Indexes: + [ + new( + Name: null, + AccessorName: "Unique1", + Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([0]) + ), + new( + Name: null, + AccessorName: "Unique2", + Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([1]) + ) + ], + Constraints: + [ + global::SpacetimeDB.Internal.ITableView< + RegressionMultipleUniqueIndexesHadSameName, + global::RegressionMultipleUniqueIndexesHadSameName + >.MakeUniqueConstraint(0), + global::SpacetimeDB.Internal.ITableView< + RegressionMultipleUniqueIndexesHadSameName, + global::RegressionMultipleUniqueIndexesHadSameName + >.MakeUniqueConstraint(1) + ], + Sequences: [], + Schedule: null, + TableType: SpacetimeDB.Internal.TableType.User, + TableAccess: SpacetimeDB.Internal.TableAccess.Private + ); + + public ulong Count => + global::SpacetimeDB.Internal.ITableView< RegressionMultipleUniqueIndexesHadSameName, global::RegressionMultipleUniqueIndexesHadSameName - > - { - static global::RegressionMultipleUniqueIndexesHadSameName global::SpacetimeDB.Internal.ITableView< + >.DoCount(); + + public IEnumerable Iter() => + global::SpacetimeDB.Internal.ITableView< RegressionMultipleUniqueIndexesHadSameName, global::RegressionMultipleUniqueIndexesHadSameName - >.ReadGenFields( - System.IO.BinaryReader reader, - global::RegressionMultipleUniqueIndexesHadSameName row - ) - { - return row; - } + >.DoIter(); - static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< + public global::RegressionMultipleUniqueIndexesHadSameName Insert( + global::RegressionMultipleUniqueIndexesHadSameName row + ) => + global::SpacetimeDB.Internal.ITableView< RegressionMultipleUniqueIndexesHadSameName, global::RegressionMultipleUniqueIndexesHadSameName - >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => - new( - Name: nameof(RegressionMultipleUniqueIndexesHadSameName), - ProductTypeRef: (uint) - new global::RegressionMultipleUniqueIndexesHadSameName.BSATN() - .GetAlgebraicType(registrar) - .Ref_, - PrimaryKey: [], - Indexes: - [ - new( - Name: null, - AccessorName: "Unique1", - Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([0]) - ), - new( - Name: null, - AccessorName: "Unique2", - Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([1]) - ) - ], - Constraints: - [ - global::SpacetimeDB.Internal.ITableView< - RegressionMultipleUniqueIndexesHadSameName, - global::RegressionMultipleUniqueIndexesHadSameName - >.MakeUniqueConstraint(0), - global::SpacetimeDB.Internal.ITableView< - RegressionMultipleUniqueIndexesHadSameName, - global::RegressionMultipleUniqueIndexesHadSameName - >.MakeUniqueConstraint(1) - ], - Sequences: [], - Schedule: null, - TableType: SpacetimeDB.Internal.TableType.User, - TableAccess: SpacetimeDB.Internal.TableAccess.Private - ); + >.DoInsert(row); - public ulong Count => - global::SpacetimeDB.Internal.ITableView< - RegressionMultipleUniqueIndexesHadSameName, - global::RegressionMultipleUniqueIndexesHadSameName - >.DoCount(); + public bool Delete(global::RegressionMultipleUniqueIndexesHadSameName row) => + global::SpacetimeDB.Internal.ITableView< + RegressionMultipleUniqueIndexesHadSameName, + global::RegressionMultipleUniqueIndexesHadSameName + >.DoDelete(row); - public IEnumerable Iter() => - global::SpacetimeDB.Internal.ITableView< - RegressionMultipleUniqueIndexesHadSameName, - global::RegressionMultipleUniqueIndexesHadSameName - >.DoIter(); + internal sealed class Unique1UniqueIndex + : UniqueIndex< + RegressionMultipleUniqueIndexesHadSameName, + global::RegressionMultipleUniqueIndexesHadSameName, + uint, + SpacetimeDB.BSATN.U32 + > + { + internal Unique1UniqueIndex() + : base("RegressionMultipleUniqueIndexesHadSameName_Unique1_idx_btree") { } - public global::RegressionMultipleUniqueIndexesHadSameName Insert( + // Important: don't move this to the base class. + // C# generics don't play well with nullable types and can't accept both struct-type-based and class-type-based + // `globalName` in one generic definition, leading to buggy `Row?` expansion for either one or another. + public global::RegressionMultipleUniqueIndexesHadSameName? Find(uint key) => + DoFilter(key) + .Cast() + .SingleOrDefault(); + + public global::RegressionMultipleUniqueIndexesHadSameName Update( global::RegressionMultipleUniqueIndexesHadSameName row - ) => - global::SpacetimeDB.Internal.ITableView< - RegressionMultipleUniqueIndexesHadSameName, - global::RegressionMultipleUniqueIndexesHadSameName - >.DoInsert(row); - - public bool Delete(global::RegressionMultipleUniqueIndexesHadSameName row) => - global::SpacetimeDB.Internal.ITableView< - RegressionMultipleUniqueIndexesHadSameName, - global::RegressionMultipleUniqueIndexesHadSameName - >.DoDelete(row); - - internal sealed class Unique1UniqueIndex - : UniqueIndex< - RegressionMultipleUniqueIndexesHadSameName, - global::RegressionMultipleUniqueIndexesHadSameName, - uint, - SpacetimeDB.BSATN.U32 - > - { - internal Unique1UniqueIndex() - : base("RegressionMultipleUniqueIndexesHadSameName_Unique1_idx_btree") { } - - // Important: don't move this to the base class. - // C# generics don't play well with nullable types and can't accept both struct-type-based and class-type-based - // `globalName` in one generic definition, leading to buggy `Row?` expansion for either one or another. - public global::RegressionMultipleUniqueIndexesHadSameName? Find(uint key) => - DoFilter(key) - .Cast() - .SingleOrDefault(); - - public global::RegressionMultipleUniqueIndexesHadSameName Update( - global::RegressionMultipleUniqueIndexesHadSameName row - ) => DoUpdate(row); - } + ) => DoUpdate(row); + } - internal Unique1UniqueIndex Unique1 => new(); + internal Unique1UniqueIndex Unique1 => new(); - internal sealed class Unique2UniqueIndex - : UniqueIndex< - RegressionMultipleUniqueIndexesHadSameName, - global::RegressionMultipleUniqueIndexesHadSameName, - uint, - SpacetimeDB.BSATN.U32 - > - { - internal Unique2UniqueIndex() - : base("RegressionMultipleUniqueIndexesHadSameName_Unique2_idx_btree") { } - - // Important: don't move this to the base class. - // C# generics don't play well with nullable types and can't accept both struct-type-based and class-type-based - // `globalName` in one generic definition, leading to buggy `Row?` expansion for either one or another. - public global::RegressionMultipleUniqueIndexesHadSameName? Find(uint key) => - DoFilter(key) - .Cast() - .SingleOrDefault(); - - public global::RegressionMultipleUniqueIndexesHadSameName Update( - global::RegressionMultipleUniqueIndexesHadSameName row - ) => DoUpdate(row); - } + internal sealed class Unique2UniqueIndex + : UniqueIndex< + RegressionMultipleUniqueIndexesHadSameName, + global::RegressionMultipleUniqueIndexesHadSameName, + uint, + SpacetimeDB.BSATN.U32 + > + { + internal Unique2UniqueIndex() + : base("RegressionMultipleUniqueIndexesHadSameName_Unique2_idx_btree") { } + + // Important: don't move this to the base class. + // C# generics don't play well with nullable types and can't accept both struct-type-based and class-type-based + // `globalName` in one generic definition, leading to buggy `Row?` expansion for either one or another. + public global::RegressionMultipleUniqueIndexesHadSameName? Find(uint key) => + DoFilter(key) + .Cast() + .SingleOrDefault(); - internal Unique2UniqueIndex Unique2 => new(); + public global::RegressionMultipleUniqueIndexesHadSameName Update( + global::RegressionMultipleUniqueIndexesHadSameName row + ) => DoUpdate(row); } - public readonly struct SendMessageTimer - : global::SpacetimeDB.Internal.ITableView< - SendMessageTimer, - global::Timers.SendMessageTimer - > + internal Unique2UniqueIndex Unique2 => new(); + } + + public readonly struct SendMessageTimer + : global::SpacetimeDB.Internal.ITableView + { + static global::Timers.SendMessageTimer global::SpacetimeDB.Internal.ITableView< + SendMessageTimer, + global::Timers.SendMessageTimer + >.ReadGenFields(System.IO.BinaryReader reader, global::Timers.SendMessageTimer row) { - static global::Timers.SendMessageTimer global::SpacetimeDB.Internal.ITableView< - SendMessageTimer, - global::Timers.SendMessageTimer - >.ReadGenFields(System.IO.BinaryReader reader, global::Timers.SendMessageTimer row) + if (row.ScheduledId == default) { - if (row.ScheduledId == default) - { - row.ScheduledId = global::Timers.SendMessageTimer.BSATN.ScheduledIdRW.Read( - reader - ); - } - return row; + row.ScheduledId = global::Timers.SendMessageTimer.BSATN.ScheduledIdRW.Read(reader); } + return row; + } - static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< - SendMessageTimer, - global::Timers.SendMessageTimer - >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => - new( - Name: nameof(SendMessageTimer), - ProductTypeRef: (uint) - new global::Timers.SendMessageTimer.BSATN() - .GetAlgebraicType(registrar) - .Ref_, - PrimaryKey: [0], - Indexes: - [ - new( - Name: null, - AccessorName: "ScheduledId", - Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([0]) - ) - ], - Constraints: - [ - global::SpacetimeDB.Internal.ITableView< - SendMessageTimer, - global::Timers.SendMessageTimer - >.MakeUniqueConstraint(0) - ], - Sequences: - [ - global::SpacetimeDB.Internal.ITableView< - SendMessageTimer, - global::Timers.SendMessageTimer - >.MakeSequence(0) - ], - Schedule: global::SpacetimeDB.Internal.ITableView< + static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< + SendMessageTimer, + global::Timers.SendMessageTimer + >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => + new( + Name: nameof(SendMessageTimer), + ProductTypeRef: (uint) + new global::Timers.SendMessageTimer.BSATN().GetAlgebraicType(registrar).Ref_, + PrimaryKey: [0], + Indexes: + [ + new( + Name: null, + AccessorName: "ScheduledId", + Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([0]) + ) + ], + Constraints: + [ + global::SpacetimeDB.Internal.ITableView< SendMessageTimer, global::Timers.SendMessageTimer - >.MakeSchedule("SendScheduledMessage", 1), - TableType: SpacetimeDB.Internal.TableType.User, - TableAccess: SpacetimeDB.Internal.TableAccess.Private - ); - - public ulong Count => - global::SpacetimeDB.Internal.ITableView< + >.MakeUniqueConstraint(0) + ], + Sequences: + [ + global::SpacetimeDB.Internal.ITableView< + SendMessageTimer, + global::Timers.SendMessageTimer + >.MakeSequence(0) + ], + Schedule: global::SpacetimeDB.Internal.ITableView< SendMessageTimer, global::Timers.SendMessageTimer - >.DoCount(); + >.MakeSchedule("SendScheduledMessage", 1), + TableType: SpacetimeDB.Internal.TableType.User, + TableAccess: SpacetimeDB.Internal.TableAccess.Private + ); - public IEnumerable Iter() => - global::SpacetimeDB.Internal.ITableView< - SendMessageTimer, - global::Timers.SendMessageTimer - >.DoIter(); + public ulong Count => + global::SpacetimeDB.Internal.ITableView< + SendMessageTimer, + global::Timers.SendMessageTimer + >.DoCount(); - public global::Timers.SendMessageTimer Insert(global::Timers.SendMessageTimer row) => - global::SpacetimeDB.Internal.ITableView< - SendMessageTimer, - global::Timers.SendMessageTimer - >.DoInsert(row); + public IEnumerable Iter() => + global::SpacetimeDB.Internal.ITableView< + SendMessageTimer, + global::Timers.SendMessageTimer + >.DoIter(); - public bool Delete(global::Timers.SendMessageTimer row) => - global::SpacetimeDB.Internal.ITableView< - SendMessageTimer, - global::Timers.SendMessageTimer - >.DoDelete(row); + public global::Timers.SendMessageTimer Insert(global::Timers.SendMessageTimer row) => + global::SpacetimeDB.Internal.ITableView< + SendMessageTimer, + global::Timers.SendMessageTimer + >.DoInsert(row); - public sealed class ScheduledIdUniqueIndex - : UniqueIndex< - SendMessageTimer, - global::Timers.SendMessageTimer, - ulong, - SpacetimeDB.BSATN.U64 - > - { - internal ScheduledIdUniqueIndex() - : base("SendMessageTimer_ScheduledId_idx_btree") { } - - // Important: don't move this to the base class. - // C# generics don't play well with nullable types and can't accept both struct-type-based and class-type-based - // `globalName` in one generic definition, leading to buggy `Row?` expansion for either one or another. - public global::Timers.SendMessageTimer? Find(ulong key) => - DoFilter(key).Cast().SingleOrDefault(); - - public global::Timers.SendMessageTimer Update( - global::Timers.SendMessageTimer row - ) => DoUpdate(row); - } + public bool Delete(global::Timers.SendMessageTimer row) => + global::SpacetimeDB.Internal.ITableView< + SendMessageTimer, + global::Timers.SendMessageTimer + >.DoDelete(row); - public ScheduledIdUniqueIndex ScheduledId => new(); + public sealed class ScheduledIdUniqueIndex + : UniqueIndex< + SendMessageTimer, + global::Timers.SendMessageTimer, + ulong, + SpacetimeDB.BSATN.U64 + > + { + internal ScheduledIdUniqueIndex() + : base("SendMessageTimer_ScheduledId_idx_btree") { } + + // Important: don't move this to the base class. + // C# generics don't play well with nullable types and can't accept both struct-type-based and class-type-based + // `globalName` in one generic definition, leading to buggy `Row?` expansion for either one or another. + public global::Timers.SendMessageTimer? Find(ulong key) => + DoFilter(key).Cast().SingleOrDefault(); + + public global::Timers.SendMessageTimer Update(global::Timers.SendMessageTimer row) => + DoUpdate(row); } - } - public sealed class Local - { - internal global::SpacetimeDB.Internal.TableHandles.BTreeMultiColumn BTreeMultiColumn => - new(); - internal global::SpacetimeDB.Internal.TableHandles.BTreeViews BTreeViews => new(); - public global::SpacetimeDB.Internal.TableHandles.MultiTable1 MultiTable1 => new(); - public global::SpacetimeDB.Internal.TableHandles.MultiTable2 MultiTable2 => new(); - public global::SpacetimeDB.Internal.TableHandles.PrivateTable PrivateTable => new(); - public global::SpacetimeDB.Internal.TableHandles.PublicTable PublicTable => new(); - internal global::SpacetimeDB.Internal.TableHandles.RegressionMultipleUniqueIndexesHadSameName RegressionMultipleUniqueIndexesHadSameName => - new(); - public global::SpacetimeDB.Internal.TableHandles.SendMessageTimer SendMessageTimer => new(); + public ScheduledIdUniqueIndex ScheduledId => new(); } } @@ -1533,24 +1508,6 @@ internal ScheduledIdIndex() } } -namespace SpacetimeDB.Internal -{ - public sealed partial class LocalReadOnly - { - internal global::SpacetimeDB.Internal.ViewHandles.BTreeMultiColumnReadOnly BTreeMultiColumn => - new(); - internal global::SpacetimeDB.Internal.ViewHandles.BTreeViewsReadOnly BTreeViews => new(); - public global::SpacetimeDB.Internal.ViewHandles.MultiTable1ReadOnly MultiTable1 => new(); - public global::SpacetimeDB.Internal.ViewHandles.MultiTable2ReadOnly MultiTable2 => new(); - public global::SpacetimeDB.Internal.ViewHandles.PrivateTableReadOnly PrivateTable => new(); - public global::SpacetimeDB.Internal.ViewHandles.PublicTableReadOnly PublicTable => new(); - internal global::SpacetimeDB.Internal.ViewHandles.RegressionMultipleUniqueIndexesHadSameNameReadOnly RegressionMultipleUniqueIndexesHadSameName => - new(); - public global::SpacetimeDB.Internal.ViewHandles.SendMessageTimerReadOnly SendMessageTimer => - new(); - } -} - static class ModuleRegistration { class Init : SpacetimeDB.Internal.IReducer @@ -1665,13 +1622,10 @@ public static void Main() new SpacetimeDB.ReducerContext(identity, connectionId, random, time) ); SpacetimeDB.Internal.Module.SetViewContextConstructor( - identity => new SpacetimeDB.ViewContext( - identity, - new SpacetimeDB.Internal.LocalReadOnly() - ) + identity => new SpacetimeDB.ViewContext(identity, new SpacetimeDB.LocalReadOnly()) ); SpacetimeDB.Internal.Module.SetAnonymousViewContextConstructor( - () => new SpacetimeDB.AnonymousViewContext(new SpacetimeDB.Internal.LocalReadOnly()) + () => new SpacetimeDB.AnonymousViewContext(new SpacetimeDB.LocalReadOnly()) ); SpacetimeDB.Internal.Module.SetProcedureContextConstructor( (identity, connectionId, random, time) => @@ -1788,6 +1742,10 @@ SpacetimeDB.Internal.BytesSink result_sink result_sink ); + [UnmanagedCallersOnly(EntryPoint = "__take_procedure_tx_offset__")] + public static byte __take_procedure_tx_offset__(ulong* offset) => + SpacetimeDB.Internal.Module.__take_procedure_tx_offset__(out *offset) ? (byte)1 : (byte)0; + [UnmanagedCallersOnly(EntryPoint = "__call_view__")] public static SpacetimeDB.Internal.Errno __call_view__( uint id, @@ -1817,4 +1775,5 @@ SpacetimeDB.Internal.BytesSink sink #endif } +#pragma warning restore STDB_UNSTABLE #pragma warning restore CS0436 diff --git a/crates/bindings-csharp/Codegen/Codegen.csproj b/crates/bindings-csharp/Codegen/Codegen.csproj index 3f1036e6ff2..7bf172ed0d0 100644 --- a/crates/bindings-csharp/Codegen/Codegen.csproj +++ b/crates/bindings-csharp/Codegen/Codegen.csproj @@ -1,5 +1,4 @@ - SpacetimeDB.Codegen 1.11.0 @@ -42,7 +41,9 @@ - + - diff --git a/crates/bindings-csharp/Codegen/Diag.cs b/crates/bindings-csharp/Codegen/Diag.cs index 6b87a4028b0..e96a4b4e25d 100644 --- a/crates/bindings-csharp/Codegen/Diag.cs +++ b/crates/bindings-csharp/Codegen/Diag.cs @@ -7,161 +7,149 @@ internal static class ErrorDescriptor { private static readonly ErrorDescriptorGroup group = new("STDB", "SpacetimeDB"); - public static readonly ErrorDescriptor ReducerReturnType = - new( - group, - "[SpacetimeDB.Reducer] methods must return void", - method => - $"Reducer method {method.Identifier} returns {method.ReturnType} instead of void.", - method => method.ReturnType - ); - - public static readonly ErrorDescriptor AutoIncNotInteger = - new( - group, - "AutoInc fields must be of integer type", - field => - $"Field {field.Name} is marked as AutoInc but it has a non-integer type {field.Type}.", - field => field - ); - - public static readonly ErrorDescriptor UniqueNotEquatable = - new( - group, - "Unique fields must be equatable", - field => - $"Field {field.Name} is marked as Unique but it has a type {field.Type} which is not an equatable primitive.", - field => field - ); - - public static readonly ErrorDescriptor EmptyIndexColumns = - new( - group, - "Index attribute must specify Columns", - _ => $"Index attribute doesn't specify columns.", - attr => attr - ); - - public static readonly ErrorDescriptor InvalidTableVisibility = - new( - group, - "Table row visibility must be public or internal", - table => $"Table {table.Identifier} and its parent types must be public or internal.", - table => table.Identifier - ); - - public static readonly ErrorDescriptor TableTaggedEnum = - new( - group, - "Tables cannot be tagged enums", - table => $"Table {table.Identifier} is a tagged enum, which is not allowed.", - table => table.BaseList! - ); + public static readonly ErrorDescriptor ReducerReturnType = new( + group, + "[SpacetimeDB.Reducer] methods must return void", + method => + $"Reducer method {method.Identifier} returns {method.ReturnType} instead of void.", + method => method.ReturnType + ); + + public static readonly ErrorDescriptor AutoIncNotInteger = new( + group, + "AutoInc fields must be of integer type", + field => + $"Field {field.Name} is marked as AutoInc but it has a non-integer type {field.Type}.", + field => field + ); + + public static readonly ErrorDescriptor UniqueNotEquatable = new( + group, + "Unique fields must be equatable", + field => + $"Field {field.Name} is marked as Unique but it has a type {field.Type} which is not an equatable primitive.", + field => field + ); + + public static readonly ErrorDescriptor EmptyIndexColumns = new( + group, + "Index attribute must specify Columns", + _ => $"Index attribute doesn't specify columns.", + attr => attr + ); + + public static readonly ErrorDescriptor InvalidTableVisibility = new( + group, + "Table row visibility must be public or internal", + table => $"Table {table.Identifier} and its parent types must be public or internal.", + table => table.Identifier + ); + + public static readonly ErrorDescriptor TableTaggedEnum = new( + group, + "Tables cannot be tagged enums", + table => $"Table {table.Identifier} is a tagged enum, which is not allowed.", + table => table.BaseList! + ); public static readonly ErrorDescriptor<( string kind, string exportName, IEnumerable fullNames - )> DuplicateExport = - new( - group, - "Duplicate exports", - ctx => - $"{ctx.kind} with the same export name {ctx.exportName} is registered in multiple places: {string.Join(", ", ctx.fullNames)}", - ctx => Location.None - ); - - public static readonly ErrorDescriptor ReducerContextParam = - new( - group, - "Reducers must have a first argument of type ReducerContext", - method => - $"Reducer method {method.Identifier} does not have a ReducerContext parameter.", - method => method.ParameterList - ); - - public static readonly ErrorDescriptor ProcedureContextParam = - new( - group, - "Procedures must have a first argument of type ProcedureContext", - method => - $"Procedure method {method.Identifier} does not have a ProcedureContext parameter.", - method => method.ParameterList - ); + )> DuplicateExport = new( + group, + "Duplicate exports", + ctx => + $"{ctx.kind} with the same export name {ctx.exportName} is registered in multiple places: {string.Join(", ", ctx.fullNames)}", + ctx => Location.None + ); + + public static readonly ErrorDescriptor ReducerContextParam = new( + group, + "Reducers must have a first argument of type ReducerContext", + method => $"Reducer method {method.Identifier} does not have a ReducerContext parameter.", + method => method.ParameterList + ); + + public static readonly ErrorDescriptor ProcedureContextParam = new( + group, + "Procedures must have a first argument of type ProcedureContext", + method => + $"Procedure method {method.Identifier} does not have a ProcedureContext parameter.", + method => method.ParameterList + ); public static readonly ErrorDescriptor<( MethodDeclarationSyntax method, string prefix - )> ReducerReservedPrefix = - new( - group, - "Reducer method has a reserved name prefix", - ctx => - $"Reducer method {ctx.method.Identifier} starts with '{ctx.prefix}', which is a reserved prefix.", - ctx => ctx.method.Identifier - ); + )> ReducerReservedPrefix = new( + group, + "Reducer method has a reserved name prefix", + ctx => + $"Reducer method {ctx.method.Identifier} starts with '{ctx.prefix}', which is a reserved prefix.", + ctx => ctx.method.Identifier + ); public static readonly ErrorDescriptor<( MethodDeclarationSyntax method, string prefix - )> ProcedureReservedPrefix = - new( - group, - "Procedure method has a reserved name prefix", - ctx => - $"Procedure method {ctx.method.Identifier} starts with '{ctx.prefix}', which is a reserved prefix.", - ctx => ctx.method.Identifier - ); + )> ProcedureReservedPrefix = new( + group, + "Procedure method has a reserved name prefix", + ctx => + $"Procedure method {ctx.method.Identifier} starts with '{ctx.prefix}', which is a reserved prefix.", + ctx => ctx.method.Identifier + ); public static readonly UnusedErrorDescriptor IncompatibleTableSchedule = new(group); public static readonly ErrorDescriptor<( ReducerKind kind, IEnumerable fullNames - )> DuplicateSpecialReducer = - new( - group, - "Multiple reducers of the same kind", - ctx => - $"Several reducers are assigned to the same lifecycle kind {ctx.kind}: {string.Join(", ", ctx.fullNames)}", - ctx => Location.None - ); + )> DuplicateSpecialReducer = new( + group, + "Multiple reducers of the same kind", + ctx => + $"Several reducers are assigned to the same lifecycle kind {ctx.kind}: {string.Join(", ", ctx.fullNames)}", + ctx => Location.None + ); public static readonly ErrorDescriptor<( AttributeData attr, string message - )> InvalidScheduledDeclaration = - new(group, "Invalid scheduled table declaration", ctx => $"{ctx.message}", ctx => ctx.attr); - - public static readonly ErrorDescriptor UnexpectedIndexColumns = - new( - group, - "Index attribute on a field must not specify Columns", - _ => - $"Index attribute on a field applies directly to that field, so it doesn't accept the Columns parameter.", - attr => attr - ); + )> InvalidScheduledDeclaration = new( + group, + "Invalid scheduled table declaration", + ctx => $"{ctx.message}", + ctx => ctx.attr + ); + + public static readonly ErrorDescriptor UnexpectedIndexColumns = new( + group, + "Index attribute on a field must not specify Columns", + _ => + $"Index attribute on a field applies directly to that field, so it doesn't accept the Columns parameter.", + attr => attr + ); public static readonly ErrorDescriptor<( AttributeData attr, string columnName, string typeName - )> UnknownColumn = - new( - group, - "Unknown column", - ctx => $"Could not find the specified column {ctx.columnName} in {ctx.typeName}.", - ctx => ctx.attr - ); - - public static readonly ErrorDescriptor ClientVisibilityNotFilter = - new( - group, - "ClientVisibilityFilters must be Filters", - field => - $"Field {field.Name} is marked as ClientVisibilityFilter but it has type {field.Type} which is not SpacetimeDB.Filter", - field => field - ); + )> UnknownColumn = new( + group, + "Unknown column", + ctx => $"Could not find the specified column {ctx.columnName} in {ctx.typeName}.", + ctx => ctx.attr + ); + + public static readonly ErrorDescriptor ClientVisibilityNotFilter = new( + group, + "ClientVisibilityFilters must be Filters", + field => + $"Field {field.Name} is marked as ClientVisibilityFilter but it has type {field.Type} which is not SpacetimeDB.Filter", + field => field + ); public static readonly ErrorDescriptor ClientVisibilityNotPublicStaticReadonly = new( @@ -181,62 +169,55 @@ string typeName field => field ); - public static readonly ErrorDescriptor InvalidDefaultValueType = - new( - group, - "Invalid Default Value Type", - field => $"Default value for field {field.Name} cannot be converted to provided type", - field => field - ); - - public static readonly ErrorDescriptor InvalidDefaultValueFormat = - new( - group, - "Invalid Default Value Format", - field => $"Default value for field {field.Name} has invalid format for provided type ", - field => field - ); - public static readonly ErrorDescriptor ViewContextParam = - new( - group, - "Views must start with ViewContext or AnonymousViewContext", - method => - $"View method {method.Identifier} must have a first parameter of type ViewContext or AnonymousViewContext.", - method => method.ParameterList - ); - - public static readonly ErrorDescriptor ViewMustHaveName = - new( - group, - "Views must have an explicit name.", - method => $"View '{method.Identifier}' must have an explicit name.", - method => method - ); - public static readonly ErrorDescriptor ViewInvalidReturn = - new( - group, - "Views must return Vec or Option", - method => $"View '{method.Identifier}' must return Vec or Option.", - method => method - ); + public static readonly ErrorDescriptor InvalidDefaultValueType = new( + group, + "Invalid Default Value Type", + field => $"Default value for field {field.Name} cannot be converted to provided type", + field => field + ); + + public static readonly ErrorDescriptor InvalidDefaultValueFormat = new( + group, + "Invalid Default Value Format", + field => $"Default value for field {field.Name} has invalid format for provided type ", + field => field + ); + public static readonly ErrorDescriptor ViewContextParam = new( + group, + "Views must start with ViewContext or AnonymousViewContext", + method => + $"View method {method.Identifier} must have a first parameter of type ViewContext or AnonymousViewContext.", + method => method.ParameterList + ); + + public static readonly ErrorDescriptor ViewMustHaveName = new( + group, + "Views must have an explicit name.", + method => $"View '{method.Identifier}' must have an explicit name.", + method => method + ); + public static readonly ErrorDescriptor ViewInvalidReturn = new( + group, + "Views must return Vec or Option", + method => $"View '{method.Identifier}' must return Vec or Option.", + method => method + ); // TODO: Remove once Views support Private: Views must be Public currently - public static readonly ErrorDescriptor ViewMustBePublic = - new( - group, - "Views must be public", - method => - $"View '{method.Identifier}' must have Public = true. Views are always public in SpacetimeDB.", - method => method - ); + public static readonly ErrorDescriptor ViewMustBePublic = new( + group, + "Views must be public", + method => + $"View '{method.Identifier}' must have Public = true. Views are always public in SpacetimeDB.", + method => method + ); // TODO: Remove once Views support arguments: Views must have no arguments beyond the context. - public static readonly ErrorDescriptor ViewArgsUnsupported = - new( - group, - "Views must have no arguments beyond the context.", - method => - $"View '{method.Identifier}' must have no arguments beyond the context. This is a temporary limitation.", - method => method - ); + public static readonly ErrorDescriptor ViewArgsUnsupported = new( + group, + "Views must have no arguments beyond the context.", + method => + $"View '{method.Identifier}' must have no arguments beyond the context. This is a temporary limitation.", + method => method + ); } diff --git a/crates/bindings-csharp/Codegen/Module.cs b/crates/bindings-csharp/Codegen/Module.cs index bc31b94c6bf..03dea0e4c93 100644 --- a/crates/bindings-csharp/Codegen/Module.cs +++ b/crates/bindings-csharp/Codegen/Module.cs @@ -557,7 +557,7 @@ public ulong Delete({{argsScalar}}) => public ulong Delete({{argsBounds}}) => DoDelete(new SpacetimeDB.Internal.BTreeIndexBounds<{{types}}>({{argName}})); - + """; } @@ -1268,25 +1268,20 @@ public string GenerateClass() "return output.ToArray();", }; - bodyLines = - new[] - { - $"var outcome = {invocation};", - "if (!outcome.IsSuccess)", - "{", - " throw outcome.Error ?? new System.InvalidOperationException(\"Transaction failed.\");", - "}", - } + bodyLines = new[] + { + $"var outcome = {invocation};", + "if (!outcome.IsSuccess)", + "{", + " throw outcome.Error ?? new System.InvalidOperationException(\"Transaction failed.\");", + "}", + } .Concat(successLines) .ToArray(); } else if (ReturnType.IsVoid) { - bodyLines = new[] - { - $"{invocation};", - "return System.Array.Empty();", - }; + bodyLines = new[] { $"{invocation};", "return System.Array.Empty();" }; } else { @@ -1302,14 +1297,15 @@ public string GenerateClass() } var invokeBody = string.Join("\n", bodyLines.Select(line => $" {line}")); - var paramReads = Args.Length == 0 - ? string.Empty - : string.Join( - "\n", - Args.Select(a => - $" var {a.Name} = {a.Name}{TypeUse.BsatnFieldSuffix}.Read(reader);" - ) - ) + "\n"; + var paramReads = + Args.Length == 0 + ? string.Empty + : string.Join( + "\n", + Args.Select(a => + $" var {a.Name} = {a.Name}{TypeUse.BsatnFieldSuffix}.Read(reader);" + ) + ) + "\n"; var returnTypeExpr = hasTxWrapper ? ( @@ -1331,20 +1327,20 @@ public string GenerateClass() } return $$$""" - class {{{Name}}} : SpacetimeDB.Internal.IProcedure { - {{{classFields}}} - - public SpacetimeDB.Internal.RawProcedureDefV9 MakeProcedureDef(SpacetimeDB.BSATN.ITypeRegistrar registrar) => new( - nameof({{{Name}}}), - [{{{MemberDeclaration.GenerateDefs(Args)}}}], - {{{returnTypeExpr}}} - ); - - public byte[] Invoke(BinaryReader reader, SpacetimeDB.Internal.IProcedureContext ctx) { - {{{paramReads}}}{{{invokeBody}}} - } - } - """; + class {{{Name}}} : SpacetimeDB.Internal.IProcedure { + {{{classFields}}} + + public SpacetimeDB.Internal.RawProcedureDefV9 MakeProcedureDef(SpacetimeDB.BSATN.ITypeRegistrar registrar) => new( + nameof({{{Name}}}), + [{{{MemberDeclaration.GenerateDefs(Args)}}}], + {{{returnTypeExpr}}} + ); + + public byte[] Invoke(BinaryReader reader, SpacetimeDB.Internal.IProcedureContext ctx) { + {{{paramReads}}}{{{invokeBody}}} + } + } + """; } public Scope.Extensions GenerateSchedule() @@ -1375,16 +1371,17 @@ public Scope.Extensions GenerateSchedule() return extensions; } - + private bool TryGetTxOutcomeType(out TypeUse payloadType) { if ( - _returnTypeSymbol is INamedTypeSymbol - { - Name: "TxOutcome", - ContainingType: { Name: "ProcedureContext" } - } named && - named.TypeArguments.Length == 1 + _returnTypeSymbol + is INamedTypeSymbol + { + Name: "TxOutcome", + ContainingType: { Name: "ProcedureContext" } + } named + && named.TypeArguments.Length == 1 ) { payloadType = TypeUse.Parse(_methodSymbol, named.TypeArguments[0], _diag); @@ -1398,12 +1395,13 @@ _returnTypeSymbol is INamedTypeSymbol private bool TryGetTxResultTypes(out TypeUse payloadType, out TypeUse errorType) { if ( - _returnTypeSymbol is INamedTypeSymbol - { - Name: "TxResult", - ContainingType: { Name: "ProcedureContext" } - } named && - named.TypeArguments.Length == 2 + _returnTypeSymbol + is INamedTypeSymbol + { + Name: "TxResult", + ContainingType: { Name: "ProcedureContext" } + } named + && named.TypeArguments.Length == 2 ) { payloadType = TypeUse.Parse(_methodSymbol, named.TypeArguments[0], _diag); diff --git a/crates/bindings-csharp/Runtime.Tests/Runtime.Tests.csproj b/crates/bindings-csharp/Runtime.Tests/Runtime.Tests.csproj index d5cb92f3a77..139122ac391 100644 --- a/crates/bindings-csharp/Runtime.Tests/Runtime.Tests.csproj +++ b/crates/bindings-csharp/Runtime.Tests/Runtime.Tests.csproj @@ -1,5 +1,4 @@ - net8.0 enable @@ -20,8 +19,7 @@ - - + + - diff --git a/crates/bindings-csharp/Runtime/Exceptions.cs b/crates/bindings-csharp/Runtime/Exceptions.cs index e6cd7ceacbf..a7a3cf8b09d 100644 --- a/crates/bindings-csharp/Runtime/Exceptions.cs +++ b/crates/bindings-csharp/Runtime/Exceptions.cs @@ -77,7 +77,8 @@ public class AutoIncOverflowException : StdbException public override string Message => "The auto-increment sequence overflowed"; } -public class TransactionWouldBlockException : StdbException { +public class TransactionWouldBlockException : StdbException +{ public override string Message => "Attempted operation while another transaction is open"; } @@ -91,7 +92,8 @@ public class TransactionIsReadOnlyException : StdbException public override string Message => "The transaction is read-only"; } -public class TransactionIsMutableException : StdbException { +public class TransactionIsMutableException : StdbException +{ public override string Message => "ABI call can only be made while inside a read-only transaction"; } diff --git a/crates/bindings-csharp/Runtime/Internal/FFI.cs b/crates/bindings-csharp/Runtime/Internal/FFI.cs index a5e3b1e612b..7407d867ef8 100644 --- a/crates/bindings-csharp/Runtime/Internal/FFI.cs +++ b/crates/bindings-csharp/Runtime/Internal/FFI.cs @@ -40,7 +40,7 @@ public enum Errno : short WOULD_BLOCK_TRANSACTION = 17, TRANSACTION_NOT_ANONYMOUS = 18, TRANSACTION_IS_READ_ONLY = 19, - TRANSACTION_IS_MUT = 20, + TRANSACTION_IS_MUT = 20, } #pragma warning disable IDE1006 // Naming Styles - Not applicable to FFI stuff. @@ -72,7 +72,7 @@ internal static partial class FFI "bindings" #endif ; - + const string StdbNamespace10_3 = #if EXPERIMENTAL_WASM_AOT "spacetime_10.3" @@ -103,7 +103,7 @@ public static CheckedStatus ConvertToManaged(Errno status) } } } - + internal static class ErrnoHelpers { public static void ThrowIfError(Errno status) @@ -116,27 +116,28 @@ public static void ThrowIfError(Errno status) throw ToException(status); } - public static Exception ToException(Errno status) => status switch - { - Errno.NOT_IN_TRANSACTION => new NotInTransactionException(), - Errno.BSATN_DECODE_ERROR => new BsatnDecodeException(), - Errno.NO_SUCH_TABLE => new NoSuchTableException(), - Errno.NO_SUCH_INDEX => new NoSuchIndexException(), - Errno.NO_SUCH_ITER => new NoSuchIterException(), - Errno.NO_SUCH_CONSOLE_TIMER => new NoSuchLogStopwatch(), - Errno.NO_SUCH_BYTES => new NoSuchBytesException(), - Errno.NO_SPACE => new NoSpaceException(), - Errno.BUFFER_TOO_SMALL => new BufferTooSmallException(), - Errno.UNIQUE_ALREADY_EXISTS => new UniqueConstraintViolationException(), - Errno.INDEX_NOT_UNIQUE => new IndexNotUniqueException(), - Errno.NO_SUCH_ROW => new NoSuchRowException(), - Errno.AUTO_INC_OVERFLOW => new AutoIncOverflowException(), - Errno.WOULD_BLOCK_TRANSACTION => new TransactionWouldBlockException(), - Errno.TRANSACTION_NOT_ANONYMOUS => new TransactionNotAnonymousException(), - Errno.TRANSACTION_IS_READ_ONLY => new TransactionIsReadOnlyException(), - Errno.TRANSACTION_IS_MUT => new TransactionIsMutableException(), - _ => new UnknownException(status), - }; + public static Exception ToException(Errno status) => + status switch + { + Errno.NOT_IN_TRANSACTION => new NotInTransactionException(), + Errno.BSATN_DECODE_ERROR => new BsatnDecodeException(), + Errno.NO_SUCH_TABLE => new NoSuchTableException(), + Errno.NO_SUCH_INDEX => new NoSuchIndexException(), + Errno.NO_SUCH_ITER => new NoSuchIterException(), + Errno.NO_SUCH_CONSOLE_TIMER => new NoSuchLogStopwatch(), + Errno.NO_SUCH_BYTES => new NoSuchBytesException(), + Errno.NO_SPACE => new NoSpaceException(), + Errno.BUFFER_TOO_SMALL => new BufferTooSmallException(), + Errno.UNIQUE_ALREADY_EXISTS => new UniqueConstraintViolationException(), + Errno.INDEX_NOT_UNIQUE => new IndexNotUniqueException(), + Errno.NO_SUCH_ROW => new NoSuchRowException(), + Errno.AUTO_INC_OVERFLOW => new AutoIncOverflowException(), + Errno.WOULD_BLOCK_TRANSACTION => new TransactionWouldBlockException(), + Errno.TRANSACTION_NOT_ANONYMOUS => new TransactionNotAnonymousException(), + Errno.TRANSACTION_IS_READ_ONLY => new TransactionIsReadOnlyException(), + Errno.TRANSACTION_IS_MUT => new TransactionIsMutableException(), + _ => new UnknownException(status), + }; } [StructLayout(LayoutKind.Sequential)] @@ -345,7 +346,7 @@ uint args_len [DllImport(StdbNamespace10_2)] public static extern Errno get_jwt(ref ConnectionId connectionId, out BytesSource source); - + [LibraryImport(StdbNamespace10_3, EntryPoint = "procedure_start_mut_tx")] public static partial Errno procedure_start_mut_tx(out long micros); @@ -354,7 +355,7 @@ uint args_len [LibraryImport(StdbNamespace10_3, EntryPoint = "procedure_abort_mut_tx")] public static partial CheckedStatus procedure_abort_mut_tx(); - + [LibraryImport(StdbNamespace10_3, EntryPoint = "__take_procedure_tx_offset__")] [return: MarshalAs(UnmanagedType.I1)] public static partial bool take_procedure_tx_offset(out ulong offset); diff --git a/crates/bindings-csharp/Runtime/Internal/ITable.cs b/crates/bindings-csharp/Runtime/Internal/ITable.cs index 575c3a9fc10..146358b4243 100644 --- a/crates/bindings-csharp/Runtime/Internal/ITable.cs +++ b/crates/bindings-csharp/Runtime/Internal/ITable.cs @@ -34,8 +34,7 @@ public bool MoveNext() // Iterator advanced and may also be `EXHAUSTED`. // When `OK`, we'll need to advance the iterator in the next call to `MoveNext`. // In both cases, copy over the row data to `Current` from the scratch `buffer`. - case Errno.EXHAUSTED - or Errno.OK: + case Errno.EXHAUSTED or Errno.OK: Current = new byte[buffer_len]; Array.Copy(buffer, 0, Current, 0, buffer_len); return buffer_len != 0; @@ -112,13 +111,12 @@ protected override void IterStart(out FFI.RowIter handle) => private static readonly string tableName = typeof(View).Name; // Note: this must be Lazy to ensure that we don't try to get the tableId during startup, before the module is initialized. - private static readonly Lazy tableId_ = - new(() => - { - var name_bytes = System.Text.Encoding.UTF8.GetBytes(tableName); - FFI.table_id_from_name(name_bytes, (uint)name_bytes.Length, out var out_); - return out_; - }); + private static readonly Lazy tableId_ = new(() => + { + var name_bytes = System.Text.Encoding.UTF8.GetBytes(tableName); + FFI.table_id_from_name(name_bytes, (uint)name_bytes.Length, out var out_); + return out_; + }); internal static FFI.TableId tableId => tableId_.Value; diff --git a/crates/bindings-csharp/Runtime/Internal/Module.cs b/crates/bindings-csharp/Runtime/Internal/Module.cs index b2937db24ed..9f43c463b5a 100644 --- a/crates/bindings-csharp/Runtime/Internal/Module.cs +++ b/crates/bindings-csharp/Runtime/Internal/Module.cs @@ -381,7 +381,7 @@ BytesSink resultSink return Errno.HOST_CALL_FAILURE; } } - + public static bool __take_procedure_tx_offset__(out ulong offset) { if (TakeProcedureTxOffset() is { } tx) diff --git a/crates/bindings-csharp/Runtime/Internal/Procedure.cs b/crates/bindings-csharp/Runtime/Internal/Procedure.cs index a11b7ff96ab..37cfd487f5b 100644 --- a/crates/bindings-csharp/Runtime/Internal/Procedure.cs +++ b/crates/bindings-csharp/Runtime/Internal/Procedure.cs @@ -21,9 +21,8 @@ internal static IDisposable PushContext(IProcedureContext ctx) => new ContextScope(ctx as IInternalProcedureContext); private static IInternalProcedureContext RequireContext() => - current.Value ?? throw new InvalidOperationException( - "Transaction syscalls require a procedure context." - ); + current.Value + ?? throw new InvalidOperationException("Transaction syscalls require a procedure context."); public static long StartMutTx() { @@ -45,7 +44,7 @@ public static void CommitMutTx() Module.RecordProcedureTxOffset(offset); } } - + public static void AbortMutTx() { FFI.procedure_abort_mut_tx(); // throws on error @@ -84,14 +83,16 @@ public static bool CommitMutTxWithRetry(Func retryBody) } catch (StdbException) { - if (retryBody()) { + Log.Warn("Committing anonymous transaction failed; retrying once."); + if (retryBody()) + { CommitMutTx(); return true; } return false; } } - + public static async Task CommitMutTxWithRetryAsync(Func> retryBody) { try @@ -105,6 +106,7 @@ public static async Task CommitMutTxWithRetryAsync(Func> retryB } catch (StdbException) { + Log.Warn("Committing anonymous transaction failed; retrying once."); if (await retryBody().ConfigureAwait(false)) { await CommitMutTxAsync().ConfigureAwait(false); @@ -133,6 +135,5 @@ public readonly struct TransactionOffset private TransactionOffset(ulong value) => Value = value; - public static TransactionOffset FromRaw(long raw) => - new(unchecked((ulong)raw)); + public static TransactionOffset FromRaw(long raw) => new(unchecked((ulong)raw)); } diff --git a/crates/bindings-csharp/Runtime/Internal/TxContext.cs b/crates/bindings-csharp/Runtime/Internal/TxContext.cs index db2589ee0cd..25bf7674edd 100644 --- a/crates/bindings-csharp/Runtime/Internal/TxContext.cs +++ b/crates/bindings-csharp/Runtime/Internal/TxContext.cs @@ -8,7 +8,8 @@ public TxContext( ConnectionId? connectionId, Timestamp timestamp, AuthCtx senderAuth, - Random rng) + Random rng + ) { Db = db; Sender = sender; @@ -27,4 +28,4 @@ public TxContext( public TxContext WithTimestamp(Timestamp ts) => new(Db, Sender, ConnectionId, ts, SenderAuth, Rng); -} \ No newline at end of file +} diff --git a/crates/bindings-csharp/Runtime/ProcedureContext.cs b/crates/bindings-csharp/Runtime/ProcedureContext.cs index e9d6c006d44..11fe27743b2 100644 --- a/crates/bindings-csharp/Runtime/ProcedureContext.cs +++ b/crates/bindings-csharp/Runtime/ProcedureContext.cs @@ -9,7 +9,8 @@ protected ProcedureContextBase( Identity sender, ConnectionId? connectionId, Random random, - Timestamp time) + Timestamp time + ) { Sender = sender; ConnectionId = connectionId; @@ -34,7 +35,9 @@ protected ProcedureContextBase( private protected ProcedureTxContextBase RequireTxContext() { - var inner = txContext ?? throw new InvalidOperationException("Transaction context was not initialised."); + var inner = + txContext + ?? throw new InvalidOperationException("Transaction context was not initialised."); cachedUserTxContext ??= CreateTxContext(inner); cachedUserTxContext.Refresh(inner); return cachedUserTxContext; @@ -44,15 +47,22 @@ public Internal.TxContext EnterTxContext(long timestampMicros) { var timestamp = new Timestamp(timestampMicros); Timestamp = timestamp; - txContext = txContext?.WithTimestamp(timestamp) - ?? new Internal.TxContext(CreateLocal(), Sender, ConnectionId, timestamp, SenderAuth, Rng); + txContext = + txContext?.WithTimestamp(timestamp) + ?? new Internal.TxContext( + CreateLocal(), + Sender, + ConnectionId, + timestamp, + SenderAuth, + Rng + ); return txContext; } public void ExitTxContext() => txContext = null; - public void SetTransactionOffset(Internal.TransactionOffset offset) => - pendingTxOffset = offset; + public void SetTransactionOffset(Internal.TransactionOffset offset) => pendingTxOffset = offset; public bool TryTakeTransactionOffset(out Internal.TransactionOffset offset) { @@ -75,24 +85,27 @@ public TxOutcome(bool isSuccess, TResult? value, Exception? error) Value = value; Error = error; } - + public bool IsSuccess { get; } public TResult? Value { get; } public Exception? Error { get; } - - public static TxOutcome Success(TResult value) => - new(true, value, null); - - public static TxOutcome Failure(Exception error) => - new(false, default, error); - + + public static TxOutcome Success(TResult value) => new(true, value, null); + + public static TxOutcome Failure(Exception error) => new(false, default, error); + public TResult UnwrapOrThrow() => - IsSuccess ? Value! : throw (Error ?? new InvalidOperationException("Transaction failed without an error object.")); - + IsSuccess + ? Value! + : throw ( + Error + ?? new InvalidOperationException("Transaction failed without an error object.") + ); + public TResult UnwrapOrThrow(Func fallbackFactory) => IsSuccess ? Value! : throw (Error ?? fallbackFactory()); } - + public readonly struct TxResult where TError : Exception { @@ -102,40 +115,39 @@ public TxResult(bool isSuccess, TResult? value, TError? error) Value = value; Error = error; } - + public bool IsSuccess { get; } public TResult? Value { get; } public TError? Error { get; } - - public static TxResult Success(TResult value) => - new(true, value, null); - - public static TxResult Failure(TError error) => - new(false, default, error); - + + public static TxResult Success(TResult value) => new(true, value, null); + + public static TxResult Failure(TError error) => new(false, default, error); + public TResult UnwrapOrThrow() { if (IsSuccess) { return Value!; } - + if (Error is not null) { throw Error; } - + throw new InvalidOperationException("Transaction failed without an error object."); } } - + [Experimental("STDB_UNSTABLE")] public TResult WithTx(Func body) => TryWithTx(tx => TxResult.Success(body(tx))).UnwrapOrThrow(); - + [Experimental("STDB_UNSTABLE")] public TxOutcome TryWithTx( - Func> body) + Func> body + ) where TError : Exception { try @@ -150,9 +162,10 @@ public TxOutcome TryWithTx( return TxOutcome.Failure(ex); } } - + private TxResult RunWithRetry( - Func> body) + Func> body + ) where TError : Exception { var result = RunOnce(body); @@ -160,29 +173,30 @@ private TxResult RunWithRetry( { return result; } - + bool Retry() { result = RunOnce(body); return result.IsSuccess; } - + if (!SpacetimeDB.Internal.Procedure.CommitMutTxWithRetry(Retry)) { return result; } - + if (TryTakeTransactionOffset(out var offset)) { SetTransactionOffset(offset); SpacetimeDB.Internal.Module.RecordProcedureTxOffset(offset); } - + return result; } - + private TxResult RunOnce( - Func> body) + Func> body + ) where TError : Exception { _ = SpacetimeDB.Internal.Procedure.StartMutTx(); @@ -194,21 +208,21 @@ private TxResult RunOnce( guard.Disarm(); return result; } - + SpacetimeDB.Internal.Procedure.AbortMutTx(); guard.Disarm(); return result; } - + private sealed class AbortGuard : IDisposable { private readonly Action abort; private bool disarmed; - + public AbortGuard(Action abort) => this.abort = abort; - + public void Disarm() => disarmed = true; - + public void Dispose() { if (!disarmed) @@ -238,13 +252,9 @@ protected ProcedureTxContextBase(Internal.TxContext inner) public Random Rng => Inner.Rng; } -public abstract class LocalBase : Internal.Local -{ -} +public abstract class LocalBase : Internal.Local { } -public abstract class LocalReadOnlyBase : Internal.LocalReadOnly -{ -} +public abstract class LocalReadOnlyBase : Internal.LocalReadOnly { } public sealed class ProcedureContext : ProcedureContextBase { @@ -254,12 +264,12 @@ public ProcedureContext( Identity sender, ConnectionId? connectionId, Random random, - Timestamp timestamp) - : base(sender, connectionId, random, timestamp) - { - } + Timestamp timestamp + ) + : base(sender, connectionId, random, timestamp) { } protected internal override LocalBase CreateLocal() => _db; + protected override ProcedureTxContextBase CreateTxContext(Internal.TxContext inner) => _cached ??= new ProcedureTxContext(inner); @@ -269,18 +279,12 @@ protected override ProcedureTxContextBase CreateTxContext(Internal.TxContext inn public sealed class ProcedureTxContext : ProcedureTxContextBase { internal ProcedureTxContext(Internal.TxContext inner) - : base(inner) - { - } + : base(inner) { } public new Local Db => (Local)base.Db; } -public sealed class Local : LocalBase -{ -} +public sealed class Local : LocalBase { } -public sealed class LocalReadOnly : LocalReadOnlyBase -{ -} -#pragma warning restore STDB_UNSTABLE \ No newline at end of file +public sealed class LocalReadOnly : LocalReadOnlyBase { } +#pragma warning restore STDB_UNSTABLE diff --git a/crates/bindings-csharp/Runtime/Runtime.csproj b/crates/bindings-csharp/Runtime/Runtime.csproj index 3a8d576f39c..41eda180cd5 100644 --- a/crates/bindings-csharp/Runtime/Runtime.csproj +++ b/crates/bindings-csharp/Runtime/Runtime.csproj @@ -1,5 +1,4 @@ - SpacetimeDB.Runtime 1.11.0 @@ -19,7 +18,11 @@ - + @@ -31,12 +34,15 @@ - + - diff --git a/crates/bindings-csharp/Runtime/build/SpacetimeDB.Runtime.props b/crates/bindings-csharp/Runtime/build/SpacetimeDB.Runtime.props index 58ccaa0de6e..eabfed55468 100644 --- a/crates/bindings-csharp/Runtime/build/SpacetimeDB.Runtime.props +++ b/crates/bindings-csharp/Runtime/build/SpacetimeDB.Runtime.props @@ -1,5 +1,4 @@ - true full @@ -25,5 +24,4 @@ false - diff --git a/crates/bindings-csharp/Runtime/build/SpacetimeDB.Runtime.targets b/crates/bindings-csharp/Runtime/build/SpacetimeDB.Runtime.targets index 780d6f19f43..1acb0d21c26 100644 --- a/crates/bindings-csharp/Runtime/build/SpacetimeDB.Runtime.targets +++ b/crates/bindings-csharp/Runtime/build/SpacetimeDB.Runtime.targets @@ -1,5 +1,4 @@ - @@ -24,8 +23,15 @@ - - + + @@ -45,8 +51,14 @@ $([System.IO.Path]::Combine($(IntermediateOutputPath), "wasi-sdk.$(WasiSdkVersion).tar.gz")) - x86_64 - arm64 + x86_64 + arm64 windows linux @@ -62,15 +74,22 @@ + SourceUrl="$(WasiSdkUrl)" + DestinationFolder="$(IntermediateOutputPath)" + DestinationFileName="$([System.IO.Path]::GetFileName('$(WasiSdkDownloadTempFile)'))" + Condition="!Exists('$(WasiClang)')" + /> - + - + - diff --git a/sdks/csharp/examples~/regression-tests/server/Lib.cs b/sdks/csharp/examples~/regression-tests/server/Lib.cs index bd5fbca25c0..474a125ffe4 100644 --- a/sdks/csharp/examples~/regression-tests/server/Lib.cs +++ b/sdks/csharp/examples~/regression-tests/server/Lib.cs @@ -173,7 +173,7 @@ public static SpacetimeDB.Unit WillPanic(ProcedureContext ctx) { throw new InvalidOperationException("This procedure is expected to panic"); } - + #pragma warning disable STDB_UNSTABLE [SpacetimeDB.Procedure] public static void InsertWithTxCommit(ProcedureContext ctx) @@ -211,7 +211,7 @@ private static void AssertRowCount(ProcedureContext ctx, ulong expected) { ctx.WithTx(tx => { - ulong actual = tx.Db.my_table.Count; + var actual = tx.Db.my_table.Count; if (actual != expected) { throw new InvalidOperationException( From 14d310bb2a9e6a64571dabb8e4b343f86b21ac0a Mon Sep 17 00:00:00 2001 From: rekhoff Date: Thu, 4 Dec 2025 09:23:44 -0800 Subject: [PATCH 4/4] More lint updates --- crates/bindings-csharp/BSATN.Codegen/Diag.cs | 99 ++--- crates/bindings-csharp/BSATN.Codegen/Type.cs | 4 +- .../BSATN.Runtime.Tests/Tests.cs | 60 ++- .../BSATN.Runtime/BSATN/AlgebraicType.cs | 12 +- .../BSATN.Runtime/BSATN/Runtime.cs | 5 +- .../bindings-csharp/BSATN.Runtime/Builtins.cs | 48 +-- crates/bindings-csharp/Codegen/Diag.cs | 343 +++++++++--------- crates/bindings-csharp/Codegen/Module.cs | 20 +- .../Runtime/Internal/ITable.cs | 16 +- .../Runtime/Internal/TxContext.cs | 38 +- .../Runtime/ProcedureContext.cs | 91 ++--- modules/benchmarks-cs/circles.cs | 9 +- modules/benchmarks-cs/ia_loop.cs | 15 +- modules/benchmarks-cs/lib.cs | 3 +- modules/benchmarks-cs/synthetic.cs | 7 +- modules/module-test-cs/Lib.cs | 4 +- modules/sdk-test-connect-disconnect-cs/Lib.cs | 4 +- modules/sdk-test-cs/Lib.cs | 4 +- .../regression-tests/client/Program.cs | 117 ++++-- 19 files changed, 455 insertions(+), 444 deletions(-) diff --git a/crates/bindings-csharp/BSATN.Codegen/Diag.cs b/crates/bindings-csharp/BSATN.Codegen/Diag.cs index 53d0d7f2432..2ae3b2513ba 100644 --- a/crates/bindings-csharp/BSATN.Codegen/Diag.cs +++ b/crates/bindings-csharp/BSATN.Codegen/Diag.cs @@ -134,55 +134,61 @@ internal static class ErrorDescriptor ISymbol member, ITypeSymbol type, Exception e - )> UnsupportedType = new( - group, - "Unsupported type", - ctx => $"BSATN implementation for {ctx.type} is not found: {ctx.e.Message}", - ctx => ctx.member - ); + )> UnsupportedType = + new( + group, + "Unsupported type", + ctx => $"BSATN implementation for {ctx.type} is not found: {ctx.e.Message}", + ctx => ctx.member + ); public static readonly ErrorDescriptor<( EqualsValueClauseSyntax equalsValue, EnumMemberDeclarationSyntax enumMember, EnumDeclarationSyntax @enum - )> EnumWithExplicitValues = new( - group, - "[SpacetimeDB.Type] enums cannot have explicit values", - ctx => - $"{ctx.@enum.Identifier}.{ctx.enumMember.Identifier} has an explicit value {ctx.equalsValue.Value} which is not allowed in SpacetimeDB enums.", - ctx => ctx.equalsValue - ); + )> EnumWithExplicitValues = + new( + group, + "[SpacetimeDB.Type] enums cannot have explicit values", + ctx => + $"{ctx.@enum.Identifier}.{ctx.enumMember.Identifier} has an explicit value {ctx.equalsValue.Value} which is not allowed in SpacetimeDB enums.", + ctx => ctx.equalsValue + ); - public static readonly ErrorDescriptor EnumTooManyVariants = new( - group, - "[SpacetimeDB.Type] enums are limited to 256 variants", - @enum => - $"{@enum.Identifier} has {@enum.Members.Count} variants which is more than the allowed 256 variants for SpacetimeDB enums.", - @enum => @enum.Members[256] - ); + public static readonly ErrorDescriptor EnumTooManyVariants = + new( + group, + "[SpacetimeDB.Type] enums are limited to 256 variants", + @enum => + $"{@enum.Identifier} has {@enum.Members.Count} variants which is more than the allowed 256 variants for SpacetimeDB enums.", + @enum => @enum.Members[256] + ); - public static readonly ErrorDescriptor TaggedEnumInlineTuple = new( - group, - "Tagged enum variants must be declared with inline tuples", - baseType => - $"{baseType} does not have the expected format SpacetimeDB.TaggedEnum<(TVariant1 v1, ..., TVariantN vN)>.", - baseType => baseType - ); + public static readonly ErrorDescriptor TaggedEnumInlineTuple = + new( + group, + "Tagged enum variants must be declared with inline tuples", + baseType => + $"{baseType} does not have the expected format SpacetimeDB.TaggedEnum<(TVariant1 v1, ..., TVariantN vN)>.", + baseType => baseType + ); - public static readonly ErrorDescriptor TaggedEnumField = new( - group, - "Tagged enums cannot have instance fields", - field => - $"{field.Name} is an instance field, which are not permitted inside SpacetimeDB tagged enums.", - field => field - ); + public static readonly ErrorDescriptor TaggedEnumField = + new( + group, + "Tagged enums cannot have instance fields", + field => + $"{field.Name} is an instance field, which are not permitted inside SpacetimeDB tagged enums.", + field => field + ); - public static readonly ErrorDescriptor TypeParams = new( - group, - "Type parameters are not yet supported", - typeParams => $"Type parameters {typeParams} are not supported in SpacetimeDB types.", - typeParams => typeParams - ); + public static readonly ErrorDescriptor TypeParams = + new( + group, + "Type parameters are not yet supported", + typeParams => $"Type parameters {typeParams} are not supported in SpacetimeDB types.", + typeParams => typeParams + ); } // This class is used to collect diagnostics during parsing and return them as a combined result. @@ -208,12 +214,13 @@ public void Report(ErrorDescriptor descriptor, TContext ctx) private DiagReporter() { } - private static readonly ErrorDescriptor<(Location location, Exception e)> InternalError = new( - new("STDBINT", "SpacetimeDB.Internal"), - "Internal SpacetimeDB codegen error", - ctx => $"An internal error occurred during codegen: {ctx.e.Message}", - ctx => ctx.location - ); + private static readonly ErrorDescriptor<(Location location, Exception e)> InternalError = + new( + new("STDBINT", "SpacetimeDB.Internal"), + "Internal SpacetimeDB codegen error", + ctx => $"An internal error occurred during codegen: {ctx.e.Message}", + ctx => ctx.location + ); public static ParseResult With(Location location, Func build) where T : IEquatable diff --git a/crates/bindings-csharp/BSATN.Codegen/Type.cs b/crates/bindings-csharp/BSATN.Codegen/Type.cs index 9d8ad56f26f..56c4af41f07 100644 --- a/crates/bindings-csharp/BSATN.Codegen/Type.cs +++ b/crates/bindings-csharp/BSATN.Codegen/Type.cs @@ -516,7 +516,7 @@ public sealed record {{m.Name}}({{m.Type.Name}} {{m.Name}}_) : {{ShortName}} public override string ToString() => $"{{m.Name}}({ SpacetimeDB.BSATN.StringUtil.GenericToString({{m.Name}}_) })"; } - + """ ) ) @@ -659,7 +659,7 @@ public override int GetHashCode() { {{getHashCode}} } - + """ ); diff --git a/crates/bindings-csharp/BSATN.Runtime.Tests/Tests.cs b/crates/bindings-csharp/BSATN.Runtime.Tests/Tests.cs index bee26979774..c3e26ddb09b 100644 --- a/crates/bindings-csharp/BSATN.Runtime.Tests/Tests.cs +++ b/crates/bindings-csharp/BSATN.Runtime.Tests/Tests.cs @@ -137,8 +137,8 @@ public static void IdentityLengthCheck() public static void NonHexStrings() { // n.b. 32 chars long - Assert.ThrowsAny(() => - ConnectionId.FromHexString("these are not hex characters....") + Assert.ThrowsAny( + () => ConnectionId.FromHexString("these are not hex characters....") ); } @@ -246,20 +246,12 @@ public BasicDataClass((int x, string y, int? z, string? w) data) } [Type] - public partial struct BasicDataStruct + public partial struct BasicDataStruct((int x, string y, int? z, string? w) data) { - public int X; - public string Y; - public int? Z; - public string? W; - - public BasicDataStruct((int x, string y, int? z, string? w) data) - { - X = data.x; - Y = data.y; - Z = data.z; - W = data.w; - } + public int X = data.x; + public string Y = data.y; + public int? Z = data.z; + public string? W = data.w; } [Type] @@ -315,12 +307,12 @@ public void Add(bool collides) } } - public double CollisionFraction + public readonly double CollisionFraction { get => (double)Collisions / (double)Comparisons; } - public void AssertCollisionsLessThan(double fraction) + public readonly void AssertCollisionsLessThan(double fraction) { Assert.True( CollisionFraction < fraction, @@ -629,14 +621,10 @@ public static void GeneratedNestedListRoundTrip() static readonly Gen<(ContainsNestedList e1, ContainsNestedList e2)> GenTwoContainsNestedList = Gen.Select(GenContainsNestedList, GenContainsNestedList, (e1, e2) => (e1, e2)); - class EnumerableEqualityComparer : EqualityComparer> + class EnumerableEqualityComparer(EqualityComparer equalityComparer) + : EqualityComparer> { - private readonly EqualityComparer EqualityComparer; - - public EnumerableEqualityComparer(EqualityComparer equalityComparer) - { - EqualityComparer = equalityComparer; - } + private readonly EqualityComparer EqualityComparer = equalityComparer; public override bool Equals(IEnumerable? x, IEnumerable? y) => x == null ? y == null : (y == null ? false : x.SequenceEqual(y, EqualityComparer)); @@ -796,22 +784,26 @@ public static void GeneratedToString() ); Assert.Equal( "ContainsList { TheList = [ X(1), Y(\"hi\"), W(BasicDataRecord { X = 1, Y = \"hi\", Z = null, W = null }) ] }", - new ContainsList([ - new BasicEnum.X(1), - new BasicEnum.Y("hi"), - new BasicEnum.W(new BasicDataRecord((1, "hi", null, null))), - ]).ToString() + new ContainsList( + [ + new BasicEnum.X(1), + new BasicEnum.Y("hi"), + new BasicEnum.W(new BasicDataRecord((1, "hi", null, null))), + ] + ).ToString() ); #pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. Assert.Equal( "ContainsNestedList { TheList = [ [ [ X(1), null ], null ], null ] }", - new ContainsNestedList([ + new ContainsNestedList( [ - [new BasicEnum.X(1), null], + [ + [new BasicEnum.X(1), null], + null, + ], null, - ], - null, - ]).ToString() + ] + ).ToString() ); #pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type. } diff --git a/crates/bindings-csharp/BSATN.Runtime/BSATN/AlgebraicType.cs b/crates/bindings-csharp/BSATN.Runtime/BSATN/AlgebraicType.cs index 603feae5c78..602afa7af5f 100644 --- a/crates/bindings-csharp/BSATN.Runtime/BSATN/AlgebraicType.cs +++ b/crates/bindings-csharp/BSATN.Runtime/BSATN/AlgebraicType.cs @@ -6,17 +6,11 @@ public interface ITypeRegistrar } [SpacetimeDB.Type] -public partial struct AggregateElement +public partial struct AggregateElement(string name, AlgebraicType algebraicType) { - public string? Name; + public string? Name = name; - public AlgebraicType AlgebraicType; - - public AggregateElement(string name, AlgebraicType algebraicType) - { - Name = name; - AlgebraicType = algebraicType; - } + public AlgebraicType AlgebraicType = algebraicType; } [SpacetimeDB.Type] diff --git a/crates/bindings-csharp/BSATN.Runtime/BSATN/Runtime.cs b/crates/bindings-csharp/BSATN.Runtime/BSATN/Runtime.cs index bde8ac8bbd7..9a7a617a2ab 100644 --- a/crates/bindings-csharp/BSATN.Runtime/BSATN/Runtime.cs +++ b/crates/bindings-csharp/BSATN.Runtime/BSATN/Runtime.cs @@ -577,9 +577,8 @@ public AlgebraicType GetAlgebraicType(ITypeRegistrar registrar) => // reduce amount of noisy compilation errors when a used type is not supported by BSATN. public readonly struct Unsupported : IReadWrite { - private static readonly NotSupportedException Exception = new( - $"Type {typeof(T)} is not supported by BSATN." - ); + private static readonly NotSupportedException Exception = + new($"Type {typeof(T)} is not supported by BSATN."); public T Read(BinaryReader reader) => throw Exception; diff --git a/crates/bindings-csharp/BSATN.Runtime/Builtins.cs b/crates/bindings-csharp/BSATN.Runtime/Builtins.cs index d2ba774bd1c..8a8aa783a5c 100644 --- a/crates/bindings-csharp/BSATN.Runtime/Builtins.cs +++ b/crates/bindings-csharp/BSATN.Runtime/Builtins.cs @@ -191,10 +191,12 @@ public void Write(BinaryWriter writer, ConnectionId value) => // --- customized --- public AlgebraicType GetAlgebraicType(ITypeRegistrar registrar) => // Return a Product directly, not a Ref, because this is a special type. - new AlgebraicType.Product([ - // Using this specific name here is important. - new("__connection_id__", new AlgebraicType.U128(default)), - ]); + new AlgebraicType.Product( + [ + // Using this specific name here is important. + new("__connection_id__", new AlgebraicType.U128(default)), + ] + ); // --- / customized --- } @@ -281,10 +283,12 @@ public void Write(BinaryWriter writer, Identity value) => // --- customized --- public AlgebraicType GetAlgebraicType(ITypeRegistrar registrar) => // Return a Product directly, not a Ref, because this is a special type. - new AlgebraicType.Product([ - // Using this specific name here is important. - new("__identity__", new AlgebraicType.U256(default)), - ]); + new AlgebraicType.Product( + [ + // Using this specific name here is important. + new("__identity__", new AlgebraicType.U256(default)), + ] + ); // --- / customized --- } @@ -361,7 +365,7 @@ public readonly TimeDuration TimeDurationSince(Timestamp earlier) => public static Timestamp operator -(Timestamp point, TimeDuration interval) => new Timestamp(checked(point.MicrosecondsSinceUnixEpoch - interval.Microseconds)); - public int CompareTo(Timestamp that) + public readonly int CompareTo(Timestamp that) { return this.MicrosecondsSinceUnixEpoch.CompareTo(that.MicrosecondsSinceUnixEpoch); } @@ -410,10 +414,9 @@ public void Write(BinaryWriter writer, Timestamp value) public AlgebraicType GetAlgebraicType(ITypeRegistrar registrar) => // Return a Product directly, not a Ref, because this is a special type. new AlgebraicType.Product( - // Using this specific name here is important. - [ - new("__timestamp_micros_since_unix_epoch__", new AlgebraicType.I64(default)), - ]); + // Using this specific name here is important. + [new("__timestamp_micros_since_unix_epoch__", new AlgebraicType.I64(default))] + ); // --- / customized --- } } @@ -513,10 +516,9 @@ public void Write(BinaryWriter writer, TimeDuration value) public AlgebraicType GetAlgebraicType(ITypeRegistrar registrar) => // Return a Product directly, not a Ref, because this is a special type. new AlgebraicType.Product( - // Using this specific name here is important. - [ - new("__time_duration_micros__", new AlgebraicType.I64(default)), - ]); + // Using this specific name here is important. + [new("__time_duration_micros__", new AlgebraicType.I64(default))] + ); // --- / customized --- } } @@ -593,11 +595,13 @@ public void Write(BinaryWriter writer, ScheduleAt value) // --- customized --- public AlgebraicType GetAlgebraicType(ITypeRegistrar registrar) => // Return a Sum directly, not a Ref, because this is a special type. - new AlgebraicType.Sum([ - // Using these specific names here is important. - new("Interval", Interval.GetAlgebraicType(registrar)), - new("Time", Time.GetAlgebraicType(registrar)), - ]); + new AlgebraicType.Sum( + [ + // Using these specific names here is important. + new("Interval", Interval.GetAlgebraicType(registrar)), + new("Time", Time.GetAlgebraicType(registrar)), + ] + ); // --- / customized --- } } diff --git a/crates/bindings-csharp/Codegen/Diag.cs b/crates/bindings-csharp/Codegen/Diag.cs index e96a4b4e25d..6b87a4028b0 100644 --- a/crates/bindings-csharp/Codegen/Diag.cs +++ b/crates/bindings-csharp/Codegen/Diag.cs @@ -7,149 +7,161 @@ internal static class ErrorDescriptor { private static readonly ErrorDescriptorGroup group = new("STDB", "SpacetimeDB"); - public static readonly ErrorDescriptor ReducerReturnType = new( - group, - "[SpacetimeDB.Reducer] methods must return void", - method => - $"Reducer method {method.Identifier} returns {method.ReturnType} instead of void.", - method => method.ReturnType - ); - - public static readonly ErrorDescriptor AutoIncNotInteger = new( - group, - "AutoInc fields must be of integer type", - field => - $"Field {field.Name} is marked as AutoInc but it has a non-integer type {field.Type}.", - field => field - ); - - public static readonly ErrorDescriptor UniqueNotEquatable = new( - group, - "Unique fields must be equatable", - field => - $"Field {field.Name} is marked as Unique but it has a type {field.Type} which is not an equatable primitive.", - field => field - ); - - public static readonly ErrorDescriptor EmptyIndexColumns = new( - group, - "Index attribute must specify Columns", - _ => $"Index attribute doesn't specify columns.", - attr => attr - ); - - public static readonly ErrorDescriptor InvalidTableVisibility = new( - group, - "Table row visibility must be public or internal", - table => $"Table {table.Identifier} and its parent types must be public or internal.", - table => table.Identifier - ); - - public static readonly ErrorDescriptor TableTaggedEnum = new( - group, - "Tables cannot be tagged enums", - table => $"Table {table.Identifier} is a tagged enum, which is not allowed.", - table => table.BaseList! - ); + public static readonly ErrorDescriptor ReducerReturnType = + new( + group, + "[SpacetimeDB.Reducer] methods must return void", + method => + $"Reducer method {method.Identifier} returns {method.ReturnType} instead of void.", + method => method.ReturnType + ); + + public static readonly ErrorDescriptor AutoIncNotInteger = + new( + group, + "AutoInc fields must be of integer type", + field => + $"Field {field.Name} is marked as AutoInc but it has a non-integer type {field.Type}.", + field => field + ); + + public static readonly ErrorDescriptor UniqueNotEquatable = + new( + group, + "Unique fields must be equatable", + field => + $"Field {field.Name} is marked as Unique but it has a type {field.Type} which is not an equatable primitive.", + field => field + ); + + public static readonly ErrorDescriptor EmptyIndexColumns = + new( + group, + "Index attribute must specify Columns", + _ => $"Index attribute doesn't specify columns.", + attr => attr + ); + + public static readonly ErrorDescriptor InvalidTableVisibility = + new( + group, + "Table row visibility must be public or internal", + table => $"Table {table.Identifier} and its parent types must be public or internal.", + table => table.Identifier + ); + + public static readonly ErrorDescriptor TableTaggedEnum = + new( + group, + "Tables cannot be tagged enums", + table => $"Table {table.Identifier} is a tagged enum, which is not allowed.", + table => table.BaseList! + ); public static readonly ErrorDescriptor<( string kind, string exportName, IEnumerable fullNames - )> DuplicateExport = new( - group, - "Duplicate exports", - ctx => - $"{ctx.kind} with the same export name {ctx.exportName} is registered in multiple places: {string.Join(", ", ctx.fullNames)}", - ctx => Location.None - ); - - public static readonly ErrorDescriptor ReducerContextParam = new( - group, - "Reducers must have a first argument of type ReducerContext", - method => $"Reducer method {method.Identifier} does not have a ReducerContext parameter.", - method => method.ParameterList - ); - - public static readonly ErrorDescriptor ProcedureContextParam = new( - group, - "Procedures must have a first argument of type ProcedureContext", - method => - $"Procedure method {method.Identifier} does not have a ProcedureContext parameter.", - method => method.ParameterList - ); + )> DuplicateExport = + new( + group, + "Duplicate exports", + ctx => + $"{ctx.kind} with the same export name {ctx.exportName} is registered in multiple places: {string.Join(", ", ctx.fullNames)}", + ctx => Location.None + ); + + public static readonly ErrorDescriptor ReducerContextParam = + new( + group, + "Reducers must have a first argument of type ReducerContext", + method => + $"Reducer method {method.Identifier} does not have a ReducerContext parameter.", + method => method.ParameterList + ); + + public static readonly ErrorDescriptor ProcedureContextParam = + new( + group, + "Procedures must have a first argument of type ProcedureContext", + method => + $"Procedure method {method.Identifier} does not have a ProcedureContext parameter.", + method => method.ParameterList + ); public static readonly ErrorDescriptor<( MethodDeclarationSyntax method, string prefix - )> ReducerReservedPrefix = new( - group, - "Reducer method has a reserved name prefix", - ctx => - $"Reducer method {ctx.method.Identifier} starts with '{ctx.prefix}', which is a reserved prefix.", - ctx => ctx.method.Identifier - ); + )> ReducerReservedPrefix = + new( + group, + "Reducer method has a reserved name prefix", + ctx => + $"Reducer method {ctx.method.Identifier} starts with '{ctx.prefix}', which is a reserved prefix.", + ctx => ctx.method.Identifier + ); public static readonly ErrorDescriptor<( MethodDeclarationSyntax method, string prefix - )> ProcedureReservedPrefix = new( - group, - "Procedure method has a reserved name prefix", - ctx => - $"Procedure method {ctx.method.Identifier} starts with '{ctx.prefix}', which is a reserved prefix.", - ctx => ctx.method.Identifier - ); + )> ProcedureReservedPrefix = + new( + group, + "Procedure method has a reserved name prefix", + ctx => + $"Procedure method {ctx.method.Identifier} starts with '{ctx.prefix}', which is a reserved prefix.", + ctx => ctx.method.Identifier + ); public static readonly UnusedErrorDescriptor IncompatibleTableSchedule = new(group); public static readonly ErrorDescriptor<( ReducerKind kind, IEnumerable fullNames - )> DuplicateSpecialReducer = new( - group, - "Multiple reducers of the same kind", - ctx => - $"Several reducers are assigned to the same lifecycle kind {ctx.kind}: {string.Join(", ", ctx.fullNames)}", - ctx => Location.None - ); + )> DuplicateSpecialReducer = + new( + group, + "Multiple reducers of the same kind", + ctx => + $"Several reducers are assigned to the same lifecycle kind {ctx.kind}: {string.Join(", ", ctx.fullNames)}", + ctx => Location.None + ); public static readonly ErrorDescriptor<( AttributeData attr, string message - )> InvalidScheduledDeclaration = new( - group, - "Invalid scheduled table declaration", - ctx => $"{ctx.message}", - ctx => ctx.attr - ); - - public static readonly ErrorDescriptor UnexpectedIndexColumns = new( - group, - "Index attribute on a field must not specify Columns", - _ => - $"Index attribute on a field applies directly to that field, so it doesn't accept the Columns parameter.", - attr => attr - ); + )> InvalidScheduledDeclaration = + new(group, "Invalid scheduled table declaration", ctx => $"{ctx.message}", ctx => ctx.attr); + + public static readonly ErrorDescriptor UnexpectedIndexColumns = + new( + group, + "Index attribute on a field must not specify Columns", + _ => + $"Index attribute on a field applies directly to that field, so it doesn't accept the Columns parameter.", + attr => attr + ); public static readonly ErrorDescriptor<( AttributeData attr, string columnName, string typeName - )> UnknownColumn = new( - group, - "Unknown column", - ctx => $"Could not find the specified column {ctx.columnName} in {ctx.typeName}.", - ctx => ctx.attr - ); - - public static readonly ErrorDescriptor ClientVisibilityNotFilter = new( - group, - "ClientVisibilityFilters must be Filters", - field => - $"Field {field.Name} is marked as ClientVisibilityFilter but it has type {field.Type} which is not SpacetimeDB.Filter", - field => field - ); + )> UnknownColumn = + new( + group, + "Unknown column", + ctx => $"Could not find the specified column {ctx.columnName} in {ctx.typeName}.", + ctx => ctx.attr + ); + + public static readonly ErrorDescriptor ClientVisibilityNotFilter = + new( + group, + "ClientVisibilityFilters must be Filters", + field => + $"Field {field.Name} is marked as ClientVisibilityFilter but it has type {field.Type} which is not SpacetimeDB.Filter", + field => field + ); public static readonly ErrorDescriptor ClientVisibilityNotPublicStaticReadonly = new( @@ -169,55 +181,62 @@ string typeName field => field ); - public static readonly ErrorDescriptor InvalidDefaultValueType = new( - group, - "Invalid Default Value Type", - field => $"Default value for field {field.Name} cannot be converted to provided type", - field => field - ); - - public static readonly ErrorDescriptor InvalidDefaultValueFormat = new( - group, - "Invalid Default Value Format", - field => $"Default value for field {field.Name} has invalid format for provided type ", - field => field - ); - public static readonly ErrorDescriptor ViewContextParam = new( - group, - "Views must start with ViewContext or AnonymousViewContext", - method => - $"View method {method.Identifier} must have a first parameter of type ViewContext or AnonymousViewContext.", - method => method.ParameterList - ); - - public static readonly ErrorDescriptor ViewMustHaveName = new( - group, - "Views must have an explicit name.", - method => $"View '{method.Identifier}' must have an explicit name.", - method => method - ); - public static readonly ErrorDescriptor ViewInvalidReturn = new( - group, - "Views must return Vec or Option", - method => $"View '{method.Identifier}' must return Vec or Option.", - method => method - ); + public static readonly ErrorDescriptor InvalidDefaultValueType = + new( + group, + "Invalid Default Value Type", + field => $"Default value for field {field.Name} cannot be converted to provided type", + field => field + ); + + public static readonly ErrorDescriptor InvalidDefaultValueFormat = + new( + group, + "Invalid Default Value Format", + field => $"Default value for field {field.Name} has invalid format for provided type ", + field => field + ); + public static readonly ErrorDescriptor ViewContextParam = + new( + group, + "Views must start with ViewContext or AnonymousViewContext", + method => + $"View method {method.Identifier} must have a first parameter of type ViewContext or AnonymousViewContext.", + method => method.ParameterList + ); + + public static readonly ErrorDescriptor ViewMustHaveName = + new( + group, + "Views must have an explicit name.", + method => $"View '{method.Identifier}' must have an explicit name.", + method => method + ); + public static readonly ErrorDescriptor ViewInvalidReturn = + new( + group, + "Views must return Vec or Option", + method => $"View '{method.Identifier}' must return Vec or Option.", + method => method + ); // TODO: Remove once Views support Private: Views must be Public currently - public static readonly ErrorDescriptor ViewMustBePublic = new( - group, - "Views must be public", - method => - $"View '{method.Identifier}' must have Public = true. Views are always public in SpacetimeDB.", - method => method - ); + public static readonly ErrorDescriptor ViewMustBePublic = + new( + group, + "Views must be public", + method => + $"View '{method.Identifier}' must have Public = true. Views are always public in SpacetimeDB.", + method => method + ); // TODO: Remove once Views support arguments: Views must have no arguments beyond the context. - public static readonly ErrorDescriptor ViewArgsUnsupported = new( - group, - "Views must have no arguments beyond the context.", - method => - $"View '{method.Identifier}' must have no arguments beyond the context. This is a temporary limitation.", - method => method - ); + public static readonly ErrorDescriptor ViewArgsUnsupported = + new( + group, + "Views must have no arguments beyond the context.", + method => + $"View '{method.Identifier}' must have no arguments beyond the context. This is a temporary limitation.", + method => method + ); } diff --git a/crates/bindings-csharp/Codegen/Module.cs b/crates/bindings-csharp/Codegen/Module.cs index 03dea0e4c93..b10817e0aab 100644 --- a/crates/bindings-csharp/Codegen/Module.cs +++ b/crates/bindings-csharp/Codegen/Module.cs @@ -557,7 +557,7 @@ public ulong Delete({{argsScalar}}) => public ulong Delete({{argsBounds}}) => DoDelete(new SpacetimeDB.Internal.BTreeIndexBounds<{{types}}>({{argName}})); - + """; } @@ -1798,7 +1798,7 @@ namespace SpacetimeDB.Internal.TableHandles { {{string.Join("\n", tableAccessors.Select(v => v.tableAccessor))}} } - {{string.Join("\n", + {{string.Join("\n", views.Array.Where(v => !v.IsAnonymous) .Select((v, i) => v.GenerateDispatcherClass((uint)i)) .Concat( @@ -1851,7 +1851,7 @@ public static void Main() { // IMPORTANT: The order in which we register views matters. // It must correspond to the order in which we call `GenerateDispatcherClass`. // See the comment on `GenerateDispatcherClass` for more explanation. - {{string.Join("\n", + {{string.Join("\n", views.Array.Where(v => !v.IsAnonymous) .Select(v => $"SpacetimeDB.Internal.Module.RegisterView<{v.Name}ViewDispatcher>();") .Concat( @@ -1870,14 +1870,14 @@ public static void Main() { )}} {{string.Join( "\n", - columnDefaultValues.Select(d => + columnDefaultValues.Select(d => "{\n" - +$"var value = new {d.BSATNTypeName}();\n" - +"__memoryStream.Position = 0;\n" - +"__memoryStream.SetLength(0);\n" - +$"value.Write(__writer, {d.value});\n" - +"var array = __memoryStream.ToArray();\n" - +$"SpacetimeDB.Internal.Module.RegisterTableDefaultValue(\"{d.tableName}\", {d.columnId}, array);" + + $"var value = new {d.BSATNTypeName}();\n" + + "__memoryStream.Position = 0;\n" + + "__memoryStream.SetLength(0);\n" + + $"value.Write(__writer, {d.value});\n" + + "var array = __memoryStream.ToArray();\n" + + $"SpacetimeDB.Internal.Module.RegisterTableDefaultValue(\"{d.tableName}\", {d.columnId}, array);" + "\n}\n") )}} } diff --git a/crates/bindings-csharp/Runtime/Internal/ITable.cs b/crates/bindings-csharp/Runtime/Internal/ITable.cs index 146358b4243..575c3a9fc10 100644 --- a/crates/bindings-csharp/Runtime/Internal/ITable.cs +++ b/crates/bindings-csharp/Runtime/Internal/ITable.cs @@ -34,7 +34,8 @@ public bool MoveNext() // Iterator advanced and may also be `EXHAUSTED`. // When `OK`, we'll need to advance the iterator in the next call to `MoveNext`. // In both cases, copy over the row data to `Current` from the scratch `buffer`. - case Errno.EXHAUSTED or Errno.OK: + case Errno.EXHAUSTED + or Errno.OK: Current = new byte[buffer_len]; Array.Copy(buffer, 0, Current, 0, buffer_len); return buffer_len != 0; @@ -111,12 +112,13 @@ protected override void IterStart(out FFI.RowIter handle) => private static readonly string tableName = typeof(View).Name; // Note: this must be Lazy to ensure that we don't try to get the tableId during startup, before the module is initialized. - private static readonly Lazy tableId_ = new(() => - { - var name_bytes = System.Text.Encoding.UTF8.GetBytes(tableName); - FFI.table_id_from_name(name_bytes, (uint)name_bytes.Length, out var out_); - return out_; - }); + private static readonly Lazy tableId_ = + new(() => + { + var name_bytes = System.Text.Encoding.UTF8.GetBytes(tableName); + FFI.table_id_from_name(name_bytes, (uint)name_bytes.Length, out var out_); + return out_; + }); internal static FFI.TableId tableId => tableId_.Value; diff --git a/crates/bindings-csharp/Runtime/Internal/TxContext.cs b/crates/bindings-csharp/Runtime/Internal/TxContext.cs index 25bf7674edd..d5bea2febd9 100644 --- a/crates/bindings-csharp/Runtime/Internal/TxContext.cs +++ b/crates/bindings-csharp/Runtime/Internal/TxContext.cs @@ -1,30 +1,20 @@ namespace SpacetimeDB.Internal; -public sealed class TxContext +public sealed class TxContext( + Local db, + Identity sender, + ConnectionId? connectionId, + Timestamp timestamp, + AuthCtx senderAuth, + Random rng +) { - public TxContext( - Local db, - Identity sender, - ConnectionId? connectionId, - Timestamp timestamp, - AuthCtx senderAuth, - Random rng - ) - { - Db = db; - Sender = sender; - ConnectionId = connectionId; - Timestamp = timestamp; - SenderAuth = senderAuth; - Rng = rng; - } - - public Local Db { get; } - public Identity Sender { get; } - public ConnectionId? ConnectionId { get; } - public Timestamp Timestamp { get; } - public AuthCtx SenderAuth { get; } - public Random Rng { get; } + public Local Db { get; } = db; + public Identity Sender { get; } = sender; + public ConnectionId? ConnectionId { get; } = connectionId; + public Timestamp Timestamp { get; } = timestamp; + public AuthCtx SenderAuth { get; } = senderAuth; + public Random Rng { get; } = rng; public TxContext WithTimestamp(Timestamp ts) => new(Db, Sender, ConnectionId, ts, SenderAuth, Rng); diff --git a/crates/bindings-csharp/Runtime/ProcedureContext.cs b/crates/bindings-csharp/Runtime/ProcedureContext.cs index 11fe27743b2..8c78a427f35 100644 --- a/crates/bindings-csharp/Runtime/ProcedureContext.cs +++ b/crates/bindings-csharp/Runtime/ProcedureContext.cs @@ -3,28 +3,19 @@ namespace SpacetimeDB; using System.Diagnostics.CodeAnalysis; #pragma warning disable STDB_UNSTABLE -public abstract class ProcedureContextBase : Internal.IInternalProcedureContext +public abstract class ProcedureContextBase( + Identity sender, + ConnectionId? connectionId, + Random random, + Timestamp time +) : Internal.IInternalProcedureContext { - protected ProcedureContextBase( - Identity sender, - ConnectionId? connectionId, - Random random, - Timestamp time - ) - { - Sender = sender; - ConnectionId = connectionId; - Rng = random; - Timestamp = time; - SenderAuth = AuthCtx.BuildFromSystemTables(connectionId, sender); - } - public Identity Identity => Internal.IProcedureContext.GetIdentity(); - public Identity Sender { get; } - public ConnectionId? ConnectionId { get; } - public Random Rng { get; } - public Timestamp Timestamp { get; private set; } - public AuthCtx SenderAuth { get; } + public Identity Sender { get; } = sender; + public ConnectionId? ConnectionId { get; } = connectionId; + public Random Rng { get; } = random; + public Timestamp Timestamp { get; private set; } = time; + public AuthCtx SenderAuth { get; } = AuthCtx.BuildFromSystemTables(connectionId, sender); private Internal.TransactionOffset? pendingTxOffset; private Internal.TxContext? txContext; @@ -77,18 +68,11 @@ public bool TryTakeTransactionOffset(out Internal.TransactionOffset offset) return false; } - public readonly struct TxOutcome + public readonly struct TxOutcome(bool isSuccess, TResult? value, Exception? error) { - public TxOutcome(bool isSuccess, TResult? value, Exception? error) - { - IsSuccess = isSuccess; - Value = value; - Error = error; - } - - public bool IsSuccess { get; } - public TResult? Value { get; } - public Exception? Error { get; } + public bool IsSuccess { get; } = isSuccess; + public TResult? Value { get; } = value; + public Exception? Error { get; } = error; public static TxOutcome Success(TResult value) => new(true, value, null); @@ -106,19 +90,12 @@ public TResult UnwrapOrThrow(Func fallbackFactory) => IsSuccess ? Value! : throw (Error ?? fallbackFactory()); } - public readonly struct TxResult + public readonly struct TxResult(bool isSuccess, TResult? value, TError? error) where TError : Exception { - public TxResult(bool isSuccess, TResult? value, TError? error) - { - IsSuccess = isSuccess; - Value = value; - Error = error; - } - - public bool IsSuccess { get; } - public TResult? Value { get; } - public TError? Error { get; } + public bool IsSuccess { get; } = isSuccess; + public TResult? Value { get; } = value; + public TError? Error { get; } = error; public static TxResult Success(TResult value) => new(true, value, null); @@ -214,13 +191,11 @@ Func> body return result; } - private sealed class AbortGuard : IDisposable + private sealed class AbortGuard(Action abort) : IDisposable { - private readonly Action abort; + private readonly Action abort = abort; private bool disarmed; - public AbortGuard(Action abort) => this.abort = abort; - public void Disarm() => disarmed = true; public void Dispose() @@ -233,14 +208,9 @@ public void Dispose() } } -public abstract class ProcedureTxContextBase +public abstract class ProcedureTxContextBase(Internal.TxContext inner) { - protected ProcedureTxContextBase(Internal.TxContext inner) - { - Inner = inner; - } - - internal Internal.TxContext Inner { get; private set; } + internal Internal.TxContext Inner { get; private set; } = inner; internal void Refresh(Internal.TxContext inner) => Inner = inner; @@ -256,18 +226,15 @@ public abstract class LocalBase : Internal.Local { } public abstract class LocalReadOnlyBase : Internal.LocalReadOnly { } -public sealed class ProcedureContext : ProcedureContextBase +public sealed class ProcedureContext( + Identity sender, + ConnectionId? connectionId, + Random random, + Timestamp timestamp +) : ProcedureContextBase(sender, connectionId, random, timestamp) { private readonly Local _db = new(); - public ProcedureContext( - Identity sender, - ConnectionId? connectionId, - Random random, - Timestamp timestamp - ) - : base(sender, connectionId, random, timestamp) { } - protected internal override LocalBase CreateLocal() => _db; protected override ProcedureTxContextBase CreateTxContext(Internal.TxContext inner) => diff --git a/modules/benchmarks-cs/circles.cs b/modules/benchmarks-cs/circles.cs index d369427e551..e818f166511 100644 --- a/modules/benchmarks-cs/circles.cs +++ b/modules/benchmarks-cs/circles.cs @@ -1,6 +1,5 @@ -using SpacetimeDB; - namespace Benchmarks; +using SpacetimeDB; public static partial class circles { @@ -48,9 +47,9 @@ public static float MassToRadius(uint mass) public static bool IsOverlapping(Entity entity1, Entity entity2) { - float entity1_radius = MassToRadius(entity1.mass); - float entity2_radius = MassToRadius(entity2.mass); - float distance = (float) + var entity1_radius = MassToRadius(entity1.mass); + var entity2_radius = MassToRadius(entity2.mass); + var distance = (float) Math.Sqrt( Math.Pow(entity1.position.x - entity2.position.x, 2) + Math.Pow(entity1.position.y - entity2.position.y, 2) diff --git a/modules/benchmarks-cs/ia_loop.cs b/modules/benchmarks-cs/ia_loop.cs index 8e8abe8c167..7a473e3f9fd 100644 --- a/modules/benchmarks-cs/ia_loop.cs +++ b/modules/benchmarks-cs/ia_loop.cs @@ -1,6 +1,5 @@ -using SpacetimeDB; - namespace Benchmarks; +using SpacetimeDB; public static partial class ia_loop { @@ -196,7 +195,7 @@ public static void insert_world(ReducerContext ctx, ulong players) { for (ulong i = 0; i < players; i++) { - ulong next_action_timestamp = + var next_action_timestamp = (i & 2) == 2 ? MomentMilliseconds() + 2000 : MomentMilliseconds(); ctx.Db.game_enemy_ai_agent_state.Insert( @@ -234,7 +233,7 @@ ulong num_players { List result = new(4); - for (ulong id = entity_id; id < num_players; id++) + for (var id = entity_id; id < num_players; id++) { foreach ( GameLiveTargetableState t in ctx.Db.game_live_targetable_state.quad.Filter((long)id) @@ -259,7 +258,7 @@ public static void MoveAgent( ulong current_time_ms ) { - ulong entity_id = agent.entity_id; + var entity_id = agent.entity_id; GameEnemyState enemy = ctx.Db.game_enemy_state.entity_id.Find(entity_id) @@ -277,7 +276,7 @@ ulong current_time_ms GameTargetableState targetable = ctx.Db.game_targetable_state.entity_id.Find(entity_id) ?? throw new Exception("GameTargetableState Entity ID not found"); - int new_hash = targetable.quad.GetHashCode(); + var new_hash = targetable.quad.GetHashCode(); targetable.quad = new_hash; ctx.Db.game_targetable_state.entity_id.Update(targetable); @@ -306,7 +305,7 @@ public static void AgentLoop( ulong current_time_ms ) { - ulong entity_id = agent.entity_id; + var entity_id = agent.entity_id; GameMobileEntityState? coordinates = ctx.Db.game_mobile_entity_state.entity_id.Find(entity_id) @@ -329,7 +328,7 @@ ulong current_time_ms public static void game_loop_enemy_ia(ReducerContext ctx, ulong players) { uint count = 0; - ulong current_time_ms = MomentMilliseconds(); + var current_time_ms = MomentMilliseconds(); foreach (GameEnemyAiAgentState agent in ctx.Db.game_enemy_ai_agent_state.Iter()) { diff --git a/modules/benchmarks-cs/lib.cs b/modules/benchmarks-cs/lib.cs index c72027d57cf..9b5784e4713 100644 --- a/modules/benchmarks-cs/lib.cs +++ b/modules/benchmarks-cs/lib.cs @@ -1,6 +1,5 @@ -using System.Runtime.CompilerServices; - namespace Benchmarks; +using System.Runtime.CompilerServices; public static class Bench { diff --git a/modules/benchmarks-cs/synthetic.cs b/modules/benchmarks-cs/synthetic.cs index cf888fd7a56..ae6ce6c64c5 100644 --- a/modules/benchmarks-cs/synthetic.cs +++ b/modules/benchmarks-cs/synthetic.cs @@ -1,6 +1,5 @@ -using SpacetimeDB; - namespace Benchmarks; +using SpacetimeDB; public static partial class synthetic { @@ -250,7 +249,7 @@ List people [SpacetimeDB.Reducer] public static void update_bulk_unique_0_u32_u64_u64(ReducerContext ctx, uint row_count) { - int hit = 0; + var hit = 0; foreach ( unique_0_u32_u64_u64_t loc in ctx.Db.unique_0_u32_u64_u64.Iter().Take((int)row_count) ) @@ -545,7 +544,7 @@ string _arg32 [SpacetimeDB.Reducer] public static void print_many_things(ReducerContext ctx, uint n) { - for (int i = 0; i < n; i++) + for (var i = 0; i < n; i++) { Log.Info("hello again!"); } diff --git a/modules/module-test-cs/Lib.cs b/modules/module-test-cs/Lib.cs index 1889f75bf2e..59227ed29fc 100644 --- a/modules/module-test-cs/Lib.cs +++ b/modules/module-test-cs/Lib.cs @@ -382,7 +382,7 @@ public static void add_player(ReducerContext ctx, string name) [Reducer] public static void delete_player(ReducerContext ctx, ulong id) { - bool deleted = ctx.Db.test_e.id.Delete(id); + var deleted = ctx.Db.test_e.id.Delete(id); if (!deleted) { throw new Exception($"No TestE row with id {id}"); @@ -429,7 +429,7 @@ public static void query_private(ReducerContext ctx) public static void test_btree_index_args(ReducerContext ctx) { // Testing various acceptable index filter argument types. - string s = "String"; + var s = "String"; var _1 = ctx.Db.test_e.name.Filter(s); var _2 = ctx.Db.test_e.name.Filter("str"); diff --git a/modules/sdk-test-connect-disconnect-cs/Lib.cs b/modules/sdk-test-connect-disconnect-cs/Lib.cs index 79af81d8cc4..40cc3532cb6 100644 --- a/modules/sdk-test-connect-disconnect-cs/Lib.cs +++ b/modules/sdk-test-connect-disconnect-cs/Lib.cs @@ -19,12 +19,12 @@ static partial class Module [SpacetimeDB.Reducer(ReducerKind.ClientConnected)] public static void identity_connected(ReducerContext ctx) { - ctx.Db.connected.Insert(new Connected { identity = ctx.Sender}); + ctx.Db.connected.Insert(new Connected { identity = ctx.Sender }); } [SpacetimeDB.Reducer(ReducerKind.ClientDisconnected)] public static void identity_disconnected(ReducerContext ctx) { - ctx.Db.disconnected.Insert(new Disconnected { identity = ctx.Sender}); + ctx.Db.disconnected.Insert(new Disconnected { identity = ctx.Sender }); } } diff --git a/modules/sdk-test-cs/Lib.cs b/modules/sdk-test-cs/Lib.cs index b17daa81ad4..84525e2b413 100644 --- a/modules/sdk-test-cs/Lib.cs +++ b/modules/sdk-test-cs/Lib.cs @@ -2010,9 +2010,9 @@ public partial struct ScheduledTable [SpacetimeDB.Reducer] public static void send_scheduled_message(ReducerContext ctx, ScheduledTable arg) { - ulong id = arg.scheduled_id; + var id = arg.scheduled_id; SpacetimeDB.ScheduleAt scheduleAt = arg.scheduled_at; - string text = arg.text; + var text = arg.text; } [SpacetimeDB.Table(Name = "indexed_table")] diff --git a/sdks/csharp/examples~/regression-tests/client/Program.cs b/sdks/csharp/examples~/regression-tests/client/Program.cs index 9b9f6d15b19..b530c1a4cd6 100644 --- a/sdks/csharp/examples~/regression-tests/client/Program.cs +++ b/sdks/csharp/examples~/regression-tests/client/Program.cs @@ -2,9 +2,11 @@ /// To run these, run a local SpacetimeDB via `spacetime start`, /// then in a separate terminal run `tools~/run-regression-tests.sh PATH_TO_SPACETIMEDB_REPO_CHECKOUT`. /// This is done on CI in .github/workflows/test.yml. - +using System; using System.Diagnostics; +using System.Linq; using System.Runtime.CompilerServices; +using System.Threading; using SpacetimeDB; using SpacetimeDB.Types; @@ -14,25 +16,30 @@ DbConnection ConnectToDB() { DbConnection? conn = null; - conn = DbConnection.Builder() + conn = DbConnection + .Builder() .WithUri(HOST) .WithModuleName(DBNAME) .OnConnect(OnConnected) - .OnConnectError((err) => - { - throw err; - }) - .OnDisconnect((conn, err) => - { - if (err != null) + .OnConnectError( + (err) => { throw err; } - else + ) + .OnDisconnect( + (conn, err) => { - throw new Exception("Unexpected disconnect"); + if (err != null) + { + throw err; + } + else + { + throw new Exception("Unexpected disconnect"); + } } - }) + ) .Build(); return conn; } @@ -46,11 +53,17 @@ void OnConnected(DbConnection conn, Identity identity, string authToken) Log.Debug($"Connected to {DBNAME} on {HOST}"); handle = conn.SubscriptionBuilder() .OnApplied(OnSubscriptionApplied) - .OnError((ctx, err) => - { - throw err; - }) - .Subscribe(["SELECT * FROM ExampleData", "SELECT * FROM MyPlayer", "SELECT * FROM PlayersForLevel"]); + .OnError( + (ctx, err) => + { + throw err; + } + ) + .Subscribe([ + "SELECT * FROM ExampleData", + "SELECT * FROM MyPlayer", + "SELECT * FROM PlayersForLevel", + ]); conn.Reducers.OnAdd += (ReducerEventContext ctx, uint id, uint indexed) => { @@ -127,30 +140,46 @@ void OnSubscriptionApplied(SubscriptionEventContext context) // Now unsubscribe and check that the unsubscribe is actually applied. Log.Debug("Calling Unsubscribe"); waiting++; - handle?.UnsubscribeThen((ctx) => - { - Log.Debug("Received Unsubscribe"); - ValidateBTreeIndexes(ctx); - waiting--; - }); - + handle?.UnsubscribeThen( + (ctx) => + { + Log.Debug("Received Unsubscribe"); + ValidateBTreeIndexes(ctx); + waiting--; + } + ); // Views test Log.Debug("Checking Views are populated"); Debug.Assert(context.Db.MyPlayer != null, "context.Db.MyPlayer != null"); Debug.Assert(context.Db.PlayersForLevel != null, "context.Db.PlayersForLevel != null"); - Debug.Assert(context.Db.MyPlayer.Count > 0, $"context.Db.MyPlayer.Count = {context.Db.MyPlayer.Count}"); - Debug.Assert(context.Db.PlayersForLevel.Count > 0, $"context.Db.PlayersForLevel.Count = {context.Db.PlayersForLevel.Count}"); + Debug.Assert( + context.Db.MyPlayer.Count > 0, + $"context.Db.MyPlayer.Count = {context.Db.MyPlayer.Count}" + ); + Debug.Assert( + context.Db.PlayersForLevel.Count > 0, + $"context.Db.PlayersForLevel.Count = {context.Db.PlayersForLevel.Count}" + ); Log.Debug("Calling Iter on View"); var viewIterRows = context.Db.MyPlayer.Iter(); - var expectedPlayer = new Player { Id = 1, Identity = context.Identity!.Value, Name = "NewPlayer" }; - Log.Debug("MyPlayer Iter count: " + (viewIterRows != null ? viewIterRows.Count().ToString() : "null")); + var expectedPlayer = new Player + { + Id = 1, + Identity = context.Identity!.Value, + Name = "NewPlayer", + }; + Log.Debug( + "MyPlayer Iter count: " + (viewIterRows != null ? viewIterRows.Count().ToString() : "null") + ); Debug.Assert(viewIterRows != null && viewIterRows.Any()); - Log.Debug("Validating View row data " + - $"Id={expectedPlayer.Id}, Identity={expectedPlayer.Identity}, Name={expectedPlayer.Name} => " + - $"Id={viewIterRows.First().Id}, Identity={viewIterRows.First().Identity}, Name={viewIterRows.First().Name}"); + Log.Debug( + "Validating View row data " + + $"Id={expectedPlayer.Id}, Identity={expectedPlayer.Identity}, Name={expectedPlayer.Name} => " + + $"Id={viewIterRows.First().Id}, Identity={viewIterRows.First().Identity}, Name={viewIterRows.First().Name}" + ); Debug.Assert(viewIterRows.First().Equals(expectedPlayer)); Log.Debug("Calling RemoteQuery on View"); @@ -165,18 +194,30 @@ void OnSubscriptionApplied(SubscriptionEventContext context) Id = 1, Identity = context.Identity!.Value, Name = "NewPlayer", - Level = 1 + Level = 1, }; - Log.Debug("PlayersForLevel Iter count: " + (anonViewIterRows != null ? anonViewIterRows.Count().ToString() : "null")); + Log.Debug( + "PlayersForLevel Iter count: " + + (anonViewIterRows != null ? anonViewIterRows.Count().ToString() : "null") + ); Debug.Assert(anonViewIterRows != null && anonViewIterRows.Any()); - Log.Debug("Validating Anonymous View row data " + - $"Id={expectedPlayerAndLevel.Id}, Identity={expectedPlayerAndLevel.Identity}, Name={expectedPlayerAndLevel.Name}, Level={expectedPlayerAndLevel.Level} => " + - $"Id={anonViewIterRows.First().Id}, Identity={anonViewIterRows.First().Identity}, Name={anonViewIterRows.First().Name}, Level={anonViewIterRows.First().Level}"); + Log.Debug( + "Validating Anonymous View row data " + + $"Id={expectedPlayerAndLevel.Id}, Identity={expectedPlayerAndLevel.Identity}, Name={expectedPlayerAndLevel.Name}, Level={expectedPlayerAndLevel.Level} => " + + $"Id={anonViewIterRows.First().Id}, Identity={anonViewIterRows.First().Identity}, Name={anonViewIterRows.First().Name}, Level={anonViewIterRows.First().Level}" + ); Debug.Assert(anonViewIterRows.First().Equals(expectedPlayerAndLevel)); Log.Debug("Calling RemoteQuery on Anonymous View"); var anonViewRemoteQueryRows = context.Db.PlayersForLevel.RemoteQuery("WHERE Level = 1"); - Log.Debug("PlayersForLevel RemoteQuery count: " + (anonViewRemoteQueryRows != null ? anonViewRemoteQueryRows.Result.Length.ToString() : "null")); + Log.Debug( + "PlayersForLevel RemoteQuery count: " + + ( + anonViewRemoteQueryRows != null + ? anonViewRemoteQueryRows.Result.Length.ToString() + : "null" + ) + ); Debug.Assert(anonViewRemoteQueryRows != null && anonViewRemoteQueryRows.Result.Length > 0); Debug.Assert(anonViewRemoteQueryRows.Result.First().Equals(expectedPlayerAndLevel)); } @@ -201,4 +242,4 @@ void OnSubscriptionApplied(SubscriptionEventContext context) } } Log.Info("Success"); -Environment.Exit(0); \ No newline at end of file +Environment.Exit(0);