Skip to content

Commit d5bb066

Browse files
committed
Add UUID built-in convenience type to SpacetimeDB
Fix uuid parsing and to_string in ts and c#
1 parent 8967ea7 commit d5bb066

98 files changed

Lines changed: 4898 additions & 98 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Cargo.lock

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

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ unicode-ident = "1.0.12"
326326
unicode-normalization = "0.1.23"
327327
url = "2.3.1"
328328
urlencoding = "2.1.2"
329-
uuid = { version = "1.18.1", features = ["v4"] }
329+
uuid = { version = "1.18.1", default-features = false }
330330
v8 = "140.2"
331331
walkdir = "2.2.5"
332332
wasmbin = "0.6"

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

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
namespace SpacetimeDB;
22

33
using System.Diagnostics.CodeAnalysis;
4+
using System.Security.Cryptography;
45
using CsCheck;
56
using SpacetimeDB.BSATN;
67
using Xunit;
@@ -861,4 +862,86 @@ public static void GeneratedEnumEqualsWorks()
861862
iter: 10_000
862863
);
863864
}
865+
866+
[Fact]
867+
public static void UUidRoundTrip()
868+
{
869+
var u1 = Uuid.NIL;
870+
var s = u1.ToString();
871+
var u2 = Uuid.Parse(s);
872+
Assert.Equal(u1, u2);
873+
Assert.Equal(u1.ToGuid(), u2.ToGuid());
874+
Assert.Equal(s, u2.ToString());
875+
}
876+
877+
[Fact]
878+
public static void UuidToString()
879+
{
880+
foreach (
881+
var uuid in new[]
882+
{
883+
Uuid.NIL,
884+
new Uuid(new U128(0x0102030405060708UL, 0x090A0B0C0D0E0F10UL)),
885+
Uuid.MAX,
886+
}
887+
)
888+
{
889+
var s = uuid.ToString();
890+
var uuid2 = Uuid.Parse(s);
891+
Assert.Equal(uuid, uuid2);
892+
var g = new Guid(s);
893+
Assert.Equal(s, g.ToString()); // same canonical form
894+
}
895+
}
896+
897+
[Fact]
898+
public static void UuidOrdered()
899+
{
900+
var u1 = new Uuid(new U128(1, 0));
901+
var u2 = new Uuid(new U128(2, 0));
902+
903+
Assert.True(u1 < u2);
904+
Assert.True(u2 > u1);
905+
Assert.Equal(u1, u1);
906+
Assert.NotEqual(u1, u2);
907+
908+
var clock = new ClockGenerator(new Timestamp());
909+
910+
var uuids = Enumerable
911+
.Range(0, 1000)
912+
.Select(_ =>
913+
{
914+
var bytes = new byte[10];
915+
RandomNumberGenerator.Fill(bytes);
916+
return Uuid.FromClockV7(clock, bytes);
917+
})
918+
.ToList();
919+
920+
for (var i = 0; i < uuids.Count - 1; i++)
921+
{
922+
var a = uuids[i];
923+
var b = uuids[i + 1];
924+
925+
Assert.True(a < b, $"UUIDs are not ordered at {i}: {a} !< {b}");
926+
}
927+
}
928+
929+
[Fact]
930+
public static void UuidVariant()
931+
{
932+
var u = Uuid.NIL;
933+
Assert.Equal(Uuid.UuidVersion.Nil, u.GetVersion());
934+
935+
u = Uuid.MAX;
936+
Assert.Equal(Uuid.UuidVersion.Max, u.GetVersion());
937+
938+
var randomBytes = new byte[16];
939+
RandomNumberGenerator.Fill(randomBytes);
940+
u = Uuid.FromRandomBytesV4(randomBytes);
941+
Assert.Equal(Uuid.UuidVersion.V4, u.GetVersion());
942+
943+
var clock = new ClockGenerator(new Timestamp());
944+
u = Uuid.FromClockV7(clock, randomBytes.AsSpan()[..10]);
945+
Assert.Equal(Uuid.UuidVersion.V7, u.GetVersion());
946+
}
864947
}

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

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
namespace SpacetimeDB;
55

6+
using System.Buffers.Binary;
67
using System.Numerics;
78
using System.Runtime.InteropServices;
89

@@ -33,6 +34,33 @@ public U128(ulong upper, ulong lower)
3334

3435
internal ulong Upper => _upper;
3536

37+
/// Returns a <see cref="U128" /> from a big-endian byte array.
38+
public static U128 FromBytesBigEndian(ReadOnlySpan<byte> bytes)
39+
{
40+
if (bytes.Length != Size)
41+
{
42+
throw new ArgumentException(
43+
$"Byte array must be exactly {Size} bytes long.",
44+
nameof(bytes)
45+
);
46+
}
47+
48+
var upper = BinaryPrimitives.ReadUInt64BigEndian(bytes.Slice(0, 8));
49+
var lower = BinaryPrimitives.ReadUInt64BigEndian(bytes.Slice(8, 8));
50+
51+
return new U128(upper, lower);
52+
}
53+
54+
public byte[] ToBytesBigEndian()
55+
{
56+
var bytes = new byte[Size];
57+
58+
BinaryPrimitives.WriteUInt64BigEndian(bytes.AsSpan(0, 8), _upper);
59+
BinaryPrimitives.WriteUInt64BigEndian(bytes.AsSpan(8, 8), _lower);
60+
61+
return bytes;
62+
}
63+
3664
/// <inheritdoc cref="IComparable.CompareTo(object)" />
3765
public int CompareTo(object? value)
3866
{
@@ -90,4 +118,11 @@ private BigInteger AsBigInt() =>
90118

91119
/// <inheritdoc cref="object.ToString()" />
92120
public override string ToString() => AsBigInt().ToString();
121+
122+
public static U128 FromGuid(Guid guid)
123+
{
124+
Span<byte> bytes = stackalloc byte[16];
125+
guid.TryWriteBytes(bytes);
126+
return FromBytesBigEndian(bytes);
127+
}
93128
}

0 commit comments

Comments
 (0)