@@ -8,15 +8,15 @@ namespace SpacetimeDB.Codegen;
8
8
9
9
/// <summary>
10
10
/// The type of a member of one of the types we are generating code for.
11
- ///
11
+ ///
12
12
/// Knows how to serialize and deserialize the member.
13
- ///
13
+ ///
14
14
/// Also knows how to compare the member for equality and compute its hash code.
15
15
/// We can't just use Equals and GetHashCode for this, because they implement reference
16
16
/// equality for arrays and Lists.
17
- ///
17
+ ///
18
18
/// (It would be nice to be able to dynamically build EqualityComparers at runtime
19
- /// to do these operations, but this seems to require either (A) reflective calls
19
+ /// to do these operations, but this seems to require either (A) reflective calls
20
20
/// or (B) instantiating generics at runtime. These are (A) slow and (B) very slow
21
21
/// when compiling under IL2CPP. Instead, we just inline the needed loops to compute
22
22
/// the relevant values. This is very simple for IL2CPP to optimize.
@@ -25,10 +25,7 @@ namespace SpacetimeDB.Codegen;
25
25
/// </summary>
26
26
/// <param name="Name">The name of the type</param>
27
27
/// <param name="BSATNName">The name of the BSATN struct for the type.</param>
28
- public abstract record TypeUse (
29
- string Name ,
30
- string BSATNName
31
- )
28
+ public abstract record TypeUse ( string Name , string BSATNName )
32
29
{
33
30
/// <summary>
34
31
/// Parse a type use for a member.
@@ -63,13 +60,21 @@ public static TypeUse Parse(ISymbol member, ITypeSymbol typeSymbol, DiagReporter
63
60
return typeSymbol switch
64
61
{
65
62
ITypeParameterSymbol => new ReferenceUse ( type , typeInfo ) ,
66
- IArrayTypeSymbol { ElementType : var elementType } => new ArrayUse ( type , typeInfo , Parse ( member , elementType , diag ) ) ,
63
+ IArrayTypeSymbol { ElementType : var elementType } => new ArrayUse (
64
+ type ,
65
+ typeInfo ,
66
+ Parse ( member , elementType , diag )
67
+ ) ,
67
68
INamedTypeSymbol named => named . OriginalDefinition . ToString ( ) switch
68
69
{
69
- "System.Collections.Generic.List<T>" => new ListUse ( type , typeInfo , Parse ( member , named . TypeArguments [ 0 ] , diag ) ) ,
70
- _ => named . IsValueType ?
71
- new ValueUse ( type , typeInfo ) :
72
- new ReferenceUse ( type , typeInfo )
70
+ "System.Collections.Generic.List<T>" => new ListUse (
71
+ type ,
72
+ typeInfo ,
73
+ Parse ( member , named . TypeArguments [ 0 ] , diag )
74
+ ) ,
75
+ _ => named . IsValueType
76
+ ? new ValueUse ( type , typeInfo )
77
+ : new ReferenceUse ( type , typeInfo ) ,
73
78
} ,
74
79
_ => throw new InvalidOperationException ( $ "Unsupported type { type } ") ,
75
80
} ;
@@ -80,18 +85,24 @@ public static TypeUse Parse(ISymbol member, ITypeSymbol typeSymbol, DiagReporter
80
85
/// logically-equals is:
81
86
/// - the same as to SequenceEquals for arrays and lists
82
87
/// - otherwise, just .Equals.
83
- ///
88
+ ///
84
89
/// This can't be an expression because some types need to use loops.
85
90
/// </summary>
86
91
/// <param name="inVar1">A variable of type `Type` that we want to hash.</param>
87
92
/// <param name="inVar2">A variable of type `Type` that we want to hash.</param>
88
93
/// <param name="outVar">The variable to declare and store the `Equals` bool in.</param>
89
94
/// <param name="level">Iteration level counter. You don't need to set this.</param>
90
95
/// <returns></returns>
91
- public abstract string EqualsStatement ( string inVar1 , string inVar2 , string outVar , int level = 0 ) ;
96
+ public abstract string EqualsStatement (
97
+ string inVar1 ,
98
+ string inVar2 ,
99
+ string outVar ,
100
+ int level = 0
101
+ ) ;
102
+
92
103
/// <summary>
93
104
/// Get a statement that declares outVar and assigns assigns the hash code of inVar to it.
94
- ///
105
+ ///
95
106
/// This can't be an expression because some types need to use loops.
96
107
/// </summary>
97
108
/// <param name="inVar">A variable of type `Type` that we want to hash.</param>
@@ -101,16 +112,20 @@ public static TypeUse Parse(ISymbol member, ITypeSymbol typeSymbol, DiagReporter
101
112
public abstract string GetHashCodeStatement ( string inVar , string outVar , int level = 0 ) ;
102
113
}
103
114
104
-
105
115
/// <summary>
106
116
/// A use of a value type.
107
117
/// </summary>
108
118
/// <param name="Type"></param>
109
119
/// <param name="TypeInfo"></param>
110
120
public record ValueUse ( string Type , string TypeInfo ) : TypeUse ( Type , TypeInfo )
111
121
{
112
- public override string EqualsStatement ( string inVar1 , string inVar2 , string outVar , int level = 0 ) =>
113
- $ "var { outVar } = { inVar1 } .Equals({ inVar2 } );";
122
+ public override string EqualsStatement (
123
+ string inVar1 ,
124
+ string inVar2 ,
125
+ string outVar ,
126
+ int level = 0
127
+ ) => $ "var { outVar } = { inVar1 } .Equals({ inVar2 } );";
128
+
114
129
public override string GetHashCodeStatement ( string inVar , string outVar , int level = 0 ) =>
115
130
$ "var { outVar } = { inVar } .GetHashCode();";
116
131
}
@@ -122,8 +137,13 @@ public override string GetHashCodeStatement(string inVar, string outVar, int lev
122
137
/// <param name="TypeInfo"></param>
123
138
public record ReferenceUse ( string Type , string TypeInfo ) : TypeUse ( Type , TypeInfo )
124
139
{
125
- public override string EqualsStatement ( string inVar1 , string inVar2 , string outVar , int level = 0 ) =>
126
- $ "var { outVar } = { inVar1 } == null ? { inVar2 } == null : { inVar1 } .Equals({ inVar2 } );";
140
+ public override string EqualsStatement (
141
+ string inVar1 ,
142
+ string inVar2 ,
143
+ string outVar ,
144
+ int level = 0
145
+ ) => $ "var { outVar } = { inVar1 } == null ? { inVar2 } == null : { inVar1 } .Equals({ inVar2 } );";
146
+
127
147
public override string GetHashCodeStatement ( string inVar , string outVar , int level = 0 ) =>
128
148
$ "var { outVar } = { inVar } == null ? 0 : { inVar } .GetHashCode();";
129
149
}
@@ -136,27 +156,37 @@ public override string GetHashCodeStatement(string inVar, string outVar, int lev
136
156
/// <param name="ElementType"></param>
137
157
public record ArrayUse ( string Type , string TypeInfo , TypeUse ElementType ) : TypeUse ( Type , TypeInfo )
138
158
{
139
- public override string EqualsStatement ( string inVar1 , string inVar2 , string outVar , int level = 0 )
159
+ public override string EqualsStatement (
160
+ string inVar1 ,
161
+ string inVar2 ,
162
+ string outVar ,
163
+ int level = 0
164
+ )
140
165
{
141
166
var iterVar = $ "i{ level } ";
142
167
var innerOutVar = $ "{ outVar } { level + 1 } ";
143
168
144
169
return $$ """
145
- var {{ outVar }} = true;
146
- if ({{ inVar1 }} == null || {{ inVar2 }} == null) {
147
- {{ outVar }} = {{ inVar1 }} == {{ inVar2 }} ;
148
- } else if ({{ inVar1 }} .Length != {{ inVar2 }} .Length) {
149
- {{ outVar }} = false;
150
- } else {
151
- for (int {{ iterVar }} = 0; {{ iterVar }} < {{ inVar1 }} .Length; {{ iterVar }} ++) {
152
- {{ ElementType . EqualsStatement ( $ "{ inVar1 } [{ iterVar } ]", $ "{ inVar2 } [{ iterVar } ]", innerOutVar , level + 1 ) }}
153
- if (!{{ innerOutVar }} ) {
154
- {{ outVar }} = false;
155
- break;
170
+ var {{ outVar }} = true;
171
+ if ({{ inVar1 }} == null || {{ inVar2 }} == null) {
172
+ {{ outVar }} = {{ inVar1 }} == {{ inVar2 }} ;
173
+ } else if ({{ inVar1 }} .Length != {{ inVar2 }} .Length) {
174
+ {{ outVar }} = false;
175
+ } else {
176
+ for (int {{ iterVar }} = 0; {{ iterVar }} < {{ inVar1 }} .Length; {{ iterVar }} ++) {
177
+ {{ ElementType . EqualsStatement (
178
+ $ "{ inVar1 } [{ iterVar } ]",
179
+ $ "{ inVar2 } [{ iterVar } ]",
180
+ innerOutVar ,
181
+ level + 1
182
+ ) }}
183
+ if (!{{ innerOutVar }} ) {
184
+ {{ outVar }} = false;
185
+ break;
186
+ }
156
187
}
157
188
}
158
- }
159
- """ ;
189
+ """ ;
160
190
}
161
191
162
192
public override string GetHashCodeStatement ( string inVar , string outVar , int level = 0 )
@@ -166,16 +196,20 @@ public override string GetHashCodeStatement(string inVar, string outVar, int lev
166
196
var innerOutVar = $ "{ outVar } { level + 1 } ";
167
197
168
198
return $$ """
169
- var {{ outVar }} = 0;
170
- if ({{ inVar }} != null) {
171
- var {{ innerHashCode }} = new System.HashCode();
172
- for (int {{ iterVar }} = 0; {{ iterVar }} < {{ inVar }} .Length; {{ iterVar }} ++) {
173
- {{ ElementType . GetHashCodeStatement ( $ "{ inVar } [{ iterVar } ]", innerOutVar , level + 1 ) }}
174
- {{ innerHashCode }} .Add({{ innerOutVar }} );
199
+ var {{ outVar }} = 0;
200
+ if ({{ inVar }} != null) {
201
+ var {{ innerHashCode }} = new System.HashCode();
202
+ for (int {{ iterVar }} = 0; {{ iterVar }} < {{ inVar }} .Length; {{ iterVar }} ++) {
203
+ {{ ElementType . GetHashCodeStatement (
204
+ $ "{ inVar } [{ iterVar } ]",
205
+ innerOutVar ,
206
+ level + 1
207
+ ) }}
208
+ {{ innerHashCode }} .Add({{ innerOutVar }} );
209
+ }
210
+ {{ outVar }} = {{ innerHashCode }} .ToHashCode();
175
211
}
176
- {{ outVar }} = {{ innerHashCode }} .ToHashCode();
177
- }
178
- """ ;
212
+ """ ;
179
213
}
180
214
}
181
215
@@ -187,7 +221,12 @@ public override string GetHashCodeStatement(string inVar, string outVar, int lev
187
221
/// <param name="ElementType"></param>
188
222
public record ListUse ( string Type , string TypeInfo , TypeUse ElementType ) : TypeUse ( Type , TypeInfo )
189
223
{
190
- public override string EqualsStatement ( string inVar1 , string inVar2 , string outVar , int level = 0 )
224
+ public override string EqualsStatement (
225
+ string inVar1 ,
226
+ string inVar2 ,
227
+ string outVar ,
228
+ int level = 0
229
+ )
191
230
{
192
231
var iterVar = $ "i{ level } ";
193
232
// needed to avoid warnings on list re-reference.
@@ -196,23 +235,23 @@ public override string EqualsStatement(string inVar1, string inVar2, string outV
196
235
var innerOutVar = $ "{ outVar } { level + 1 } ";
197
236
198
237
return $$ """
199
- var {{ outVar }} = true;
200
- if ({{ inVar1 }} == null || {{ inVar2 }} == null) {
201
- {{ outVar }} = {{ inVar1 }} == {{ inVar2 }} ;
202
- } else if ({{ inVar1 }} .Count != {{ inVar2 }} .Count) {
203
- {{ outVar }} = false;
204
- } else {
205
- for (int {{ iterVar }} = 0; {{ iterVar }} < {{ inVar1 }} .Count; {{ iterVar }} ++) {
206
- var {{ innerTmp1 }} = {{ inVar1 }} [{{ iterVar }} ];
207
- var {{ innerTmp2 }} = {{ inVar2 }} [{{ iterVar }} ];
208
- {{ ElementType . EqualsStatement ( innerTmp1 , innerTmp2 , innerOutVar , level + 1 ) }}
209
- if (!{{ innerOutVar }} ) {
210
- {{ outVar }} = false;
211
- break;
238
+ var {{ outVar }} = true;
239
+ if ({{ inVar1 }} == null || {{ inVar2 }} == null) {
240
+ {{ outVar }} = {{ inVar1 }} == {{ inVar2 }} ;
241
+ } else if ({{ inVar1 }} .Count != {{ inVar2 }} .Count) {
242
+ {{ outVar }} = false;
243
+ } else {
244
+ for (int {{ iterVar }} = 0; {{ iterVar }} < {{ inVar1 }} .Count; {{ iterVar }} ++) {
245
+ var {{ innerTmp1 }} = {{ inVar1 }} [{{ iterVar }} ];
246
+ var {{ innerTmp2 }} = {{ inVar2 }} [{{ iterVar }} ];
247
+ {{ ElementType . EqualsStatement ( innerTmp1 , innerTmp2 , innerOutVar , level + 1 ) }}
248
+ if (!{{ innerOutVar }} ) {
249
+ {{ outVar }} = false;
250
+ break;
251
+ }
212
252
}
213
253
}
214
- }
215
- """ ;
254
+ """ ;
216
255
}
217
256
218
257
public override string GetHashCodeStatement ( string inVar , string outVar , int level = 0 )
@@ -223,17 +262,17 @@ public override string GetHashCodeStatement(string inVar, string outVar, int lev
223
262
var innerOutVar = $ "{ outVar } { level + 1 } ";
224
263
225
264
return $$ """
226
- var {{ outVar }} = 0;
227
- if ({{ inVar }} != null) {
228
- var {{ innerHashCode }} = new System.HashCode();
229
- for (int {{ iterVar }} = 0; {{ iterVar }} < {{ inVar }} .Count; {{ iterVar }} ++) {
230
- var {{ innerTmp }} = {{ inVar }} [{{ iterVar }} ];
231
- {{ ElementType . GetHashCodeStatement ( innerTmp , innerOutVar , level + 1 ) }}
232
- {{ innerHashCode }} .Add({{ innerOutVar }} );
265
+ var {{ outVar }} = 0;
266
+ if ({{ inVar }} != null) {
267
+ var {{ innerHashCode }} = new System.HashCode();
268
+ for (int {{ iterVar }} = 0; {{ iterVar }} < {{ inVar }} .Count; {{ iterVar }} ++) {
269
+ var {{ innerTmp }} = {{ inVar }} [{{ iterVar }} ];
270
+ {{ ElementType . GetHashCodeStatement ( innerTmp , innerOutVar , level + 1 ) }}
271
+ {{ innerHashCode }} .Add({{ innerOutVar }} );
272
+ }
273
+ {{ outVar }} = {{ innerHashCode }} .ToHashCode();
233
274
}
234
- {{ outVar }} = {{ innerHashCode }} .ToHashCode();
235
- }
236
- """ ;
275
+ """ ;
237
276
}
238
277
}
239
278
@@ -249,10 +288,7 @@ TypeUse Type
249
288
)
250
289
{
251
290
public MemberDeclaration ( ISymbol member , ITypeSymbol type , DiagReporter diag )
252
- : this ( member . Name , TypeUse . Parse ( member , type , diag ) )
253
- {
254
-
255
- }
291
+ : this ( member . Name , TypeUse . Parse ( member , type , diag ) ) { }
256
292
257
293
public MemberDeclaration ( IFieldSymbol field , DiagReporter diag )
258
294
: this ( field , field . Type , diag ) { }
0 commit comments