Skip to content

Commit 7bfc1a6

Browse files
committed
Add method to IStructuralReadWrite to get an IReadWrite<Self>. This is technically a breaking change if anyone is manually implementing IStructuralReadWrite.
1 parent afdc188 commit 7bfc1a6

29 files changed

+215
-0
lines changed

crates/bindings-csharp/BSATN.Codegen/Type.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,10 @@ public void WriteFields(System.IO.BinaryWriter writer) {
512512
)}}
513513
}
514514
515+
object SpacetimeDB.BSATN.IStructuralReadWrite.GetSerializer() {
516+
return new BSATN();
517+
}
518+
515519
"""
516520
);
517521

crates/bindings-csharp/BSATN.Runtime/BSATN/Runtime.cs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,61 @@ namespace SpacetimeDB.BSATN;
22

33
using System.Text;
44

5+
/// <summary>
6+
/// Implemented by product types marked with [SpacetimeDB.Type].
7+
/// All rows in SpacetimeDB are product types, so this is also implemented by all row types.
8+
///
9+
/// </summary>
510
public interface IStructuralReadWrite
611
{
12+
/// <summary>
13+
/// Initialize this value from the reader.
14+
/// The reader is assumed to store a <see href="https://spacetimedb.com/docs/bsatn">BSATN-encoded</see>
15+
/// value of this type.
16+
/// Advances the reader to the first byte past the end of the read value.
17+
/// Throws an exception if this would advance past the end of the reader.
18+
/// </summary>
19+
/// <param name="reader"></param>
720
void ReadFields(BinaryReader reader);
821

22+
/// <summary>
23+
/// Write the fields of this type to the writer.
24+
/// Throws an exception if the underlying writer throws.
25+
/// Throws if this value is malformed (i.e. has null values for fields that
26+
/// are not explicitly marked nullable.)
27+
/// </summary>
28+
/// <param name="writer"></param>
929
void WriteFields(BinaryWriter writer);
1030

31+
/// <summary>
32+
/// Get an IReadWrite implementation that can read values of this type.
33+
/// In Rust, this would return <c>IReadWrite&lt;Self&gt;</c>, but the C# type system
34+
/// has no equivalent Self type -- that is, you can't use the implementing type in type signatures
35+
/// in an interface. So, you have to manually downcast.
36+
/// A typical invocation looks like: <c>(IReadWrite&lt;Row&gt;) new Row().GetSerializer()</c>
37+
///
38+
/// This is an instance method because of limitations of C# interfaces.
39+
/// (C# 11 has static virtual interface members, but Unity does not support C# 11.)
40+
/// This method always works, whether or not the row it is called on is correctly initialized.
41+
/// The returned serializer has nothing to do with the row GetSerializer is called on -- it returns
42+
/// new rows and does not modify or interact with the original row.
43+
///
44+
/// Using the resulting serializer rather than <c>Read&lt;T&gt;</c> is usually faster in Mono/IL2CPP.
45+
/// This is because we manually monomorphise the code to read rows in our automatically-generated
46+
/// implementation of IReadWrite. This allows rows to be initialized with new() rather than reflection
47+
/// in the generated code.
48+
/// </summary>
49+
/// <returns>An <c>IReadWrite&lt;T&gt;</c> for <c>T : IStructuralReadWrite</c>.</returns>
50+
object GetSerializer();
51+
52+
/// <summary>
53+
/// Read a row from the reader.
54+
/// This method usually uses Activator.CreateInstance to create the resulting row;
55+
/// if this is too slow, prefer using GetSerializer.
56+
/// </summary>
57+
/// <typeparam name="T"></typeparam>
58+
/// <param name="reader"></param>
59+
/// <returns></returns>
1160
static T Read<T>(BinaryReader reader)
1261
where T : IStructuralReadWrite, new()
1362
{
@@ -38,12 +87,34 @@ public static byte[] ToBytes<T>(T value)
3887
}
3988
}
4089

90+
/// <summary>
91+
/// Interface for types that know how to serialize another type.
92+
/// We auto-generate an implementation of <c>IReadWrite&lt;T&gt;</c> for all
93+
/// types marked with <c>[SpacetimeDB.Type]</c>. For a type <c>T</c>, this implementation
94+
/// is accessible at <c>T.BSATN</c>. The implementation is always a zero-sized struct.
95+
/// </summary>
96+
/// <typeparam name="T"></typeparam>
4197
public interface IReadWrite<T>
4298
{
99+
/// <summary>
100+
/// Read a BSATN-encoded value of type T from the reader.
101+
/// Throws on end-of-stream or if the stream is malformed.
102+
/// Advances the reader to the first byte past the end of the encoded value.
103+
/// </summary>
104+
/// <param name="reader"></param>
105+
/// <returns></returns>
43106
T Read(BinaryReader reader);
44107

108+
/// <summary>
109+
/// Write a BSATN-encoded value of type T to the writer.
110+
/// </summary>
45111
void Write(BinaryWriter writer, T value);
46112

113+
/// <summary>
114+
/// Get metadata for this type. Used in module initialization.
115+
/// </summary>
116+
/// <param name="registrar"></param>
117+
/// <returns></returns>
47118
AlgebraicType GetAlgebraicType(ITypeRegistrar registrar);
48119
}
49120

crates/bindings-csharp/BSATN.Runtime/Builtins.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,11 @@ public readonly void WriteFields(BinaryWriter writer)
392392
BSATN.MicrosecondsSinceUnixEpoch.Write(writer, MicrosecondsSinceUnixEpoch);
393393
}
394394

395+
readonly object IStructuralReadWrite.GetSerializer()
396+
{
397+
return new BSATN();
398+
}
399+
395400
public readonly partial struct BSATN : IReadWrite<Timestamp>
396401
{
397402
internal static readonly I64 MicrosecondsSinceUnixEpoch = new();
@@ -463,6 +468,11 @@ public readonly void WriteFields(BinaryWriter writer)
463468
BSATN.__time_duration_micros__.Write(writer, Microseconds);
464469
}
465470

471+
readonly object IStructuralReadWrite.GetSerializer()
472+
{
473+
return new BSATN();
474+
}
475+
466476
public readonly partial struct BSATN : IReadWrite<TimeDuration>
467477
{
468478
internal static readonly I64 __time_duration_micros__ = new();

crates/bindings-csharp/Codegen.Tests/fixtures/client/snapshots/Type#CustomClass.verified.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ public void WriteFields(System.IO.BinaryWriter writer)
1616
BSATN.StringField.Write(writer, StringField);
1717
}
1818

19+
object SpacetimeDB.BSATN.IStructuralReadWrite.GetSerializer()
20+
{
21+
return new BSATN();
22+
}
23+
1924
public override string ToString() =>
2025
$"CustomClass {{ IntField = {SpacetimeDB.BSATN.StringUtil.GenericToString(IntField)}, StringField = {SpacetimeDB.BSATN.StringUtil.GenericToString(StringField)} }}";
2126

crates/bindings-csharp/Codegen.Tests/fixtures/client/snapshots/Type#CustomStruct.verified.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ public void WriteFields(System.IO.BinaryWriter writer)
1818
BSATN.StringField.Write(writer, StringField);
1919
}
2020

21+
object SpacetimeDB.BSATN.IStructuralReadWrite.GetSerializer()
22+
{
23+
return new BSATN();
24+
}
25+
2126
public override string ToString() =>
2227
$"CustomStruct {{ IntField = {SpacetimeDB.BSATN.StringUtil.GenericToString(IntField)}, StringField = {SpacetimeDB.BSATN.StringUtil.GenericToString(StringField)} }}";
2328

crates/bindings-csharp/Codegen.Tests/fixtures/client/snapshots/Type#PublicTable.verified.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@ public void WriteFields(System.IO.BinaryWriter writer)
6262
BSATN.NullableReferenceField.Write(writer, NullableReferenceField);
6363
}
6464

65+
object SpacetimeDB.BSATN.IStructuralReadWrite.GetSerializer()
66+
{
67+
return new BSATN();
68+
}
69+
6570
public override string ToString() =>
6671
$"PublicTable {{ ByteField = {SpacetimeDB.BSATN.StringUtil.GenericToString(ByteField)}, UshortField = {SpacetimeDB.BSATN.StringUtil.GenericToString(UshortField)}, UintField = {SpacetimeDB.BSATN.StringUtil.GenericToString(UintField)}, UlongField = {SpacetimeDB.BSATN.StringUtil.GenericToString(UlongField)}, U128Field = {SpacetimeDB.BSATN.StringUtil.GenericToString(U128Field)}, U256Field = {SpacetimeDB.BSATN.StringUtil.GenericToString(U256Field)}, SbyteField = {SpacetimeDB.BSATN.StringUtil.GenericToString(SbyteField)}, ShortField = {SpacetimeDB.BSATN.StringUtil.GenericToString(ShortField)}, IntField = {SpacetimeDB.BSATN.StringUtil.GenericToString(IntField)}, LongField = {SpacetimeDB.BSATN.StringUtil.GenericToString(LongField)}, I128Field = {SpacetimeDB.BSATN.StringUtil.GenericToString(I128Field)}, I256Field = {SpacetimeDB.BSATN.StringUtil.GenericToString(I256Field)}, BoolField = {SpacetimeDB.BSATN.StringUtil.GenericToString(BoolField)}, FloatField = {SpacetimeDB.BSATN.StringUtil.GenericToString(FloatField)}, DoubleField = {SpacetimeDB.BSATN.StringUtil.GenericToString(DoubleField)}, StringField = {SpacetimeDB.BSATN.StringUtil.GenericToString(StringField)}, IdentityField = {SpacetimeDB.BSATN.StringUtil.GenericToString(IdentityField)}, ConnectionIdField = {SpacetimeDB.BSATN.StringUtil.GenericToString(ConnectionIdField)}, CustomStructField = {SpacetimeDB.BSATN.StringUtil.GenericToString(CustomStructField)}, CustomClassField = {SpacetimeDB.BSATN.StringUtil.GenericToString(CustomClassField)}, CustomEnumField = {SpacetimeDB.BSATN.StringUtil.GenericToString(CustomEnumField)}, CustomTaggedEnumField = {SpacetimeDB.BSATN.StringUtil.GenericToString(CustomTaggedEnumField)}, ListField = {SpacetimeDB.BSATN.StringUtil.GenericToString(ListField)}, NullableValueField = {SpacetimeDB.BSATN.StringUtil.GenericToString(NullableValueField)}, NullableReferenceField = {SpacetimeDB.BSATN.StringUtil.GenericToString(NullableReferenceField)} }}";
6772

crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module#InAnotherNamespace.TestDuplicateTableName.verified.cs

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module#TestAutoIncNotInteger.verified.cs

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module#TestDuplicateTableName.verified.cs

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module#TestIndexIssues.verified.cs

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module#TestScheduleIssues.verified.cs

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module#TestUniqueNotEquatable.verified.cs

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Type#TestTypeParams_T_.verified.cs

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Type#TestUnsupportedType.verified.cs

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/bindings-csharp/Codegen.Tests/fixtures/server/snapshots/Module#BTreeMultiColumn.verified.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ public void WriteFields(System.IO.BinaryWriter writer)
2020
BSATN.Z.Write(writer, Z);
2121
}
2222

23+
object SpacetimeDB.BSATN.IStructuralReadWrite.GetSerializer()
24+
{
25+
return new BSATN();
26+
}
27+
2328
public override string ToString() =>
2429
$"BTreeMultiColumn {{ X = {SpacetimeDB.BSATN.StringUtil.GenericToString(X)}, Y = {SpacetimeDB.BSATN.StringUtil.GenericToString(Y)}, Z = {SpacetimeDB.BSATN.StringUtil.GenericToString(Z)} }}";
2530

crates/bindings-csharp/Codegen.Tests/fixtures/server/snapshots/Module#BTreeViews.verified.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ public void WriteFields(System.IO.BinaryWriter writer)
2020
BSATN.Faction.Write(writer, Faction);
2121
}
2222

23+
object SpacetimeDB.BSATN.IStructuralReadWrite.GetSerializer()
24+
{
25+
return new BSATN();
26+
}
27+
2328
public override string ToString() =>
2429
$"BTreeViews {{ Id = {SpacetimeDB.BSATN.StringUtil.GenericToString(Id)}, X = {SpacetimeDB.BSATN.StringUtil.GenericToString(X)}, Y = {SpacetimeDB.BSATN.StringUtil.GenericToString(Y)}, Faction = {SpacetimeDB.BSATN.StringUtil.GenericToString(Faction)} }}";
2530

crates/bindings-csharp/Codegen.Tests/fixtures/server/snapshots/Module#MultiTableRow.verified.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ public void WriteFields(System.IO.BinaryWriter writer)
2020
BSATN.Bar.Write(writer, Bar);
2121
}
2222

23+
object SpacetimeDB.BSATN.IStructuralReadWrite.GetSerializer()
24+
{
25+
return new BSATN();
26+
}
27+
2328
public override string ToString() =>
2429
$"MultiTableRow {{ Name = {SpacetimeDB.BSATN.StringUtil.GenericToString(Name)}, Foo = {SpacetimeDB.BSATN.StringUtil.GenericToString(Foo)}, Bar = {SpacetimeDB.BSATN.StringUtil.GenericToString(Bar)} }}";
2530

crates/bindings-csharp/Codegen.Tests/fixtures/server/snapshots/Module#PrivateTable.verified.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ public void ReadFields(System.IO.BinaryReader reader) { }
88

99
public void WriteFields(System.IO.BinaryWriter writer) { }
1010

11+
object SpacetimeDB.BSATN.IStructuralReadWrite.GetSerializer()
12+
{
13+
return new BSATN();
14+
}
15+
1116
public override string ToString() => $"PrivateTable {{ }}";
1217

1318
public readonly partial struct BSATN : SpacetimeDB.BSATN.IReadWrite<PrivateTable>

crates/bindings-csharp/Codegen.Tests/fixtures/server/snapshots/Module#PublicTable.verified.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ public void WriteFields(System.IO.BinaryWriter writer)
6868
BSATN.NullableReferenceField.Write(writer, NullableReferenceField);
6969
}
7070

71+
object SpacetimeDB.BSATN.IStructuralReadWrite.GetSerializer()
72+
{
73+
return new BSATN();
74+
}
75+
7176
public override string ToString() =>
7277
$"PublicTable {{ Id = {SpacetimeDB.BSATN.StringUtil.GenericToString(Id)}, ByteField = {SpacetimeDB.BSATN.StringUtil.GenericToString(ByteField)}, UshortField = {SpacetimeDB.BSATN.StringUtil.GenericToString(UshortField)}, UintField = {SpacetimeDB.BSATN.StringUtil.GenericToString(UintField)}, UlongField = {SpacetimeDB.BSATN.StringUtil.GenericToString(UlongField)}, UInt128Field = {SpacetimeDB.BSATN.StringUtil.GenericToString(UInt128Field)}, U128Field = {SpacetimeDB.BSATN.StringUtil.GenericToString(U128Field)}, U256Field = {SpacetimeDB.BSATN.StringUtil.GenericToString(U256Field)}, SbyteField = {SpacetimeDB.BSATN.StringUtil.GenericToString(SbyteField)}, ShortField = {SpacetimeDB.BSATN.StringUtil.GenericToString(ShortField)}, IntField = {SpacetimeDB.BSATN.StringUtil.GenericToString(IntField)}, LongField = {SpacetimeDB.BSATN.StringUtil.GenericToString(LongField)}, Int128Field = {SpacetimeDB.BSATN.StringUtil.GenericToString(Int128Field)}, I128Field = {SpacetimeDB.BSATN.StringUtil.GenericToString(I128Field)}, I256Field = {SpacetimeDB.BSATN.StringUtil.GenericToString(I256Field)}, BoolField = {SpacetimeDB.BSATN.StringUtil.GenericToString(BoolField)}, FloatField = {SpacetimeDB.BSATN.StringUtil.GenericToString(FloatField)}, DoubleField = {SpacetimeDB.BSATN.StringUtil.GenericToString(DoubleField)}, StringField = {SpacetimeDB.BSATN.StringUtil.GenericToString(StringField)}, IdentityField = {SpacetimeDB.BSATN.StringUtil.GenericToString(IdentityField)}, ConnectionIdField = {SpacetimeDB.BSATN.StringUtil.GenericToString(ConnectionIdField)}, CustomStructField = {SpacetimeDB.BSATN.StringUtil.GenericToString(CustomStructField)}, CustomClassField = {SpacetimeDB.BSATN.StringUtil.GenericToString(CustomClassField)}, CustomEnumField = {SpacetimeDB.BSATN.StringUtil.GenericToString(CustomEnumField)}, CustomTaggedEnumField = {SpacetimeDB.BSATN.StringUtil.GenericToString(CustomTaggedEnumField)}, ListField = {SpacetimeDB.BSATN.StringUtil.GenericToString(ListField)}, NullableValueField = {SpacetimeDB.BSATN.StringUtil.GenericToString(NullableValueField)}, NullableReferenceField = {SpacetimeDB.BSATN.StringUtil.GenericToString(NullableReferenceField)} }}";
7378

crates/bindings-csharp/Codegen.Tests/fixtures/server/snapshots/Module#RegressionMultipleUniqueIndexesHadSameName.verified.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ public void WriteFields(System.IO.BinaryWriter writer)
1818
BSATN.Unique2.Write(writer, Unique2);
1919
}
2020

21+
object SpacetimeDB.BSATN.IStructuralReadWrite.GetSerializer()
22+
{
23+
return new BSATN();
24+
}
25+
2126
public override string ToString() =>
2227
$"RegressionMultipleUniqueIndexesHadSameName {{ Unique1 = {SpacetimeDB.BSATN.StringUtil.GenericToString(Unique1)}, Unique2 = {SpacetimeDB.BSATN.StringUtil.GenericToString(Unique2)} }}";
2328

crates/bindings-csharp/Codegen.Tests/fixtures/server/snapshots/Module#Timers.SendMessageTimer.verified.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ public void WriteFields(System.IO.BinaryWriter writer)
2222
BSATN.Text.Write(writer, Text);
2323
}
2424

25+
object SpacetimeDB.BSATN.IStructuralReadWrite.GetSerializer()
26+
{
27+
return new BSATN();
28+
}
29+
2530
public override string ToString() =>
2631
$"SendMessageTimer {{ ScheduledId = {SpacetimeDB.BSATN.StringUtil.GenericToString(ScheduledId)}, ScheduledAt = {SpacetimeDB.BSATN.StringUtil.GenericToString(ScheduledAt)}, Text = {SpacetimeDB.BSATN.StringUtil.GenericToString(Text)} }}";
2732

crates/bindings-csharp/Codegen.Tests/fixtures/server/snapshots/Type#ContainsNestedLists.verified.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ public void WriteFields(System.IO.BinaryWriter writer)
3030
BSATN.StringListListArray.Write(writer, StringListListArray);
3131
}
3232

33+
object SpacetimeDB.BSATN.IStructuralReadWrite.GetSerializer()
34+
{
35+
return new BSATN();
36+
}
37+
3338
public override string ToString() =>
3439
$"ContainsNestedLists {{ IntList = {SpacetimeDB.BSATN.StringUtil.GenericToString(IntList)}, StringList = {SpacetimeDB.BSATN.StringUtil.GenericToString(StringList)}, IntArray = {SpacetimeDB.BSATN.StringUtil.GenericToString(IntArray)}, StringArray = {SpacetimeDB.BSATN.StringUtil.GenericToString(StringArray)}, IntArrayArrayList = {SpacetimeDB.BSATN.StringUtil.GenericToString(IntArrayArrayList)}, IntListListArray = {SpacetimeDB.BSATN.StringUtil.GenericToString(IntListListArray)}, StringArrayArrayList = {SpacetimeDB.BSATN.StringUtil.GenericToString(StringArrayArrayList)}, StringListListArray = {SpacetimeDB.BSATN.StringUtil.GenericToString(StringListListArray)} }}";
3540

crates/bindings-csharp/Codegen.Tests/fixtures/server/snapshots/Type#CustomClass.verified.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ public void WriteFields(System.IO.BinaryWriter writer)
2020
BSATN.NullableStringField.Write(writer, NullableStringField);
2121
}
2222

23+
object SpacetimeDB.BSATN.IStructuralReadWrite.GetSerializer()
24+
{
25+
return new BSATN();
26+
}
27+
2328
public override string ToString() =>
2429
$"CustomClass {{ IntField = {SpacetimeDB.BSATN.StringUtil.GenericToString(IntField)}, StringField = {SpacetimeDB.BSATN.StringUtil.GenericToString(StringField)}, NullableIntField = {SpacetimeDB.BSATN.StringUtil.GenericToString(NullableIntField)}, NullableStringField = {SpacetimeDB.BSATN.StringUtil.GenericToString(NullableStringField)} }}";
2530

0 commit comments

Comments
 (0)