From dc5c78dbc5ee9b3dd806283f4358ef6bfaee27ed Mon Sep 17 00:00:00 2001 From: Lisandro Crespo Date: Fri, 17 Jul 2026 14:27:43 -0500 Subject: [PATCH 1/2] Add static generic caches for reducers and more --- .../diag/snapshots/Module#FFI.verified.cs | 344 +++++++++++++++--- .../snapshots/Module#FFI.verified.cs | 141 ++++--- .../server/snapshots/Module#FFI.verified.cs | 211 ++++++++--- crates/bindings-csharp/Codegen/Module.cs | 138 ++++--- .../Runtime/Internal/Module.cs | 221 ++++++++++- 5 files changed, 859 insertions(+), 196 deletions(-) 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 c5fbd45e8b9..f6bba9200a8 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 @@ -3210,7 +3210,7 @@ public sealed partial class LocalReadOnly static class ModuleRegistration { - class __ReducerWithReservedPrefix : SpacetimeDB.Internal.IReducer + sealed class __ReducerWithReservedPrefix : SpacetimeDB.Internal.IReducer { public SpacetimeDB.Internal.RawReducerDefV10 MakeReducerDef( SpacetimeDB.BSATN.ITypeRegistrar registrar @@ -3231,7 +3231,7 @@ public void Invoke(BinaryReader reader, SpacetimeDB.Internal.IReducerContext ctx } } - class DummyScheduledReducer : SpacetimeDB.Internal.IReducer + sealed class DummyScheduledReducer : SpacetimeDB.Internal.IReducer { private static readonly TestScheduleIssues.BSATN tableRW = new(); @@ -3257,7 +3257,7 @@ public void Invoke(BinaryReader reader, SpacetimeDB.Internal.IReducerContext ctx } } - class OnReducerWithReservedPrefix : SpacetimeDB.Internal.IReducer + sealed class OnReducerWithReservedPrefix : SpacetimeDB.Internal.IReducer { public SpacetimeDB.Internal.RawReducerDefV10 MakeReducerDef( SpacetimeDB.BSATN.ITypeRegistrar registrar @@ -3278,7 +3278,7 @@ public void Invoke(BinaryReader reader, SpacetimeDB.Internal.IReducerContext ctx } } - class TestDuplicateReducerKind1 : SpacetimeDB.Internal.IReducer + sealed class TestDuplicateReducerKind1 : SpacetimeDB.Internal.IReducer { public SpacetimeDB.Internal.RawReducerDefV10 MakeReducerDef( SpacetimeDB.BSATN.ITypeRegistrar registrar @@ -3299,7 +3299,7 @@ public void Invoke(BinaryReader reader, SpacetimeDB.Internal.IReducerContext ctx } } - class TestDuplicateReducerKind2 : SpacetimeDB.Internal.IReducer + sealed class TestDuplicateReducerKind2 : SpacetimeDB.Internal.IReducer { public SpacetimeDB.Internal.RawReducerDefV10 MakeReducerDef( SpacetimeDB.BSATN.ITypeRegistrar registrar @@ -3320,7 +3320,7 @@ public void Invoke(BinaryReader reader, SpacetimeDB.Internal.IReducerContext ctx } } - class TestDuplicateReducerName : SpacetimeDB.Internal.IReducer + sealed class TestDuplicateReducerName : SpacetimeDB.Internal.IReducer { public SpacetimeDB.Internal.RawReducerDefV10 MakeReducerDef( SpacetimeDB.BSATN.ITypeRegistrar registrar @@ -3341,7 +3341,7 @@ public void Invoke(BinaryReader reader, SpacetimeDB.Internal.IReducerContext ctx } } - class TestReducerReturnType : SpacetimeDB.Internal.IReducer + sealed class TestReducerReturnType : SpacetimeDB.Internal.IReducer { public SpacetimeDB.Internal.RawReducerDefV10 MakeReducerDef( SpacetimeDB.BSATN.ITypeRegistrar registrar @@ -3362,7 +3362,7 @@ public void Invoke(BinaryReader reader, SpacetimeDB.Internal.IReducerContext ctx } } - class TestReducerWithoutContext : SpacetimeDB.Internal.IReducer + sealed class TestReducerWithoutContext : SpacetimeDB.Internal.IReducer { public SpacetimeDB.Internal.RawReducerDefV10 MakeReducerDef( SpacetimeDB.BSATN.ITypeRegistrar registrar @@ -3756,18 +3756,118 @@ public static SpacetimeDB.Internal.Errno __call_reducer__( SpacetimeDB.Internal.BytesSource args, SpacetimeDB.Internal.BytesSink error ) => - SpacetimeDB.Internal.Module.__call_reducer__( - id, - sender_0, - sender_1, - sender_2, - sender_3, - conn_id_0, - conn_id_1, - timestamp, - args, - error - ); + id switch + { + 0 + => SpacetimeDB.Internal.Module.__call_reducer__<__ReducerWithReservedPrefix>( + sender_0, + sender_1, + sender_2, + sender_3, + conn_id_0, + conn_id_1, + timestamp, + args, + error + ), + 1 + => SpacetimeDB.Internal.Module.__call_reducer__( + sender_0, + sender_1, + sender_2, + sender_3, + conn_id_0, + conn_id_1, + timestamp, + args, + error + ), + 2 + => SpacetimeDB.Internal.Module.__call_reducer__( + sender_0, + sender_1, + sender_2, + sender_3, + conn_id_0, + conn_id_1, + timestamp, + args, + error + ), + 3 + => SpacetimeDB.Internal.Module.__call_reducer__( + sender_0, + sender_1, + sender_2, + sender_3, + conn_id_0, + conn_id_1, + timestamp, + args, + error + ), + 4 + => SpacetimeDB.Internal.Module.__call_reducer__( + sender_0, + sender_1, + sender_2, + sender_3, + conn_id_0, + conn_id_1, + timestamp, + args, + error + ), + 5 + => SpacetimeDB.Internal.Module.__call_reducer__( + sender_0, + sender_1, + sender_2, + sender_3, + conn_id_0, + conn_id_1, + timestamp, + args, + error + ), + 6 + => SpacetimeDB.Internal.Module.__call_reducer__( + sender_0, + sender_1, + sender_2, + sender_3, + conn_id_0, + conn_id_1, + timestamp, + args, + error + ), + 7 + => SpacetimeDB.Internal.Module.__call_reducer__( + sender_0, + sender_1, + sender_2, + sender_3, + conn_id_0, + conn_id_1, + timestamp, + args, + error + ), + _ + => SpacetimeDB.Internal.Module.__call_reducer__( + id, + sender_0, + sender_1, + sender_2, + sender_3, + conn_id_0, + conn_id_1, + timestamp, + args, + error + ) + }; [UnmanagedCallersOnly(EntryPoint = "__call_procedure__")] public static SpacetimeDB.Internal.Errno __call_procedure__( @@ -3782,18 +3882,22 @@ public static SpacetimeDB.Internal.Errno __call_procedure__( SpacetimeDB.Internal.BytesSource args, SpacetimeDB.Internal.BytesSink result_sink ) => - SpacetimeDB.Internal.Module.__call_procedure__( - id, - sender_0, - sender_1, - sender_2, - sender_3, - conn_id_0, - conn_id_1, - timestamp, - args, - result_sink - ); + id switch + { + _ + => SpacetimeDB.Internal.Module.__call_procedure__( + id, + sender_0, + sender_1, + sender_2, + sender_3, + conn_id_0, + conn_id_1, + timestamp, + args, + result_sink + ) + }; [UnmanagedCallersOnly(EntryPoint = "__call_http_handler__")] public static SpacetimeDB.Internal.Errno __call_http_handler__( @@ -3804,14 +3908,18 @@ public static SpacetimeDB.Internal.Errno __call_http_handler__( SpacetimeDB.Internal.BytesSink response_sink, SpacetimeDB.Internal.BytesSink response_body_sink ) => - SpacetimeDB.Internal.Module.__call_http_handler__( - id, - timestamp, - request, - request_body, - response_sink, - response_body_sink - ); + id switch + { + _ + => SpacetimeDB.Internal.Module.__call_http_handler__( + id, + timestamp, + request, + request_body, + response_sink, + response_body_sink + ) + }; [UnmanagedCallersOnly(EntryPoint = "__call_view__")] public static SpacetimeDB.Internal.Errno __call_view__( @@ -3823,22 +3931,158 @@ public static SpacetimeDB.Internal.Errno __call_view__( SpacetimeDB.Internal.BytesSource args, SpacetimeDB.Internal.BytesSink sink ) => - SpacetimeDB.Internal.Module.__call_view__( - id, - sender_0, - sender_1, - sender_2, - sender_3, - args, - sink - ); + id switch + { + 0 + => SpacetimeDB.Internal.Module.__call_view__( + sender_0, + sender_1, + sender_2, + sender_3, + args, + sink + ), + 1 + => SpacetimeDB.Internal.Module.__call_view__( + sender_0, + sender_1, + sender_2, + sender_3, + args, + sink + ), + 2 + => SpacetimeDB.Internal.Module.__call_view__( + sender_0, + sender_1, + sender_2, + sender_3, + args, + sink + ), + 3 + => SpacetimeDB.Internal.Module.__call_view__( + sender_0, + sender_1, + sender_2, + sender_3, + args, + sink + ), + 4 + => SpacetimeDB.Internal.Module.__call_view__( + sender_0, + sender_1, + sender_2, + sender_3, + args, + sink + ), + 5 + => SpacetimeDB.Internal.Module.__call_view__( + sender_0, + sender_1, + sender_2, + sender_3, + args, + sink + ), + 6 + => SpacetimeDB.Internal.Module.__call_view__( + sender_0, + sender_1, + sender_2, + sender_3, + args, + sink + ), + 7 + => SpacetimeDB.Internal.Module.__call_view__( + sender_0, + sender_1, + sender_2, + sender_3, + args, + sink + ), + 8 + => SpacetimeDB.Internal.Module.__call_view__( + sender_0, + sender_1, + sender_2, + sender_3, + args, + sink + ), + 9 + => SpacetimeDB.Internal.Module.__call_view__( + sender_0, + sender_1, + sender_2, + sender_3, + args, + sink + ), + 10 + => SpacetimeDB.Internal.Module.__call_view__( + sender_0, + sender_1, + sender_2, + sender_3, + args, + sink + ), + 11 + => SpacetimeDB.Internal.Module.__call_view__( + sender_0, + sender_1, + sender_2, + sender_3, + args, + sink + ), + _ + => SpacetimeDB.Internal.Module.__call_view__( + id, + sender_0, + sender_1, + sender_2, + sender_3, + args, + sink + ) + }; [UnmanagedCallersOnly(EntryPoint = "__call_view_anon__")] public static SpacetimeDB.Internal.Errno __call_view_anon__( int id, SpacetimeDB.Internal.BytesSource args, SpacetimeDB.Internal.BytesSink sink - ) => SpacetimeDB.Internal.Module.__call_view_anon__(id, args, sink); + ) => + id switch + { + 0 + => SpacetimeDB.Internal.Module.__call_view_anon__( + args, + sink + ), + 1 + => SpacetimeDB.Internal.Module.__call_view_anon__( + args, + sink + ), + 2 + => SpacetimeDB.Internal.Module.__call_view_anon__( + args, + sink + ), + 3 + => SpacetimeDB.Internal.Module.__call_view_anon__( + args, + sink + ), + _ => SpacetimeDB.Internal.Module.__call_view_anon__(id, args, sink) + }; #endif } diff --git a/crates/bindings-csharp/Codegen.Tests/fixtures/explicitnames/snapshots/Module#FFI.verified.cs b/crates/bindings-csharp/Codegen.Tests/fixtures/explicitnames/snapshots/Module#FFI.verified.cs index e0124d76783..3b5bcc02f65 100644 --- a/crates/bindings-csharp/Codegen.Tests/fixtures/explicitnames/snapshots/Module#FFI.verified.cs +++ b/crates/bindings-csharp/Codegen.Tests/fixtures/explicitnames/snapshots/Module#FFI.verified.cs @@ -511,7 +511,7 @@ public sealed partial class LocalReadOnly static class ModuleRegistration { - class DemoReducer : SpacetimeDB.Internal.IReducer + sealed class DemoReducer : SpacetimeDB.Internal.IReducer { private static readonly SpacetimeDB.BSATN.I32 valueRW = new(); @@ -534,7 +534,7 @@ public void Invoke(BinaryReader reader, SpacetimeDB.Internal.IReducerContext ctx } } - class DemoProcedure : SpacetimeDB.Internal.IProcedure + sealed class DemoProcedure : SpacetimeDB.Internal.IProcedure { public SpacetimeDB.Internal.RawProcedureDefV10 MakeProcedureDef( SpacetimeDB.BSATN.ITypeRegistrar registrar @@ -646,18 +646,34 @@ public static SpacetimeDB.Internal.Errno __call_reducer__( SpacetimeDB.Internal.BytesSource args, SpacetimeDB.Internal.BytesSink error ) => - SpacetimeDB.Internal.Module.__call_reducer__( - id, - sender_0, - sender_1, - sender_2, - sender_3, - conn_id_0, - conn_id_1, - timestamp, - args, - error - ); + id switch + { + 0 + => SpacetimeDB.Internal.Module.__call_reducer__( + sender_0, + sender_1, + sender_2, + sender_3, + conn_id_0, + conn_id_1, + timestamp, + args, + error + ), + _ + => SpacetimeDB.Internal.Module.__call_reducer__( + id, + sender_0, + sender_1, + sender_2, + sender_3, + conn_id_0, + conn_id_1, + timestamp, + args, + error + ) + }; [UnmanagedCallersOnly(EntryPoint = "__call_procedure__")] public static SpacetimeDB.Internal.Errno __call_procedure__( @@ -672,18 +688,34 @@ public static SpacetimeDB.Internal.Errno __call_procedure__( SpacetimeDB.Internal.BytesSource args, SpacetimeDB.Internal.BytesSink result_sink ) => - SpacetimeDB.Internal.Module.__call_procedure__( - id, - sender_0, - sender_1, - sender_2, - sender_3, - conn_id_0, - conn_id_1, - timestamp, - args, - result_sink - ); + id switch + { + 0 + => SpacetimeDB.Internal.Module.__call_procedure__( + sender_0, + sender_1, + sender_2, + sender_3, + conn_id_0, + conn_id_1, + timestamp, + args, + result_sink + ), + _ + => SpacetimeDB.Internal.Module.__call_procedure__( + id, + sender_0, + sender_1, + sender_2, + sender_3, + conn_id_0, + conn_id_1, + timestamp, + args, + result_sink + ) + }; [UnmanagedCallersOnly(EntryPoint = "__call_http_handler__")] public static SpacetimeDB.Internal.Errno __call_http_handler__( @@ -694,14 +726,18 @@ public static SpacetimeDB.Internal.Errno __call_http_handler__( SpacetimeDB.Internal.BytesSink response_sink, SpacetimeDB.Internal.BytesSink response_body_sink ) => - SpacetimeDB.Internal.Module.__call_http_handler__( - id, - timestamp, - request, - request_body, - response_sink, - response_body_sink - ); + id switch + { + _ + => SpacetimeDB.Internal.Module.__call_http_handler__( + id, + timestamp, + request, + request_body, + response_sink, + response_body_sink + ) + }; [UnmanagedCallersOnly(EntryPoint = "__call_view__")] public static SpacetimeDB.Internal.Errno __call_view__( @@ -713,22 +749,39 @@ public static SpacetimeDB.Internal.Errno __call_view__( SpacetimeDB.Internal.BytesSource args, SpacetimeDB.Internal.BytesSink sink ) => - SpacetimeDB.Internal.Module.__call_view__( - id, - sender_0, - sender_1, - sender_2, - sender_3, - args, - sink - ); + id switch + { + 0 + => SpacetimeDB.Internal.Module.__call_view__( + sender_0, + sender_1, + sender_2, + sender_3, + args, + sink + ), + _ + => SpacetimeDB.Internal.Module.__call_view__( + id, + sender_0, + sender_1, + sender_2, + sender_3, + args, + sink + ) + }; [UnmanagedCallersOnly(EntryPoint = "__call_view_anon__")] public static SpacetimeDB.Internal.Errno __call_view_anon__( int id, SpacetimeDB.Internal.BytesSource args, SpacetimeDB.Internal.BytesSink sink - ) => SpacetimeDB.Internal.Module.__call_view_anon__(id, args, sink); + ) => + id switch + { + _ => SpacetimeDB.Internal.Module.__call_view_anon__(id, args, sink) + }; #endif } 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 234e43c9c50..3378de69b21 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 @@ -2322,7 +2322,7 @@ public sealed partial class LocalReadOnly static class ModuleRegistration { - class Init : SpacetimeDB.Internal.IReducer + sealed class Init : SpacetimeDB.Internal.IReducer { public SpacetimeDB.Internal.RawReducerDefV10 MakeReducerDef( SpacetimeDB.BSATN.ITypeRegistrar registrar @@ -2343,7 +2343,7 @@ public void Invoke(BinaryReader reader, SpacetimeDB.Internal.IReducerContext ctx } } - class InsertData : SpacetimeDB.Internal.IReducer + sealed class InsertData : SpacetimeDB.Internal.IReducer { private static readonly PublicTable.BSATN dataRW = new(); @@ -2366,7 +2366,7 @@ public void Invoke(BinaryReader reader, SpacetimeDB.Internal.IReducerContext ctx } } - class InsertData2 : SpacetimeDB.Internal.IReducer + sealed class InsertData2 : SpacetimeDB.Internal.IReducer { private static readonly PublicTable.BSATN dataRW = new(); @@ -2392,7 +2392,7 @@ public void Invoke(BinaryReader reader, SpacetimeDB.Internal.IReducerContext ctx } } - class InsertMultiData : SpacetimeDB.Internal.IReducer + sealed class InsertMultiData : SpacetimeDB.Internal.IReducer { private static readonly MultiTableRow.BSATN dataRW = new(); @@ -2415,7 +2415,7 @@ public void Invoke(BinaryReader reader, SpacetimeDB.Internal.IReducerContext ctx } } - class ScheduleImmediate : SpacetimeDB.Internal.IReducer + sealed class ScheduleImmediate : SpacetimeDB.Internal.IReducer { private static readonly PublicTable.BSATN dataRW = new(); @@ -2438,7 +2438,7 @@ public void Invoke(BinaryReader reader, SpacetimeDB.Internal.IReducerContext ctx } } - class SendScheduledMessage : SpacetimeDB.Internal.IReducer + sealed class SendScheduledMessage : SpacetimeDB.Internal.IReducer { private static readonly Timers.SendMessageTimer.BSATN argRW = new(); @@ -2574,18 +2574,94 @@ public static SpacetimeDB.Internal.Errno __call_reducer__( SpacetimeDB.Internal.BytesSource args, SpacetimeDB.Internal.BytesSink error ) => - SpacetimeDB.Internal.Module.__call_reducer__( - id, - sender_0, - sender_1, - sender_2, - sender_3, - conn_id_0, - conn_id_1, - timestamp, - args, - error - ); + id switch + { + 0 + => SpacetimeDB.Internal.Module.__call_reducer__( + sender_0, + sender_1, + sender_2, + sender_3, + conn_id_0, + conn_id_1, + timestamp, + args, + error + ), + 1 + => SpacetimeDB.Internal.Module.__call_reducer__( + sender_0, + sender_1, + sender_2, + sender_3, + conn_id_0, + conn_id_1, + timestamp, + args, + error + ), + 2 + => SpacetimeDB.Internal.Module.__call_reducer__( + sender_0, + sender_1, + sender_2, + sender_3, + conn_id_0, + conn_id_1, + timestamp, + args, + error + ), + 3 + => SpacetimeDB.Internal.Module.__call_reducer__( + sender_0, + sender_1, + sender_2, + sender_3, + conn_id_0, + conn_id_1, + timestamp, + args, + error + ), + 4 + => SpacetimeDB.Internal.Module.__call_reducer__( + sender_0, + sender_1, + sender_2, + sender_3, + conn_id_0, + conn_id_1, + timestamp, + args, + error + ), + 5 + => SpacetimeDB.Internal.Module.__call_reducer__( + sender_0, + sender_1, + sender_2, + sender_3, + conn_id_0, + conn_id_1, + timestamp, + args, + error + ), + _ + => SpacetimeDB.Internal.Module.__call_reducer__( + id, + sender_0, + sender_1, + sender_2, + sender_3, + conn_id_0, + conn_id_1, + timestamp, + args, + error + ) + }; [UnmanagedCallersOnly(EntryPoint = "__call_procedure__")] public static SpacetimeDB.Internal.Errno __call_procedure__( @@ -2600,18 +2676,22 @@ public static SpacetimeDB.Internal.Errno __call_procedure__( SpacetimeDB.Internal.BytesSource args, SpacetimeDB.Internal.BytesSink result_sink ) => - SpacetimeDB.Internal.Module.__call_procedure__( - id, - sender_0, - sender_1, - sender_2, - sender_3, - conn_id_0, - conn_id_1, - timestamp, - args, - result_sink - ); + id switch + { + _ + => SpacetimeDB.Internal.Module.__call_procedure__( + id, + sender_0, + sender_1, + sender_2, + sender_3, + conn_id_0, + conn_id_1, + timestamp, + args, + result_sink + ) + }; [UnmanagedCallersOnly(EntryPoint = "__call_http_handler__")] public static SpacetimeDB.Internal.Errno __call_http_handler__( @@ -2622,14 +2702,18 @@ public static SpacetimeDB.Internal.Errno __call_http_handler__( SpacetimeDB.Internal.BytesSink response_sink, SpacetimeDB.Internal.BytesSink response_body_sink ) => - SpacetimeDB.Internal.Module.__call_http_handler__( - id, - timestamp, - request, - request_body, - response_sink, - response_body_sink - ); + id switch + { + _ + => SpacetimeDB.Internal.Module.__call_http_handler__( + id, + timestamp, + request, + request_body, + response_sink, + response_body_sink + ) + }; [UnmanagedCallersOnly(EntryPoint = "__call_view__")] public static SpacetimeDB.Internal.Errno __call_view__( @@ -2641,22 +2725,53 @@ public static SpacetimeDB.Internal.Errno __call_view__( SpacetimeDB.Internal.BytesSource args, SpacetimeDB.Internal.BytesSink sink ) => - SpacetimeDB.Internal.Module.__call_view__( - id, - sender_0, - sender_1, - sender_2, - sender_3, - args, - sink - ); + id switch + { + 0 + => SpacetimeDB.Internal.Module.__call_view__( + sender_0, + sender_1, + sender_2, + sender_3, + args, + sink + ), + 1 + => SpacetimeDB.Internal.Module.__call_view__( + sender_0, + sender_1, + sender_2, + sender_3, + args, + sink + ), + _ + => SpacetimeDB.Internal.Module.__call_view__( + id, + sender_0, + sender_1, + sender_2, + sender_3, + args, + sink + ) + }; [UnmanagedCallersOnly(EntryPoint = "__call_view_anon__")] public static SpacetimeDB.Internal.Errno __call_view_anon__( int id, SpacetimeDB.Internal.BytesSource args, SpacetimeDB.Internal.BytesSink sink - ) => SpacetimeDB.Internal.Module.__call_view_anon__(id, args, sink); + ) => + id switch + { + 0 + => SpacetimeDB.Internal.Module.__call_view_anon__( + args, + sink + ), + _ => SpacetimeDB.Internal.Module.__call_view_anon__(id, args, sink) + }; #endif } diff --git a/crates/bindings-csharp/Codegen/Module.cs b/crates/bindings-csharp/Codegen/Module.cs index 43bbc702687..5634ad21219 100644 --- a/crates/bindings-csharp/Codegen/Module.cs +++ b/crates/bindings-csharp/Codegen/Module.cs @@ -1567,7 +1567,7 @@ public string GenerateClass() )})"; return $$""" - class {{Identifier}}: SpacetimeDB.Internal.IReducer { + sealed class {{Identifier}}: SpacetimeDB.Internal.IReducer { {{MemberDeclaration.GenerateBsatnFields(Accessibility.Private, Args)}} public SpacetimeDB.Internal.RawReducerDefV10 MakeReducerDef(SpacetimeDB.BSATN.ITypeRegistrar registrar) => new ( @@ -1797,7 +1797,7 @@ public string GenerateClass() } return $$$""" - class {{{Identifier}}} : SpacetimeDB.Internal.IProcedure { + sealed class {{{Identifier}}} : SpacetimeDB.Internal.IProcedure { {{{classFields}}} public SpacetimeDB.Internal.RawProcedureDefV10 MakeProcedureDef(SpacetimeDB.BSATN.ITypeRegistrar registrar) => new( @@ -1939,7 +1939,7 @@ public string GenerateClass() : $"return {FullName}((SpacetimeDB.HandlerContext)ctx, request);"; return $$""" - class {{Identifier}} : SpacetimeDB.Internal.IHttpHandler { + sealed class {{Identifier}} : SpacetimeDB.Internal.IHttpHandler { public SpacetimeDB.Internal.RawHttpHandlerDefV10 MakeHandlerDef() => new( SourceName: nameof({{Identifier}}) ); @@ -2906,18 +2906,26 @@ public static SpacetimeDB.Internal.Errno __call_reducer__( SpacetimeDB.Timestamp timestamp, SpacetimeDB.Internal.BytesSource args, SpacetimeDB.Internal.BytesSink error - ) => SpacetimeDB.Internal.Module.__call_reducer__( - id, - sender_0, - sender_1, - sender_2, - sender_3, - conn_id_0, - conn_id_1, - timestamp, - args, - error - ); + ) => id switch { + {{string.Join( + "\n", + addReducers.Select((r, i) => + $"{i} => SpacetimeDB.Internal.Module.__call_reducer__<{EscapeIdentifier(r.Name)}>(sender_0, sender_1, sender_2, sender_3, conn_id_0, conn_id_1, timestamp, args, error)," + ) + )}} + _ => SpacetimeDB.Internal.Module.__call_reducer__( + id, + sender_0, + sender_1, + sender_2, + sender_3, + conn_id_0, + conn_id_1, + timestamp, + args, + error + ) + }; [UnmanagedCallersOnly(EntryPoint = "__call_procedure__")] public static SpacetimeDB.Internal.Errno __call_procedure__( @@ -2931,18 +2939,26 @@ public static SpacetimeDB.Internal.Errno __call_procedure__( SpacetimeDB.Timestamp timestamp, SpacetimeDB.Internal.BytesSource args, SpacetimeDB.Internal.BytesSink result_sink - ) => SpacetimeDB.Internal.Module.__call_procedure__( - id, - sender_0, - sender_1, - sender_2, - sender_3, - conn_id_0, - conn_id_1, - timestamp, - args, - result_sink - ); + ) => id switch { + {{string.Join( + "\n", + addProcedures.Select((p, i) => + $"{i} => SpacetimeDB.Internal.Module.__call_procedure__<{EscapeIdentifier(p.Name)}>(sender_0, sender_1, sender_2, sender_3, conn_id_0, conn_id_1, timestamp, args, result_sink)," + ) + )}} + _ => SpacetimeDB.Internal.Module.__call_procedure__( + id, + sender_0, + sender_1, + sender_2, + sender_3, + conn_id_0, + conn_id_1, + timestamp, + args, + result_sink + ) + }; [UnmanagedCallersOnly(EntryPoint = "__call_http_handler__")] public static SpacetimeDB.Internal.Errno __call_http_handler__( @@ -2952,14 +2968,22 @@ public static SpacetimeDB.Internal.Errno __call_http_handler__( SpacetimeDB.Internal.BytesSource request_body, SpacetimeDB.Internal.BytesSink response_sink, SpacetimeDB.Internal.BytesSink response_body_sink - ) => SpacetimeDB.Internal.Module.__call_http_handler__( - id, - timestamp, - request, - request_body, - response_sink, - response_body_sink - ); + ) => id switch { + {{string.Join( + "\n", + addHttpHandlers.Select((h, i) => + $"{i} => SpacetimeDB.Internal.Module.__call_http_handler__<{EscapeIdentifier(h.Name)}>(timestamp, request, request_body, response_sink, response_body_sink)," + ) + )}} + _ => SpacetimeDB.Internal.Module.__call_http_handler__( + id, + timestamp, + request, + request_body, + response_sink, + response_body_sink + ) + }; [UnmanagedCallersOnly(EntryPoint = "__call_view__")] public static SpacetimeDB.Internal.Errno __call_view__( @@ -2970,26 +2994,42 @@ public static SpacetimeDB.Internal.Errno __call_view__( ulong sender_3, SpacetimeDB.Internal.BytesSource args, SpacetimeDB.Internal.BytesSink sink - ) => SpacetimeDB.Internal.Module.__call_view__( - id, - sender_0, - sender_1, - sender_2, - sender_3, - args, - sink - ); + ) => id switch { + {{string.Join("\n", + views.Array.Where(v => !v.IsAnonymous) + .Select((v, i) => + $"{i} => SpacetimeDB.Internal.Module.__call_view__<{v.Name}ViewDispatcher>(sender_0, sender_1, sender_2, sender_3, args, sink)," + ) + )}} + _ => SpacetimeDB.Internal.Module.__call_view__( + id, + sender_0, + sender_1, + sender_2, + sender_3, + args, + sink + ) + }; [UnmanagedCallersOnly(EntryPoint = "__call_view_anon__")] public static SpacetimeDB.Internal.Errno __call_view_anon__( int id, SpacetimeDB.Internal.BytesSource args, SpacetimeDB.Internal.BytesSink sink - ) => SpacetimeDB.Internal.Module.__call_view_anon__( - id, - args, - sink - ); + ) => id switch { + {{string.Join("\n", + views.Array.Where(v => v.IsAnonymous) + .Select((v, i) => + $"{i} => SpacetimeDB.Internal.Module.__call_view_anon__<{v.Name}ViewDispatcher>(args, sink)," + ) + )}} + _ => SpacetimeDB.Internal.Module.__call_view_anon__( + id, + args, + sink + ) + }; #endif } diff --git a/crates/bindings-csharp/Runtime/Internal/Module.cs b/crates/bindings-csharp/Runtime/Internal/Module.cs index 83e04453964..e6fd46a265a 100644 --- a/crates/bindings-csharp/Runtime/Internal/Module.cs +++ b/crates/bindings-csharp/Runtime/Internal/Module.cs @@ -265,6 +265,36 @@ private static void EnsureNativeAotTypeRoots() private static readonly List viewDispatchers = []; private static readonly List anonymousViewDispatchers = []; + private static class ReducerCache + where R : IReducer, new() + { + public static readonly R Instance = new(); + } + + private static class ProcedureCache

+ where P : IProcedure, new() + { + public static readonly P Instance = new(); + } + + private static class HttpHandlerCache + where H : IHttpHandler, new() + { + public static readonly H Instance = new(); + } + + private static class ViewDispatcherCache + where TDispatcher : IView, new() + { + public static readonly TDispatcher Instance = new(); + } + + private static class AnonymousViewDispatcherCache + where TDispatcher : IAnonymousView, new() + { + public static readonly TDispatcher Instance = new(); + } + private static Func< Identity, ConnectionId?, @@ -337,7 +367,7 @@ public AlgebraicType.Ref RegisterType(Func public static void RegisterReducer() where R : IReducer, new() { - var reducer = new R(); + var reducer = ReducerCache.Instance; reducers.Add(reducer); moduleDef.RegisterReducer(reducer.MakeReducerDef(typeRegistrar), reducer.Lifecycle); } @@ -345,7 +375,7 @@ public static void RegisterReducer() public static void RegisterProcedure

() where P : IProcedure, new() { - var procedure = new P(); + var procedure = ProcedureCache

.Instance; procedures.Add(procedure); moduleDef.RegisterProcedure(procedure.MakeProcedureDef(typeRegistrar)); } @@ -353,7 +383,7 @@ public static void RegisterProcedure

() public static void RegisterHttpHandler() where H : IHttpHandler, new() { - var handler = new H(); + var handler = HttpHandlerCache.Instance; httpHandlers.Add(handler); moduleDef.RegisterHttpHandler(handler.MakeHandlerDef()); } @@ -394,7 +424,7 @@ public static void RegisterTable() public static void RegisterView() where TDispatcher : IView, new() { - var dispatcher = new TDispatcher(); + var dispatcher = ViewDispatcherCache.Instance; var def = dispatcher.MakeViewDef(typeRegistrar); viewDispatchers.Add(dispatcher); moduleDef.RegisterView(def); @@ -403,7 +433,7 @@ public static void RegisterView() public static void RegisterAnonymousView() where TDispatcher : IAnonymousView, new() { - var dispatcher = new TDispatcher(); + var dispatcher = AnonymousViewDispatcherCache.Instance; var def = dispatcher.MakeAnonymousViewDef(typeRegistrar); anonymousViewDispatchers.Add(dispatcher); moduleDef.RegisterView(def); @@ -579,6 +609,50 @@ BytesSink error } } + public static Errno __call_reducer__( + ulong sender_0, + ulong sender_1, + ulong sender_2, + ulong sender_3, + ulong conn_id_0, + ulong conn_id_1, + Timestamp timestamp, + BytesSource args, + BytesSink error + ) + where R : IReducer, new() + { + try + { + var senderIdentity = Identity.From( + MemoryMarshal.AsBytes([sender_0, sender_1, sender_2, sender_3]).ToArray() + ); + var connectionId = ConnectionId.From( + MemoryMarshal.AsBytes([conn_id_0, conn_id_1]).ToArray() + ); + var random = new Random((int)timestamp.MicrosecondsSinceUnixEpoch); + var time = timestamp.ToStd(); + + var ctx = newReducerContext!(senderIdentity, connectionId, random, time); + + using var stream = args.Consume(ref reducerArgsBuffer); + using var reader = new BinaryReader(stream); + ReducerCache.Instance.Invoke(reader, ctx); + if (stream.Position != stream.Length) + { + throw new Exception("Unrecognised extra bytes in the reducer arguments"); + } + return Errno.OK; /* no exception */ + } + catch (Exception e) + { + var error_str = e.Message ?? e.GetType().FullName ?? e.GetType().Name; + var error_bytes = System.Text.Encoding.UTF8.GetBytes(error_str); + error.Write(error_bytes); + return Errno.HOST_CALL_FAILURE; + } + } + public static Errno __call_procedure__( int id, ulong sender_0, @@ -624,6 +698,50 @@ BytesSink resultSink } } + public static Errno __call_procedure__

( + ulong sender_0, + ulong sender_1, + ulong sender_2, + ulong sender_3, + ulong conn_id_0, + ulong conn_id_1, + Timestamp timestamp, + BytesSource args, + BytesSink resultSink + ) + where P : IProcedure, new() + { + try + { + var sender = Identity.From( + MemoryMarshal.AsBytes([sender_0, sender_1, sender_2, sender_3]).ToArray() + ); + var connectionId = ConnectionId.From( + MemoryMarshal.AsBytes([conn_id_0, conn_id_1]).ToArray() + ); + var random = new Random((int)timestamp.MicrosecondsSinceUnixEpoch); + var time = timestamp.ToStd(); + + var ctx = newProcedureContext!(sender, connectionId, random, time); + + using var stream = args.Consume(ref procedureArgsBuffer); + using var reader = new BinaryReader(stream); + var bytes = ProcedureCache

.Instance.Invoke(reader, ctx); + if (stream.Position != stream.Length) + { + throw new Exception("Unrecognised extra bytes in the procedure arguments"); + } + resultSink.Write(bytes); + + return Errno.OK; + } + catch (Exception e) + { + Log.Error($"Error while invoking procedure: {e}"); + throw; + } + } + public static Errno __call_http_handler__( int id, Timestamp timestamp, @@ -668,6 +786,51 @@ BytesSink responseBodySink } } + public static Errno __call_http_handler__( + Timestamp timestamp, + BytesSource request, + BytesSource requestBody, + BytesSink responseSink, + BytesSink responseBodySink + ) + where H : IHttpHandler, new() + { + try + { + var random = new Random((int)timestamp.MicrosecondsSinceUnixEpoch); + var time = timestamp.ToStd(); + var ctx = newHandlerContext!(random, time); + + using var stream = request.Consume(ref httpRequestBuffer); + using var reader = new BinaryReader(stream); + var requestWire = new HttpRequestWire.BSATN().Read(reader); + if (stream.Position != stream.Length) + { + throw new Exception("Unrecognised extra bytes in the HTTP handler request"); + } + + var response = HttpHandlerCache.Instance.Invoke( + ctx, + SpacetimeDB.HttpClient.FromWire( + requestWire, + requestBody.Consume(ref httpRequestBodyBuffer).ToArray() + ) + ); + var (responseWire, responseBody) = SpacetimeDB.HttpClient.ToWire(response); + responseSink.Write( + IStructuralReadWrite.ToBytes(new HttpResponseWire.BSATN(), responseWire) + ); + responseBodySink.Write(responseBody); + + return Errno.OK; + } + catch (Exception e) + { + Log.Error($"Error while invoking HTTP handler: {e}"); + throw; + } + } + ///

/// Called by the host to execute a view when the sender calls the view identified by . /// @@ -721,6 +884,35 @@ BytesSink rows } } + public static Errno __call_view__( + ulong sender_0, + ulong sender_1, + ulong sender_2, + ulong sender_3, + BytesSource args, + BytesSink rows + ) + where TDispatcher : IView, new() + { + try + { + var sender = Identity.From( + MemoryMarshal.AsBytes([sender_0, sender_1, sender_2, sender_3]).ToArray() + ); + var ctx = newViewContext!(sender); + using var stream = args.Consume(ref viewArgsBuffer); + using var reader = new BinaryReader(stream); + var bytes = ViewDispatcherCache.Instance.Invoke(reader, ctx); + rows.Write(bytes); + return (Errno)2; + } + catch (Exception e) + { + Log.Error($"Error while invoking view: {e}"); + return Errno.HOST_CALL_FAILURE; + } + } + /// /// Called by the host to execute an anonymous view. /// @@ -758,6 +950,25 @@ public static Errno __call_view_anon__(int id, BytesSource args, BytesSink rows) return Errno.HOST_CALL_FAILURE; } } + + public static Errno __call_view_anon__(BytesSource args, BytesSink rows) + where TDispatcher : IAnonymousView, new() + { + try + { + var ctx = newAnonymousViewContext!(); + using var stream = args.Consume(ref anonymousViewArgsBuffer); + using var reader = new BinaryReader(stream); + var bytes = AnonymousViewDispatcherCache.Instance.Invoke(reader, ctx); + rows.Write(bytes); + return (Errno)2; + } + catch (Exception e) + { + Log.Error($"Error while invoking anonymous view: {e}"); + return Errno.HOST_CALL_FAILURE; + } + } } /// From bca31d76f6c2cc3adb35fa358a56ae0a16914c45 Mon Sep 17 00:00:00 2001 From: Lisandro Crespo Date: Thu, 13 Aug 2026 10:42:57 -0500 Subject: [PATCH 2/2] Remove unnecessary ToArray() --- crates/bindings-csharp/Runtime/Internal/Module.cs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/crates/bindings-csharp/Runtime/Internal/Module.cs b/crates/bindings-csharp/Runtime/Internal/Module.cs index e6fd46a265a..fca33f525f8 100644 --- a/crates/bindings-csharp/Runtime/Internal/Module.cs +++ b/crates/bindings-csharp/Runtime/Internal/Module.cs @@ -625,11 +625,9 @@ BytesSink error try { var senderIdentity = Identity.From( - MemoryMarshal.AsBytes([sender_0, sender_1, sender_2, sender_3]).ToArray() - ); - var connectionId = ConnectionId.From( - MemoryMarshal.AsBytes([conn_id_0, conn_id_1]).ToArray() + MemoryMarshal.AsBytes([sender_0, sender_1, sender_2, sender_3]) ); + var connectionId = ConnectionId.From(MemoryMarshal.AsBytes([conn_id_0, conn_id_1])); var random = new Random((int)timestamp.MicrosecondsSinceUnixEpoch); var time = timestamp.ToStd(); @@ -714,11 +712,9 @@ BytesSink resultSink try { var sender = Identity.From( - MemoryMarshal.AsBytes([sender_0, sender_1, sender_2, sender_3]).ToArray() - ); - var connectionId = ConnectionId.From( - MemoryMarshal.AsBytes([conn_id_0, conn_id_1]).ToArray() + MemoryMarshal.AsBytes([sender_0, sender_1, sender_2, sender_3]) ); + var connectionId = ConnectionId.From(MemoryMarshal.AsBytes([conn_id_0, conn_id_1])); var random = new Random((int)timestamp.MicrosecondsSinceUnixEpoch); var time = timestamp.ToStd(); @@ -897,7 +893,7 @@ BytesSink rows try { var sender = Identity.From( - MemoryMarshal.AsBytes([sender_0, sender_1, sender_2, sender_3]).ToArray() + MemoryMarshal.AsBytes([sender_0, sender_1, sender_2, sender_3]) ); var ctx = newViewContext!(sender); using var stream = args.Consume(ref viewArgsBuffer);