Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1047,7 +1047,8 @@ jobs:
run: dotnet restore --configfile ../../../NuGet.Config blackholio.csproj

- name: Build Godot project
run: godot --headless --verbose --path demo/Blackholio/client-godot --build-solutions --quit
working-directory: demo/Blackholio/client-godot
run: godot --headless --verbose --build-solutions --quit

- name: Start SpacetimeDB
run: |
Expand All @@ -1061,7 +1062,8 @@ jobs:
bash ./publish.sh

- name: Run Godot tests
run: godot --headless --path demo/Blackholio/client-godot --scene res://tests/GodotPlayModeTests.tscn
working-directory: demo/Blackholio/client-godot
run: godot --headless --scene res://tests/GodotPlayModeTests.tscn

csharp-testsuite:
needs: [merge_queue_noop, lints]
Expand Down
12 changes: 6 additions & 6 deletions crates/bindings-csharp/BSATN.Codegen/Type.cs
Original file line number Diff line number Diff line change
Expand Up @@ -740,13 +740,13 @@ public override string ToString() =>

write = "value.WriteFields(writer);";

var declHashName = (MemberDeclaration decl) => $"___hash{decl.Name}";
static string DeclHashName(MemberDeclaration decl) => $"___hash{decl.Name}";

getHashCode = $$"""
{{string.Join("\n", bsatnDecls.Select(decl => decl.Type.GetHashCodeStatement(decl.Identifier, declHashName(decl))))}}
{{string.Join("\n", bsatnDecls.Select(decl => decl.Type.GetHashCodeStatement(decl.Identifier, DeclHashName(decl))))}}
return {{JoinOrValue(
" ^\n ",
bsatnDecls.Select(declHashName),
bsatnDecls.Select(DeclHashName),
"0" // if there are no members, the hash is 0.
)}};
""";
Expand Down Expand Up @@ -789,7 +789,7 @@ public override int GetHashCode()
// If we are a reference type, various equality methods need to take nullable references.
// If we are a value type, everything is pleasantly by-value.
var fullNameMaybeRef = $"{FullName}{(Scope.IsStruct ? "" : "?")}";
var declEqualsName = (MemberDeclaration decl) => $"___eq{decl.Name}";
static string DeclEqualsName(MemberDeclaration decl) => $"___eq{decl.Name}";

extensions.Contents.Append(
$$"""
Expand All @@ -798,10 +798,10 @@ public override int GetHashCode()
public bool Equals({{fullNameMaybeRef}} that)
{
{{(Scope.IsStruct ? "" : "if (((object?)that) == null) { return false; }\n ")}}
{{string.Join("\n", bsatnDecls.Select(decl => decl.Type.EqualsStatement($"this.{decl.Identifier}", $"that.{decl.Identifier}", declEqualsName(decl))))}}
{{string.Join("\n", bsatnDecls.Select(decl => decl.Type.EqualsStatement($"this.{decl.Identifier}", $"that.{decl.Identifier}", DeclEqualsName(decl))))}}
return {{JoinOrValue(
" &&\n ",
bsatnDecls.Select(declEqualsName),
bsatnDecls.Select(DeclEqualsName),
"true" // if there are no elements, the structs are equal :)
)}};
}
Expand Down
11 changes: 8 additions & 3 deletions crates/bindings-csharp/BSATN.Runtime/BSATN/Runtime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,9 @@ public interface IReadWrite<T>
/// Note: the [Type] macro rejects enums with explicitly set values (see Codegen.Tests),
/// so this array is guaranteed to be continuous and indexed starting from 0.
/// </summary>
#pragma warning disable CA2263, IDE0305 // netstandard2.1 lacks the generic Enum overloads.
private static readonly T[] TagToValue = Enum.GetValues(typeof(T)).Cast<T>().ToArray();
#pragma warning restore CA2263, IDE0305

public T Read(BinaryReader reader)
{
Expand Down Expand Up @@ -177,9 +179,12 @@ public AlgebraicType GetAlgebraicType(ITypeRegistrar registrar) =>
registrar.RegisterType<T>(
(_) =>
new AlgebraicType.Sum(
Enum.GetNames(typeof(T))
.Select(name => new AggregateElement(name, AlgebraicType.Unit))
.ToArray()
#pragma warning disable CA2263 // netstandard2.1 lacks the generic Enum overloads.
[
.. Enum.GetNames(typeof(T))
.Select(name => new AggregateElement(name, AlgebraicType.Unit)),
]
#pragma warning restore CA2263
)
);
}
Expand Down
4 changes: 2 additions & 2 deletions crates/bindings-csharp/BSATN.Runtime/BSATN/U128.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ public static U128 FromBytesBigEndian(ReadOnlySpan<byte> bytes)
);
}

var upper = BinaryPrimitives.ReadUInt64BigEndian(bytes.Slice(0, 8));
var lower = BinaryPrimitives.ReadUInt64BigEndian(bytes.Slice(8, 8));
var upper = BinaryPrimitives.ReadUInt64BigEndian(bytes[..8]);
var lower = BinaryPrimitives.ReadUInt64BigEndian(bytes[8..16]);

return new U128(upper, lower);
}
Expand Down
38 changes: 19 additions & 19 deletions crates/bindings-csharp/BSATN.Runtime/Builtins.cs
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ public static implicit operator DateTimeOffset(Timestamp t) =>
DateTimeOffset.UnixEpoch.AddTicks(t.MicrosecondsSinceUnixEpoch * Util.TicksPerMicrosecond);

public static implicit operator Timestamp(DateTimeOffset offset) =>
new Timestamp(offset.Subtract(DateTimeOffset.UnixEpoch).Ticks / Util.TicksPerMicrosecond);
new(offset.Subtract(DateTimeOffset.UnixEpoch).Ticks / Util.TicksPerMicrosecond);

// For backwards-compatibility.
public readonly DateTimeOffset ToStd() => this;
Expand All @@ -373,7 +373,7 @@ public override readonly string ToString()
public static readonly Timestamp UNIX_EPOCH = new(0);

public static Timestamp FromTimeDurationSinceUnixEpoch(TimeDuration timeDuration) =>
new Timestamp(timeDuration.Microseconds);
new(timeDuration.Microseconds);

public readonly TimeDuration ToTimeDurationSinceUnixEpoch() => TimeDurationSince(UNIX_EPOCH);

Expand All @@ -383,13 +383,13 @@ public static Timestamp FromTimeSpanSinceUnixEpoch(TimeSpan timeSpan) =>
public readonly TimeSpan ToTimeSpanSinceUnixEpoch() => (TimeSpan)ToTimeDurationSinceUnixEpoch();

public readonly TimeDuration TimeDurationSince(Timestamp earlier) =>
new TimeDuration(checked(MicrosecondsSinceUnixEpoch - earlier.MicrosecondsSinceUnixEpoch));
new(checked(MicrosecondsSinceUnixEpoch - earlier.MicrosecondsSinceUnixEpoch));

public static Timestamp operator +(Timestamp point, TimeDuration interval) =>
new Timestamp(checked(point.MicrosecondsSinceUnixEpoch + interval.Microseconds));
new(checked(point.MicrosecondsSinceUnixEpoch + interval.Microseconds));

public static Timestamp operator -(Timestamp point, TimeDuration interval) =>
new Timestamp(checked(point.MicrosecondsSinceUnixEpoch - interval.Microseconds));
new(checked(point.MicrosecondsSinceUnixEpoch - interval.Microseconds));

public readonly int CompareTo(Timestamp that)
{
Expand Down Expand Up @@ -492,10 +492,10 @@ public static implicit operator TimeDuration(TimeSpan timeSpan) =>
new(timeSpan.Ticks / Util.TicksPerMicrosecond);

public static TimeDuration operator +(TimeDuration lhs, TimeDuration rhs) =>
new TimeDuration(checked(lhs.Microseconds + rhs.Microseconds));
new(checked(lhs.Microseconds + rhs.Microseconds));

public static TimeDuration operator -(TimeDuration lhs, TimeDuration rhs) =>
new TimeDuration(checked(lhs.Microseconds + rhs.Microseconds));
new(checked(lhs.Microseconds + rhs.Microseconds));

// For backwards-compatibility.
public readonly TimeSpan ToStd() => this;
Expand Down Expand Up @@ -574,7 +574,7 @@ long microsSinceUnixEpoch
// --- auto-generated ---
private ScheduleAt() { }

internal enum @enum : byte
internal enum ScheduleAtVariant : byte
{
Interval,
Time,
Expand All @@ -586,15 +586,15 @@ public sealed record Time(Timestamp Time_) : ScheduleAt;

public readonly partial struct BSATN : IReadWrite<ScheduleAt>
{
internal static readonly SpacetimeDB.BSATN.Enum<@enum> __enumTag = new();
internal static readonly SpacetimeDB.BSATN.Enum<ScheduleAtVariant> __enumTag = new();
internal static readonly TimeDuration.BSATN Interval = new();
internal static readonly Timestamp.BSATN Time = new();

public ScheduleAt Read(BinaryReader reader) =>
__enumTag.Read(reader) switch
{
@enum.Interval => new Interval(Interval.Read(reader)),
@enum.Time => new Time(Time.Read(reader)),
ScheduleAtVariant.Interval => new Interval(Interval.Read(reader)),
ScheduleAtVariant.Time => new Time(Time.Read(reader)),
_ => throw new InvalidOperationException(
"Invalid tag value, this state should be unreachable."
),
Expand All @@ -605,12 +605,12 @@ public void Write(BinaryWriter writer, ScheduleAt value)
switch (value)
{
case Interval(var inner):
__enumTag.Write(writer, @enum.Interval);
__enumTag.Write(writer, ScheduleAtVariant.Interval);
Interval.Write(writer, inner);
break;

case Time(var inner):
__enumTag.Write(writer, @enum.Time);
__enumTag.Write(writer, ScheduleAtVariant.Time);
Time.Write(writer, inner);
break;
}
Expand Down Expand Up @@ -682,7 +682,7 @@ public T UnwrapOrElse(Func<E, T> f) =>

private Result() { }

internal enum @enum : byte
internal enum ResultVariant : byte
{
Ok,
Err,
Expand All @@ -702,15 +702,15 @@ private enum Variant : byte
where OkRW : struct, IReadWrite<T>
where ErrRW : struct, IReadWrite<E>
{
private static readonly SpacetimeDB.BSATN.Enum<@enum> __enumTag = new();
private static readonly SpacetimeDB.BSATN.Enum<ResultVariant> __enumTag = new();
private static readonly OkRW okRW = new();
private static readonly ErrRW errRW = new();

public Result<T, E> Read(BinaryReader reader) =>
__enumTag.Read(reader) switch
{
@enum.Ok => new OkR(okRW.Read(reader)),
@enum.Err => new ErrR(errRW.Read(reader)),
ResultVariant.Ok => new OkR(okRW.Read(reader)),
ResultVariant.Err => new ErrR(errRW.Read(reader)),
_ => throw new InvalidOperationException(),
};

Expand All @@ -719,12 +719,12 @@ public void Write(BinaryWriter writer, Result<T, E> value)
switch (value)
{
case OkR(var v):
__enumTag.Write(writer, @enum.Ok);
__enumTag.Write(writer, ResultVariant.Ok);
okRW.Write(writer, v);
break;

case ErrR(var e):
__enumTag.Write(writer, @enum.Err);
__enumTag.Write(writer, ResultVariant.Err);
errRW.Write(writer, e);
break;
}
Expand Down
53 changes: 9 additions & 44 deletions crates/bindings-csharp/BSATN.Runtime/QueryBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
#nullable enable

namespace SpacetimeDB;

using System;
Expand Down Expand Up @@ -68,14 +66,9 @@ public interface IQuery<TRow>
string ToSql();
}

public readonly struct BoolExpr<TRow>
public readonly struct BoolExpr<TRow>(string sql)
{
public string Sql { get; }

public BoolExpr(string sql)
{
Sql = sql;
}
public string Sql { get; } = sql;

public BoolExpr<TRow> And(BoolExpr<TRow> other) => new($"({Sql} AND {other.Sql})");

Expand Down Expand Up @@ -120,18 +113,9 @@ internal IxJoinEq(string leftRefSql, string rightRefSql)
}
}

public readonly struct Col<TRow, TValue>
public readonly struct Col<TRow, TValue>(string tableName, string columnName)
where TValue : notnull
{
private readonly string tableName;
private readonly string columnName;

public Col(string tableName, string columnName)
{
this.tableName = tableName;
this.columnName = columnName;
}

internal string RefSql =>
$"{SqlFormat.QuoteIdent(tableName)}.{SqlFormat.QuoteIdent(columnName)}";

Expand Down Expand Up @@ -162,18 +146,9 @@ public Col(string tableName, string columnName)
public override string ToString() => RefSql;
}

public readonly struct IxCol<TRow, TValue>
public readonly struct IxCol<TRow, TValue>(string tableName, string columnName)
where TValue : notnull
{
private readonly string tableName;
private readonly string columnName;

public IxCol(string tableName, string columnName)
{
this.tableName = tableName;
this.columnName = columnName;
}

internal string RefSql =>
$"{SqlFormat.QuoteIdent(tableName)}.{SqlFormat.QuoteIdent(columnName)}";

Expand All @@ -187,19 +162,9 @@ public IxJoinEq<TRow, TOtherRow> Eq<TOtherRow>(IxCol<TOtherRow, TValue> other) =
public override string ToString() => RefSql;
}

public sealed class Table<TRow, TCols, TIxCols> : IQuery<TRow>
public sealed class Table<TRow, TCols, TIxCols>(string tableName, TCols cols, TIxCols ixCols)
: IQuery<TRow>
{
private readonly string tableName;
private readonly TCols cols;
private readonly TIxCols ixCols;

public Table(string tableName, TCols cols, TIxCols ixCols)
{
this.tableName = tableName;
this.cols = cols;
this.ixCols = ixCols;
}

internal string TableRefSql => SqlFormat.QuoteIdent(tableName);

internal TCols Cols => cols;
Expand Down Expand Up @@ -229,7 +194,7 @@ public LeftSemiJoin<TRow, TCols, TIxCols, TRightRow, TRightCols, TRightIxCols> L
>(
Table<TRightRow, TRightCols, TRightIxCols> right,
Func<TIxCols, TRightIxCols, IxJoinEq<TRow, TRightRow>> on
) => new(this, right, on(ixCols, right.ixCols), whereExpr: null);
) => new(this, right, on(ixCols, right.IxCols), whereExpr: null);

public RightSemiJoin<TRow, TCols, TIxCols, TRightRow, TRightCols, TRightIxCols> RightSemijoin<
TRightRow,
Expand All @@ -238,7 +203,7 @@ public RightSemiJoin<TRow, TCols, TIxCols, TRightRow, TRightCols, TRightIxCols>
>(
Table<TRightRow, TRightCols, TRightIxCols> right,
Func<TIxCols, TRightIxCols, IxJoinEq<TRow, TRightRow>> on
) => new(this, right, on(ixCols, right.ixCols), leftWhereExpr: null);
) => new(this, right, on(ixCols, right.IxCols), leftWhereExpr: null);
}

public sealed class FromWhere<TRow, TCols, TIxCols> : IQuery<TRow>
Expand Down Expand Up @@ -889,7 +854,7 @@ public static string FormatHexLiteral(string hex)
var s = hex;
if (s.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
{
s = s.Substring(2);
s = s[2..];
}

s = s.Replace("-", string.Empty);
Expand Down
15 changes: 4 additions & 11 deletions crates/bindings-csharp/Codegen.Tests/Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,11 @@ public static class GeneratorSnapshotTests

record struct StepOutput(string Key, IncrementalStepRunReason Reason, object Value);

private class Fixture
private class Fixture(string projectDir, CSharpCompilation sampleCompilation)
{
private readonly string projectDir;
public CSharpCompilation SampleCompilation { get; }
public CSharpParseOptions ParseOptions { get; }

public Fixture(string projectDir, CSharpCompilation sampleCompilation)
{
this.projectDir = projectDir;
SampleCompilation = sampleCompilation;
ParseOptions = (CSharpParseOptions)sampleCompilation.SyntaxTrees.First().Options;
}
public CSharpCompilation SampleCompilation { get; } = sampleCompilation;
public CSharpParseOptions ParseOptions { get; } =
(CSharpParseOptions)sampleCompilation.SyntaxTrees.First().Options;

public static async Task<Fixture> Compile(string name)
{
Expand Down
Loading
Loading