Skip to content

Commit d00b7c6

Browse files
authored
UUID Ver7 in UUID Generator Tool. (#45)
* Add UUIDv7 in UUIDGenerator Tool. * Update Description. * Update unit test (UuidHelper). * Use RandomNumberGenerator. * Update unit test.
1 parent 71ae6f0 commit d00b7c6

44 files changed

Lines changed: 205 additions & 21 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,41 @@
1-
using DevToys.Tools.Helpers;
1+
using System.Text.RegularExpressions;
2+
using DevToys.Tools.Helpers;
23
using DevToys.Tools.Models;
34

45
namespace DevToys.Tools.UnitTests.Tools.Helpers;
56

67
public class UuidHelperTests
78
{
89
[Theory]
9-
[InlineData(UuidVersion.One, true, true)]
10-
[InlineData(UuidVersion.One, false, true)]
11-
[InlineData(UuidVersion.One, true, false)]
12-
[InlineData(UuidVersion.One, false, false)]
13-
[InlineData(UuidVersion.Four, true, true)]
14-
[InlineData(UuidVersion.Four, false, true)]
15-
[InlineData(UuidVersion.Four, true, false)]
16-
[InlineData(UuidVersion.Four, false, false)]
17-
internal void GenerateUuid(UuidVersion uuidVersion, bool hyphens, bool uppercase)
10+
[InlineData(UuidVersion.One, true, true, 1)]
11+
[InlineData(UuidVersion.One, false, true, 1)]
12+
[InlineData(UuidVersion.One, true, false, 1)]
13+
[InlineData(UuidVersion.One, false, false, 1)]
14+
[InlineData(UuidVersion.Four, true, true, 4)]
15+
[InlineData(UuidVersion.Four, false, true, 4)]
16+
[InlineData(UuidVersion.Four, true, false, 4)]
17+
[InlineData(UuidVersion.Four, false, false, 4)]
18+
[InlineData(UuidVersion.Seven, true, true, 7)]
19+
[InlineData(UuidVersion.Seven, false, true, 7)]
20+
[InlineData(UuidVersion.Seven, true, false, 7)]
21+
[InlineData(UuidVersion.Seven, false, false, 7)]
22+
internal void GenerateUuid(UuidVersion uuidVersion, bool hyphens, bool uppercase, int version)
1823
{
1924
string newUuid
2025
= UuidHelper.GenerateUuid(
2126
uuidVersion,
2227
hyphens,
2328
uppercase);
24-
TestUuid(newUuid, hyphens, uppercase);
29+
TestUuid(newUuid, hyphens, uppercase, version);
2530
}
2631

27-
private static void TestUuid(string uuid, bool hyphens, bool uppercase)
32+
private static void TestUuid(string uuid, bool hyphens, bool uppercase, int version)
2833
{
2934
Guid.TryParse(uuid, out _).Should().BeTrue();
3035
uuid.Contains('-').Should().Be(hyphens);
3136
uuid.Length.Should().Be(hyphens ? 36 : 32);
3237
uuid.Should().Be(uppercase ? uuid.ToUpperInvariant() : uuid.ToLowerInvariant());
38+
string pattern = "^[0-9a-f]{8}-?[0-9a-f]{4}-?" + version + "[0-9a-f]{3}-?[89ab][0-9a-f]{3}-?[0-9a-f]{12}$";
39+
Regex.IsMatch(uuid.ToLowerInvariant(), pattern).Should().BeTrue();
3340
}
3441
}

src/DevToys.Tools/Helpers/UuidHelper.cs

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using DevToys.Tools.Models;
1+
using System.Security.Cryptography;
2+
using DevToys.Tools.Models;
23

34
namespace DevToys.Tools.Helpers;
45
internal static class UuidHelper
@@ -8,15 +9,20 @@ private enum GuidVersion
89
TimeBased = 0x01,
910
Reserved = 0x02,
1011
NameBased = 0x03,
11-
Random = 0x04
12+
Random = 0x04,
13+
NameBasedV5 = 0x05,
14+
UuidV6 = 0x06,
15+
UnixEpoch = 0x07
1216
}
1317

1418
private static readonly Random random = new();
19+
private static readonly RandomNumberGenerator cRandom = RandomNumberGenerator.Create();
1520

1621
private static readonly DateTimeOffset gregorianCalendarStart = new(1582, 10, 15, 0, 0, 0, TimeSpan.Zero);
1722
private const int VariantByte = 8;
1823
private const int VariantByteMask = 0x3f;
1924
private const int VariantByteShift = 0x80;
25+
private const int VariantByteShiftRFC = 0x80;
2026
private const int VersionByte = 7;
2127
private const int VersionByteMask = 0x0f;
2228
private const int VersionByteShift = 4;
@@ -42,6 +48,10 @@ internal static string GenerateUuid(UuidVersion version, bool hyphens, bool uppe
4248
{
4349
uuid = GenerateTimeBasedGuid().ToString(guidStringFormat);
4450
}
51+
else if (version == UuidVersion.Seven)
52+
{
53+
uuid = GenerateUUIDv7().ToString(guidStringFormat);
54+
}
4555
else
4656
{
4757
uuid = Guid.NewGuid().ToString(guidStringFormat);
@@ -85,6 +95,43 @@ private static Guid GenerateTimeBasedGuid()
8595
return new Guid(guid);
8696
}
8797

98+
private static Guid GenerateUUIDv7()
99+
{
100+
// TTTTTTTT-TTTT-7aaa-rRRR-RRRRRRRRRRRR
101+
// T=unix_ts_ms 7=version a=rand_a r=variant R=rand_b
102+
103+
// RRRRRRRR-RRRR-RRRR-RRRR-RRRRRRRRRRRR
104+
byte[] guid = new byte[ByteArraySize];
105+
cRandom.GetBytes(guid);
106+
107+
// timestamp
108+
// If more precise timestamping or monotonicity is needed,
109+
// the 12-bit space in rand_a and some space in rand_b can be used.
110+
DateTimeOffset dateTime = DateTimeOffset.UtcNow;
111+
long timestamp = dateTime.ToUnixTimeMilliseconds();
112+
113+
// 48-bit big-endian unsigned number of the Unix Epoch timestamp in milliseconds.
114+
// TTTTTTTT-TTTT-****-****-************
115+
guid[0] = (byte)((timestamp >> 40) & 0xFF);
116+
guid[1] = (byte)((timestamp >> 32) & 0xFF);
117+
guid[2] = (byte)((timestamp >> 24) & 0xFF);
118+
guid[3] = (byte)((timestamp >> 16) & 0xFF);
119+
guid[4] = (byte)((timestamp >> 8) & 0xFF);
120+
guid[5] = (byte)(timestamp & 0xFF);
121+
122+
// set the version
123+
// ********-****-7***-****-************
124+
guid[6] &= (byte)VersionByteMask;
125+
guid[6] |= (byte)((byte)GuidVersion.UnixEpoch << VersionByteShift);
126+
127+
// set the variant
128+
// ********-****-****-r***-************
129+
guid[8] &= (byte)VariantByteMask;
130+
guid[8] |= (byte)VariantByteShiftRFC;
131+
132+
return new Guid(BitConverter.ToString(guid).Replace("-", ""));
133+
}
134+
88135
public static byte[] GenerateNodeBytes()
89136
{
90137
byte[]? node = new byte[6];
@@ -101,14 +148,14 @@ public static byte[] GenerateClockSequenceBytes(DateTime dt)
101148

102149
if (bytes.Length == 0)
103150
{
104-
return new byte[] { 0x0, 0x0 };
151+
return [0x0, 0x0];
105152
}
106153

107154
if (bytes.Length == 1)
108155
{
109-
return new byte[] { 0x0, bytes[0] };
156+
return [0x0, bytes[0]];
110157
}
111158

112-
return new byte[] { bytes[0], bytes[1] };
159+
return [bytes[0], bytes[1]];
113160
}
114161
}

src/DevToys.Tools/Models/UuidVersion.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@
33
internal enum UuidVersion
44
{
55
One,
6-
Four
6+
Four,
7+
Seven
78
}

src/DevToys.Tools/Tools/Generators/UUID/UUIDGenerator.Designer.cs

Lines changed: 12 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/DevToys.Tools/Tools/Generators/UUID/UUIDGenerator.af-ZA.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,9 @@
165165
<data name="UuidVersionOne" xml:space="preserve">
166166
<value>1</value>
167167
</data>
168+
<data name="UuidVersionSeven" xml:space="preserve">
169+
<value>7</value>
170+
</data>
168171
<data name="VersionDescription" xml:space="preserve">
169172
<value>Choose the version of UUID to generate</value>
170173
</data>

src/DevToys.Tools/Tools/Generators/UUID/UUIDGenerator.ar-SA.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,9 @@
165165
<data name="UuidVersionOne" xml:space="preserve">
166166
<value>1</value>
167167
</data>
168+
<data name="UuidVersionSeven" xml:space="preserve">
169+
<value>7</value>
170+
</data>
168171
<data name="VersionDescription" xml:space="preserve">
169172
<value>Choose the version of UUID to generate</value>
170173
</data>

src/DevToys.Tools/Tools/Generators/UUID/UUIDGenerator.bn-BD.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,9 @@
165165
<data name="UuidVersionOne" xml:space="preserve">
166166
<value>1</value>
167167
</data>
168+
<data name="UuidVersionSeven" xml:space="preserve">
169+
<value>7</value>
170+
</data>
168171
<data name="VersionDescription" xml:space="preserve">
169172
<value>Choose the version of UUID to generate</value>
170173
</data>

src/DevToys.Tools/Tools/Generators/UUID/UUIDGenerator.ca-ES.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,9 @@
165165
<data name="UuidVersionOne" xml:space="preserve">
166166
<value>1</value>
167167
</data>
168+
<data name="UuidVersionSeven" xml:space="preserve">
169+
<value>7</value>
170+
</data>
168171
<data name="VersionDescription" xml:space="preserve">
169172
<value>Choose the version of UUID to generate</value>
170173
</data>

src/DevToys.Tools/Tools/Generators/UUID/UUIDGenerator.cs-CZ.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,9 @@
165165
<data name="UuidVersionOne" xml:space="preserve">
166166
<value>1</value>
167167
</data>
168+
<data name="UuidVersionSeven" xml:space="preserve">
169+
<value>7</value>
170+
</data>
168171
<data name="VersionDescription" xml:space="preserve">
169172
<value>Zvolte verzi UUID, která se má vygenerovat</value>
170173
</data>

src/DevToys.Tools/Tools/Generators/UUID/UUIDGenerator.da-DK.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,9 @@
165165
<data name="UuidVersionOne" xml:space="preserve">
166166
<value>1</value>
167167
</data>
168+
<data name="UuidVersionSeven" xml:space="preserve">
169+
<value>7</value>
170+
</data>
168171
<data name="VersionDescription" xml:space="preserve">
169172
<value>Vælg den UUID-version, der skal genereres</value>
170173
</data>

0 commit comments

Comments
 (0)