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 e6df8c9e52a..1045907b398 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__( uint 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 1602df16086..ae1b988c644 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__( uint 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 1ce8d795d15..27ad1324446 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__( uint 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 34040525b94..f15d89a4cb9 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__( uint 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/AuthCtx.cs b/crates/bindings-csharp/Runtime/AuthCtx.cs index a99ebe7d21c..7bf844719fc 100644 --- a/crates/bindings-csharp/Runtime/AuthCtx.cs +++ b/crates/bindings-csharp/Runtime/AuthCtx.cs @@ -4,6 +4,8 @@ namespace SpacetimeDB; public sealed class AuthCtx { + private static byte[] jwtBuffer = new byte[0x10_000]; + private readonly bool _isInternal; private readonly Lazy _jwtLazy; @@ -47,11 +49,12 @@ private static AuthCtx FromConnectionId(ConnectionId connectionId, Identity iden { var result = SpacetimeDB.Internal.FFI.get_jwt(ref connectionId, out var source); SpacetimeDB.Internal.FFI.CheckedStatus.Marshaller.ConvertToManaged(result); - var bytes = SpacetimeDB.Internal.Module.Consume(source); - if (bytes == null || bytes.Length == 0) + using var stream = SpacetimeDB.Internal.Module.Consume(source, ref jwtBuffer); + if (stream.Length == 0) { return null; } + var bytes = stream.ToArray(); var jwt = System.Text.Encoding.UTF8.GetString(bytes); return jwt != null ? new JwtClaims(jwt, identity) : null; } diff --git a/crates/bindings-csharp/Runtime/Http.cs b/crates/bindings-csharp/Runtime/Http.cs index 2567f4a11e5..78850782590 100644 --- a/crates/bindings-csharp/Runtime/Http.cs +++ b/crates/bindings-csharp/Runtime/Http.cs @@ -155,6 +155,9 @@ public sealed class HttpError(string message) : Exception(message) public sealed class HttpClient { private static readonly TimeSpan MaxTimeout = TimeSpan.FromMilliseconds(500); + private static byte[] responseWireBuffer = new byte[0x10_000]; + private static byte[] responseBodyBuffer = new byte[0x10_000]; + private static byte[] errorWireBuffer = new byte[0x10_000]; /// /// Send a simple GET request to with no headers. @@ -341,10 +344,10 @@ out var out_ { case Errno.OK: { - var responseWireBytes = out_.A.Consume(); + var responseWireBytes = out_.A.Consume(ref responseWireBuffer).ToArray(); var responseWire = FromBytes(new HttpResponseWire.BSATN(), responseWireBytes); - var body = new HttpBody(out_.B.Consume()); + var body = new HttpBody(out_.B.Consume(ref responseBodyBuffer).ToArray()); var (statusCode, version, headers) = FromWireResponse(responseWire); return Result.Ok( @@ -353,7 +356,7 @@ out var out_ } case Errno.HTTP_ERROR: { - var errorWireBytes = out_.A.Consume(); + var errorWireBytes = out_.A.Consume(ref errorWireBuffer).ToArray(); var err = FromBytes(new SpacetimeDB.BSATN.String(), errorWireBytes); return Result.Err(new HttpError(err)); } diff --git a/crates/bindings-csharp/Runtime/Internal/FFI.cs b/crates/bindings-csharp/Runtime/Internal/FFI.cs index c9f07994f1d..96984a4f281 100644 --- a/crates/bindings-csharp/Runtime/Internal/FFI.cs +++ b/crates/bindings-csharp/Runtime/Internal/FFI.cs @@ -50,6 +50,11 @@ public enum Errno : short HTTP_ERROR = 21, } +internal static class ErrnoExtensions +{ + public static void Check(this Errno status) => FFI.ErrnoHelpers.ThrowIfError(status); +} + #pragma warning disable IDE1006 // Naming Styles - Not applicable to FFI stuff. internal static partial class FFI { diff --git a/crates/bindings-csharp/Runtime/Internal/IIndex.cs b/crates/bindings-csharp/Runtime/Internal/IIndex.cs index 33525924f2d..5b0b9e330f4 100644 --- a/crates/bindings-csharp/Runtime/Internal/IIndex.cs +++ b/crates/bindings-csharp/Runtime/Internal/IIndex.cs @@ -44,7 +44,7 @@ out ReadOnlySpan rend } protected IEnumerable DoFilter(Bounds bounds) - where Bounds : IBTreeIndexBounds => new RawTableIter(indexId, bounds).Parse(); + where Bounds : IBTreeIndexBounds => new RawTableIter(indexId, bounds); protected uint DoDelete(Bounds bounds) where Bounds : IBTreeIndexBounds @@ -129,7 +129,7 @@ out var numDeleted new RW().Write(w, key); var point = s.ToArray(); - using var e = new RawPointIter(indexId, point).Parse().GetEnumerator(); + using var e = new RawPointIter(indexId, point).GetEnumerator(); if (!e.MoveNext()) { return null; @@ -192,7 +192,7 @@ out var numDeleted new RW().Write(w, key); var point = s.ToArray(); - using var e = new RawPointIter(indexId, point).Parse().GetEnumerator(); + using var e = new RawPointIter(indexId, point).GetEnumerator(); if (!e.MoveNext()) { return null; @@ -241,7 +241,7 @@ protected override void IterStart(out FFI.RowIter handle) => new RW().Write(w, key); var point = s.ToArray(); - using var e = new RawPointIter(indexId, point).Parse().GetEnumerator(); + using var e = new RawPointIter(indexId, point).GetEnumerator(); if (!e.MoveNext()) { return null; @@ -280,7 +280,7 @@ protected override void IterStart(out FFI.RowIter handle) => new RW().Write(w, key); var point = s.ToArray(); - using var e = new RawPointIter(indexId, point).Parse().GetEnumerator(); + using var e = new RawPointIter(indexId, point).GetEnumerator(); if (!e.MoveNext()) { return null; @@ -319,5 +319,5 @@ protected ulong DoCount() return count; } - protected IEnumerable DoIter() => new TableIter(tableId).Parse(); + protected IEnumerable DoIter() => new TableIter(tableId); } diff --git a/crates/bindings-csharp/Runtime/Internal/ITable.cs b/crates/bindings-csharp/Runtime/Internal/ITable.cs index a322216a1d3..7b284f5eb66 100644 --- a/crates/bindings-csharp/Runtime/Internal/ITable.cs +++ b/crates/bindings-csharp/Runtime/Internal/ITable.cs @@ -1,34 +1,26 @@ namespace SpacetimeDB.Internal; using System.Buffers; +using System.Collections; using SpacetimeDB.BSATN; -internal abstract class RawTableIterBase +internal abstract class RawTableIterBase : IEnumerable where T : IStructuralReadWrite, new() { - public sealed class Enumerator(FFI.RowIter handle) : IDisposable - { - private const int InitialBufferSize = 1024; - private byte[]? buffer = ArrayPool.Shared.Rent(InitialBufferSize); - public ArraySegment Current { get; private set; } = ArraySegment.Empty; - - public bool MoveNext() - { - if (handle == FFI.RowIter.INVALID) - { - return false; - } + private const int InitialBufferSize = 1024; - if (buffer is null) - { - return false; - } + protected abstract void IterStart(out FFI.RowIter handle); - uint buffer_len; - while (true) + public IEnumerator GetEnumerator() + { + IterStart(out var handle); + var buffer = ArrayPool.Shared.Rent(InitialBufferSize); + try + { + while (handle != FFI.RowIter.INVALID) { var requested_len = (uint)buffer.Length; - buffer_len = requested_len; + var buffer_len = requested_len; var ret = FFI.row_iter_bsatn_advance(handle, buffer, ref buffer_len); if (ret == Errno.EXHAUSTED) { @@ -38,82 +30,50 @@ public bool MoveNext() buffer_len = 0; } } + // On success, the only way `buffer_len == 0` is for the iterator to be exhausted. // This happens when the host iterator was empty from the start. System.Diagnostics.Debug.Assert(!(ret == Errno.OK && buffer_len == 0)); switch (ret) { - // 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, update `Current` to point at the valid range in the scratch `buffer`. case Errno.EXHAUSTED or Errno.OK: - Current = new ArraySegment(buffer, 0, (int)buffer_len); - return buffer_len != 0; - // Couldn't find the iterator, error! - case Errno.NO_SUCH_ITER: - throw new NoSuchIterException(); - // The scratch `buffer` is too small to fit a row / chunk. - // Grow `buffer` and try again. - // The `buffer_len` will have been updated with the necessary size. + { + using var stream = new MemoryStream( + buffer, + 0, + (int)buffer_len, + writable: false, + publiclyVisible: true + ); + using var reader = new BinaryReader(stream); + while (stream.Position < stream.Length) + { + yield return IStructuralReadWrite.Read(reader); + } + break; + } case Errno.BUFFER_TOO_SMALL: ArrayPool.Shared.Return(buffer); buffer = ArrayPool.Shared.Rent((int)buffer_len); - continue; + break; default: - throw new UnknownException(ret); + ret.Check(); + break; } } } - - public void Dispose() + finally { if (handle != FFI.RowIter.INVALID) { FFI.row_iter_bsatn_close(handle); - handle = FFI.RowIter.INVALID; } - - if (buffer is not null) - { - ArrayPool.Shared.Return(buffer); - buffer = null; - } - } - - public void Reset() - { - throw new NotImplementedException(); + ArrayPool.Shared.Return(buffer); } } - protected abstract void IterStart(out FFI.RowIter handle); - - // Note: using the GetEnumerator() duck-typing protocol instead of IEnumerable to avoid extra boxing. - public Enumerator GetEnumerator() - { - IterStart(out var handle); - return new(handle); - } - - public IEnumerable Parse() - { - foreach (var chunk in this) - { - using var stream = new MemoryStream( - chunk.Array!, - chunk.Offset, - chunk.Count, - writable: false, - publiclyVisible: true - ); - using var reader = new BinaryReader(stream); - while (stream.Position < stream.Length) - { - yield return IStructuralReadWrite.Read(reader); - } - } - } + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } public interface ITableView @@ -166,7 +126,7 @@ protected static ulong DoCount() return count; } - protected static IEnumerable DoIter() => new RawTableIter(tableId).Parse(); + protected static IEnumerable DoIter() => new RawTableIter(tableId); protected static T DoInsert(T row) { diff --git a/crates/bindings-csharp/Runtime/Internal/Module.cs b/crates/bindings-csharp/Runtime/Internal/Module.cs index eebd573cfc5..ca31682ae08 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); @@ -439,11 +469,11 @@ public static void RegisterExplicitFunctionName(string sourceName, string canoni public static void RegisterExplicitIndexName(string sourceName, string canonicalName) => moduleDef.RegisterExplicitIndexName(sourceName, canonicalName); - public static byte[] Consume(this BytesSource source) + internal static MemoryStream Consume(this BytesSource source, ref byte[] buffer) { if (source == BytesSource.INVALID) { - return []; + return new(); } var len = (uint)0; @@ -458,42 +488,28 @@ public static byte[] Consume(this BytesSource source) throw new UnknownException(ret); } - var buffer = new byte[len]; + if (buffer.Length < len) + { + Array.Resize(ref buffer, (int)len); + } + var written = 0U; - // Because we've reserved space in our buffer already, this loop should be unnecessary. - // We expect the first call to `bytes_source_read` to always return `-1`. - // I (pgoldman 2025-09-26) am leaving the loop here because there's no downside to it, - // and in the future we may want to support `BytesSource`s which don't have a known length ahead of time - // (i.e. put arbitrary streams in `BytesSource` on the host side rather than just `Bytes` buffers), - // at which point the loop will become useful again. while (true) { - // Write into the spare capacity of the buffer. var spare = buffer.AsSpan((int)written); var buf_len = (uint)spare.Length; ret = FFI.bytes_source_read(source, spare, ref buf_len); written += buf_len; switch (ret) { - // Host side source exhausted, we're done. case Errno.EXHAUSTED: - Array.Resize(ref buffer, (int)written); - return buffer; - // Wrote the entire spare capacity. - // Need to reserve more space in the buffer. + return new(buffer, 0, (int)written); case Errno.OK when written == buffer.Length: Array.Resize(ref buffer, buffer.Length + 1024); break; - // Host didn't write as much as possible. - // Try to read some more. - // The host will likely not trigger this branch (current host doesn't), - // but a module should be prepared for it. case Errno.OK: + ret.Check(); break; - case Errno.NO_SUCH_BYTES: - throw new NoSuchBytesException(); - default: - throw new UnknownException(ret); } } } @@ -510,6 +526,14 @@ private static void Write(this BytesSink sink, byte[] bytes) } } + // __call_reducer__ is not invoked in parallel because modules do not support multithreading in Wasm. + private static byte[] reducerArgsBuffer = new byte[0x10_000]; + private static byte[] procedureArgsBuffer = new byte[0x10_000]; + private static byte[] httpRequestBuffer = new byte[0x10_000]; + private static byte[] httpRequestBodyBuffer = new byte[0x10_000]; + private static byte[] viewArgsBuffer = new byte[0x10_000]; + private static byte[] anonymousViewArgsBuffer = new byte[0x10_000]; + #pragma warning disable IDE1006 // Naming Styles - methods below are meant for FFI. public static void __describe_module__(BytesSink description) @@ -554,7 +578,7 @@ BytesSink error var ctx = newReducerContext!(senderIdentity, connectionId, random, time); - using var stream = new MemoryStream(args.Consume()); + using var stream = args.Consume(ref reducerArgsBuffer); using var reader = new BinaryReader(stream); reducers[(int)id].Invoke(reader, ctx); if (stream.Position != stream.Length) @@ -572,6 +596,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__( uint id, ulong sender_0, @@ -598,7 +666,7 @@ BytesSink resultSink var ctx = newProcedureContext!(sender, connectionId, random, time); - using var stream = new MemoryStream(args.Consume()); + using var stream = args.Consume(ref procedureArgsBuffer); using var reader = new BinaryReader(stream); var bytes = procedures[(int)id].Invoke(reader, ctx); if (stream.Position != stream.Length) @@ -619,6 +687,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__( uint id, Timestamp timestamp, @@ -634,8 +746,7 @@ BytesSink responseBodySink var time = timestamp.ToStd(); var ctx = newHandlerContext!(random, time); - var requestBytes = request.Consume(); - using var stream = new MemoryStream(requestBytes); + 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) @@ -644,7 +755,58 @@ BytesSink responseBodySink } var response = httpHandlers[(int)id] - .Invoke(ctx, SpacetimeDB.HttpClient.FromWire(requestWire, requestBody.Consume())); + .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; + } + } + + 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) @@ -700,7 +862,7 @@ BytesSink rows MemoryMarshal.AsBytes([sender_0, sender_1, sender_2, sender_3]).ToArray() ); var ctx = newViewContext!(sender); - using var stream = new MemoryStream(args.Consume()); + using var stream = args.Consume(ref viewArgsBuffer); using var reader = new BinaryReader(stream); var bytes = viewDispatchers[(int)id].Invoke(reader, ctx); rows.Write(bytes); @@ -713,6 +875,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. /// @@ -738,7 +929,7 @@ public static Errno __call_view_anon__(uint id, BytesSource args, BytesSink rows try { var ctx = newAnonymousViewContext!(); - using var stream = new MemoryStream(args.Consume()); + using var stream = args.Consume(ref anonymousViewArgsBuffer); using var reader = new BinaryReader(stream); var bytes = anonymousViewDispatchers[(int)id].Invoke(reader, ctx); rows.Write(bytes); @@ -750,6 +941,25 @@ public static Errno __call_view_anon__(uint 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; + } + } } ///