Skip to content

Commit 10bbb80

Browse files
committed
Fix fields named 'read'
Add header comment CSharpier More comments
1 parent 14ba750 commit 10bbb80

31 files changed

+704
-579
lines changed

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

+50-18
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
namespace SpacetimeDB.Codegen;
22

3+
// Generate code to implement serialization to the BSATN format (https://spacetimedb.com/docs/bsatn).
4+
// C# doesn't support static methods in interfaces, so instead we declare a zero-sized `struct` type that implements
5+
// the serialization interface (IReadWrite) for us.
6+
//
7+
// See BSATN.Runtime for the support code referenced by code generation,
8+
// and see Codegen.Tests/fixtures/*/snapshots for examples of generated code.
9+
// Also, if you set <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles> in a csproj,
10+
// you can find the generated code in obj/Debug/*/generated/SpacetimeDB.BSATN.Codegen.
11+
312
using System.Collections.Immutable;
413
using Microsoft.CodeAnalysis;
514
using Microsoft.CodeAnalysis.CSharp;
@@ -13,6 +22,17 @@ public record MemberDeclaration(
1322
bool IsNullableReferenceType
1423
)
1524
{
25+
internal static string BSATN_FIELD_SUFFIX = "RW";
26+
27+
/// <summary>
28+
/// The name of the static field containing an IReadWrite in the IReadWrite struct associated with this type.
29+
/// We make sure this is different from the field name so that collisions cannot occur.
30+
/// </summary>
31+
public string BsatnFieldName
32+
{
33+
get => $"{Name}{BSATN_FIELD_SUFFIX}";
34+
}
35+
1636
public MemberDeclaration(ISymbol member, ITypeSymbol type, DiagReporter diag)
1737
: this(member.Name, SymbolToName(type), "", Utils.IsNullableReferenceType(type))
1838
{
@@ -46,14 +66,20 @@ IEnumerable<MemberDeclaration> members
4666
var visStr = SyntaxFacts.GetText(visibility);
4767
return string.Join(
4868
"\n ",
49-
members.Select(m => $"{visStr} static readonly {m.TypeInfo} {m.Name} = new();")
69+
members.Select(m =>
70+
$"{visStr} static readonly {m.TypeInfo} {m.BsatnFieldName} = new();"
71+
)
5072
);
5173
}
5274

5375
public static string GenerateDefs(IEnumerable<MemberDeclaration> members) =>
5476
string.Join(
5577
",\n ",
56-
members.Select(m => $"new(nameof({m.Name}), {m.Name}.GetAlgebraicType(registrar))")
78+
// we can't use nameof(m.BsatnFieldName) because the bsatn field name differs from the logical name
79+
// assigned in the type.
80+
members.Select(m =>
81+
$"new(\"{m.Name}\", {m.BsatnFieldName}.GetAlgebraicType(registrar))"
82+
)
5783
);
5884
}
5985

@@ -166,27 +192,33 @@ public Scope.Extensions ToExtensions()
166192
var extensions = new Scope.Extensions(Scope, FullName);
167193

168194
var bsatnDecls = Members.Cast<MemberDeclaration>();
169-
var fieldNames = bsatnDecls.Select(m => m.Name);
170195

171196
extensions.BaseTypes.Add($"System.IEquatable<{ShortName}>");
172197

173198
if (Kind is TypeKind.Sum)
174199
{
200+
var enumTag = new MemberDeclaration(
201+
"__enumTag",
202+
"@enum",
203+
"SpacetimeDB.BSATN.Enum<@enum>",
204+
false
205+
);
206+
175207
extensions.Contents.Append(
176208
$$"""
177209
private {{ShortName}}() { }
178210
179211
internal enum @enum: byte
180212
{
181-
{{string.Join(",\n ", fieldNames)}}
213+
{{string.Join(",\n ", bsatnDecls.Select(decl => decl.Name))}}
182214
}
183215
184216
"""
185217
);
186218
extensions.Contents.Append(
187219
string.Join(
188220
"\n",
189-
Members.Select(m =>
221+
bsatnDecls.Select(m =>
190222
// C# puts field names in the same namespace as records themselves, and will complain about clashes if they match.
191223
// To avoid this, we append an underscore to the field name.
192224
// In most cases the field name shouldn't matter anyway as you'll idiomatically use pattern matching to extract the value.
@@ -203,11 +235,11 @@ public override string ToString() =>
203235
);
204236

205237
read = $$"""
206-
__enumTag.Read(reader) switch {
238+
{{enumTag.BsatnFieldName}}.Read(reader) switch {
207239
{{string.Join(
208240
"\n ",
209-
fieldNames.Select(name =>
210-
$"@enum.{name} => new {name}({name}.Read(reader)),"
241+
bsatnDecls.Select(m =>
242+
$"@enum.{m.Name} => new {m.Name}({m.BsatnFieldName}.Read(reader)),"
211243
)
212244
)}}
213245
_ => throw new System.InvalidOperationException("Invalid tag value, this state should be unreachable.")
@@ -218,10 +250,10 @@ public override string ToString() =>
218250
switch (value) {
219251
{{string.Join(
220252
"\n",
221-
fieldNames.Select(name => $"""
222-
case {name}(var inner):
223-
__enumTag.Write(writer, @enum.{name});
224-
{name}.Write(writer, inner);
253+
bsatnDecls.Select(m => $"""
254+
case {m.Name}(var inner):
255+
{enumTag.BsatnFieldName}.Write(writer, @enum.{m.Name});
256+
{m.BsatnFieldName}.Write(writer, inner);
225257
break;
226258
"""))}}
227259
}
@@ -255,9 +287,9 @@ public override string ToString() =>
255287
}
256288
""";
257289

258-
bsatnDecls = bsatnDecls.Prepend(
259-
new("__enumTag", "@enum", "SpacetimeDB.BSATN.Enum<@enum>", false)
260-
);
290+
// It's important that this happen here; only the stuff later in this method
291+
// needs to see the enum tag as one of the bsatn declarations.
292+
bsatnDecls = bsatnDecls.Prepend(enumTag);
261293
}
262294
else
263295
{
@@ -268,14 +300,14 @@ public override string ToString() =>
268300
public void ReadFields(System.IO.BinaryReader reader) {
269301
{{string.Join(
270302
"\n",
271-
fieldNames.Select(name => $" {name} = BSATN.{name}.Read(reader);")
303+
bsatnDecls.Select(m => $" {m.Name} = BSATN.{m.BsatnFieldName}.Read(reader);")
272304
)}}
273305
}
274306
275307
public void WriteFields(System.IO.BinaryWriter writer) {
276308
{{string.Join(
277309
"\n",
278-
fieldNames.Select(name => $" BSATN.{name}.Write(writer, {name});")
310+
bsatnDecls.Select(m => $" BSATN.{m.BsatnFieldName}.Write(writer, {m.Name});")
279311
)}}
280312
}
281313
@@ -291,7 +323,7 @@ public void WriteFields(System.IO.BinaryWriter writer) {
291323
public override string ToString() =>
292324
$"{{ShortName}} {{start}} {{string.Join(
293325
", ",
294-
fieldNames.Select(name => $$"""{{name}} = {SpacetimeDB.BSATN.StringUtil.GenericToString({{name}})}""")
326+
bsatnDecls.Select(m => $$"""{{m.Name}} = {SpacetimeDB.BSATN.StringUtil.GenericToString({{m.Name}})}""")
295327
)}} {{end}}";
296328
"""
297329
);

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

+8-8
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,23 @@ partial struct CustomClass : System.IEquatable<CustomClass>, SpacetimeDB.BSATN.I
66
{
77
public void ReadFields(System.IO.BinaryReader reader)
88
{
9-
IntField = BSATN.IntField.Read(reader);
10-
StringField = BSATN.StringField.Read(reader);
9+
IntField = BSATN.IntFieldRW.Read(reader);
10+
StringField = BSATN.StringFieldRW.Read(reader);
1111
}
1212

1313
public void WriteFields(System.IO.BinaryWriter writer)
1414
{
15-
BSATN.IntField.Write(writer, IntField);
16-
BSATN.StringField.Write(writer, StringField);
15+
BSATN.IntFieldRW.Write(writer, IntField);
16+
BSATN.StringFieldRW.Write(writer, StringField);
1717
}
1818

1919
public override string ToString() =>
2020
$"CustomClass {{ IntField = {SpacetimeDB.BSATN.StringUtil.GenericToString(IntField)}, StringField = {SpacetimeDB.BSATN.StringUtil.GenericToString(StringField)} }}";
2121

2222
public readonly partial struct BSATN : SpacetimeDB.BSATN.IReadWrite<CustomClass>
2323
{
24-
internal static readonly SpacetimeDB.BSATN.I32 IntField = new();
25-
internal static readonly SpacetimeDB.BSATN.String StringField = new();
24+
internal static readonly SpacetimeDB.BSATN.I32 IntFieldRW = new();
25+
internal static readonly SpacetimeDB.BSATN.String StringFieldRW = new();
2626

2727
public CustomClass Read(System.IO.BinaryReader reader) =>
2828
SpacetimeDB.BSATN.IStructuralReadWrite.Read<CustomClass>(reader);
@@ -38,8 +38,8 @@ SpacetimeDB.BSATN.ITypeRegistrar registrar
3838
registrar.RegisterType<CustomClass>(_ => new SpacetimeDB.BSATN.AlgebraicType.Product(
3939
new SpacetimeDB.BSATN.AggregateElement[]
4040
{
41-
new(nameof(IntField), IntField.GetAlgebraicType(registrar)),
42-
new(nameof(StringField), StringField.GetAlgebraicType(registrar))
41+
new("IntField", IntFieldRW.GetAlgebraicType(registrar)),
42+
new("StringField", StringFieldRW.GetAlgebraicType(registrar))
4343
}
4444
));
4545

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

+8-8
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,23 @@ partial struct CustomStruct
88
{
99
public void ReadFields(System.IO.BinaryReader reader)
1010
{
11-
IntField = BSATN.IntField.Read(reader);
12-
StringField = BSATN.StringField.Read(reader);
11+
IntField = BSATN.IntFieldRW.Read(reader);
12+
StringField = BSATN.StringFieldRW.Read(reader);
1313
}
1414

1515
public void WriteFields(System.IO.BinaryWriter writer)
1616
{
17-
BSATN.IntField.Write(writer, IntField);
18-
BSATN.StringField.Write(writer, StringField);
17+
BSATN.IntFieldRW.Write(writer, IntField);
18+
BSATN.StringFieldRW.Write(writer, StringField);
1919
}
2020

2121
public override string ToString() =>
2222
$"CustomStruct {{ IntField = {SpacetimeDB.BSATN.StringUtil.GenericToString(IntField)}, StringField = {SpacetimeDB.BSATN.StringUtil.GenericToString(StringField)} }}";
2323

2424
public readonly partial struct BSATN : SpacetimeDB.BSATN.IReadWrite<CustomStruct>
2525
{
26-
internal static readonly SpacetimeDB.BSATN.I32 IntField = new();
27-
internal static readonly SpacetimeDB.BSATN.String StringField = new();
26+
internal static readonly SpacetimeDB.BSATN.I32 IntFieldRW = new();
27+
internal static readonly SpacetimeDB.BSATN.String StringFieldRW = new();
2828

2929
public CustomStruct Read(System.IO.BinaryReader reader) =>
3030
SpacetimeDB.BSATN.IStructuralReadWrite.Read<CustomStruct>(reader);
@@ -40,8 +40,8 @@ SpacetimeDB.BSATN.ITypeRegistrar registrar
4040
registrar.RegisterType<CustomStruct>(_ => new SpacetimeDB.BSATN.AlgebraicType.Product(
4141
new SpacetimeDB.BSATN.AggregateElement[]
4242
{
43-
new(nameof(IntField), IntField.GetAlgebraicType(registrar)),
44-
new(nameof(StringField), StringField.GetAlgebraicType(registrar))
43+
new("IntField", IntFieldRW.GetAlgebraicType(registrar)),
44+
new("StringField", StringFieldRW.GetAlgebraicType(registrar))
4545
}
4646
));
4747

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

+12-12
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,15 @@ public override string ToString() =>
2626

2727
public readonly partial struct BSATN : SpacetimeDB.BSATN.IReadWrite<CustomTaggedEnum>
2828
{
29-
internal static readonly SpacetimeDB.BSATN.Enum<@enum> __enumTag = new();
30-
internal static readonly SpacetimeDB.BSATN.I32 IntVariant = new();
31-
internal static readonly SpacetimeDB.BSATN.String StringVariant = new();
29+
internal static readonly SpacetimeDB.BSATN.Enum<@enum> __enumTagRW = new();
30+
internal static readonly SpacetimeDB.BSATN.I32 IntVariantRW = new();
31+
internal static readonly SpacetimeDB.BSATN.String StringVariantRW = new();
3232

3333
public CustomTaggedEnum Read(System.IO.BinaryReader reader) =>
34-
__enumTag.Read(reader) switch
34+
__enumTagRW.Read(reader) switch
3535
{
36-
@enum.IntVariant => new IntVariant(IntVariant.Read(reader)),
37-
@enum.StringVariant => new StringVariant(StringVariant.Read(reader)),
36+
@enum.IntVariant => new IntVariant(IntVariantRW.Read(reader)),
37+
@enum.StringVariant => new StringVariant(StringVariantRW.Read(reader)),
3838
_
3939
=> throw new System.InvalidOperationException(
4040
"Invalid tag value, this state should be unreachable."
@@ -46,12 +46,12 @@ public void Write(System.IO.BinaryWriter writer, CustomTaggedEnum value)
4646
switch (value)
4747
{
4848
case IntVariant(var inner):
49-
__enumTag.Write(writer, @enum.IntVariant);
50-
IntVariant.Write(writer, inner);
49+
__enumTagRW.Write(writer, @enum.IntVariant);
50+
IntVariantRW.Write(writer, inner);
5151
break;
5252
case StringVariant(var inner):
53-
__enumTag.Write(writer, @enum.StringVariant);
54-
StringVariant.Write(writer, inner);
53+
__enumTagRW.Write(writer, @enum.StringVariant);
54+
StringVariantRW.Write(writer, inner);
5555
break;
5656
}
5757
}
@@ -62,8 +62,8 @@ SpacetimeDB.BSATN.ITypeRegistrar registrar
6262
registrar.RegisterType<CustomTaggedEnum>(_ => new SpacetimeDB.BSATN.AlgebraicType.Sum(
6363
new SpacetimeDB.BSATN.AggregateElement[]
6464
{
65-
new(nameof(IntVariant), IntVariant.GetAlgebraicType(registrar)),
66-
new(nameof(StringVariant), StringVariant.GetAlgebraicType(registrar))
65+
new("IntVariant", IntVariantRW.GetAlgebraicType(registrar)),
66+
new("StringVariant", StringVariantRW.GetAlgebraicType(registrar))
6767
}
6868
));
6969

0 commit comments

Comments
 (0)