Skip to content

Commit

Permalink
Use 'bigEndian' Guid method argument in .NET 8.
Browse files Browse the repository at this point in the history
  • Loading branch information
bgrainger committed Oct 5, 2024
1 parent 17dc7e8 commit 39c7bc6
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 10 deletions.
31 changes: 27 additions & 4 deletions src/NGuid/GuidHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,14 @@ public static Guid CreateFromName(Guid namespaceId, ReadOnlySpan<byte> name, int

// convert the namespace UUID to network order (step 3)
Span<byte> buffer = name.Length < 500 ? stackalloc byte[16 + name.Length + 20] : new byte[16 + name.Length + 20];
#if NET8_0_OR_GREATER
if (!namespaceId.TryWriteBytes(buffer, bigEndian: true, out _))
throw new InvalidOperationException("Failed to write namespace ID bytes to buffer");
#else
if (!namespaceId.TryWriteBytes(buffer))
throw new InvalidOperationException("Failed to write Guid bytes to buffer");
SwapByteOrder(buffer);
#endif

// compute the hash of the namespace ID concatenated with the name (step 4)
#pragma warning disable CA5350 // Do Not Use Weak Cryptographic Algorithms
Expand All @@ -131,9 +136,13 @@ public static Guid CreateFromName(Guid namespaceId, ReadOnlySpan<byte> name, int
// set the two most significant bits (bits 6 and 7) of the clock_seq_hi_and_reserved to zero and one, respectively (step 10)
newGuid[8] = (byte) ((newGuid[8] & 0x3F) | 0x80);

#if NET8_0_OR_GREATER
return new Guid(newGuid, bigEndian: true);
#else
// convert the resulting UUID to local byte order (step 13)
SwapByteOrder(newGuid);
return new Guid(newGuid);
#endif
}
#endif

Expand Down Expand Up @@ -354,14 +363,17 @@ public static Guid CreateVersion8(ReadOnlySpan<byte> bytes)
Span<byte> guidBytes = stackalloc byte[16];
bytes[..16].CopyTo(guidBytes);

// convert the bytes to network order (so that bytes[0] is the first byte in the serialized GUID output)
SwapByteOrder(guidBytes);

// set the version and variant fields
guidBytes[7] = (byte) (0x80 | (guidBytes[7] & 0xF));
guidBytes[6] = (byte) (0x80 | (guidBytes[6] & 0xF));
guidBytes[8] = (byte) (0x80 | (guidBytes[8] & 0x3F));

#if NET8_0_OR_GREATER
return new Guid(guidBytes, bigEndian: true);
#else
// convert the bytes to network order (so that bytes[0] is the first byte in the serialized GUID output)
SwapByteOrder(guidBytes);
return new Guid(guidBytes);
#endif
}
#endif

Expand Down Expand Up @@ -422,10 +434,15 @@ public static Guid CreateVersion8FromName(HashAlgorithmName hashAlgorithmName, G
#endif
Span<byte> buffer = name.Length < 500 ? stackalloc byte[16 + name.Length] : new byte[16 + name.Length];

#if NET8_0_OR_GREATER
if (!namespaceId.TryWriteBytes(buffer, bigEndian: true, out _))
throw new InvalidOperationException("Failed to write namespace ID bytes to buffer");
#else
// convert the hash space and namespace UUIDs to network order
if (!namespaceId.TryWriteBytes(buffer))
throw new InvalidOperationException("Failed to write namespace ID bytes to buffer");
SwapByteOrder(buffer);
#endif

// compute the hash of [ namespace ID, name ]
name.CopyTo(buffer[16..]);
Expand All @@ -447,9 +464,13 @@ public static Guid CreateVersion8FromName(HashAlgorithmName hashAlgorithmName, G
newGuid[6] = (byte) ((newGuid[6] & 0x0F) | 0x80);
newGuid[8] = (byte) ((newGuid[8] & 0x3F) | 0x80);

#if NET8_0_OR_GREATER
return new Guid(newGuid, bigEndian: true);
#else
// convert the resulting UUID to local byte order
SwapByteOrder(newGuid);
return new Guid(newGuid);
#endif
}
#endif

Expand Down Expand Up @@ -479,6 +500,7 @@ private static HashAlgorithm GetHashAlgorithm(HashAlgorithmName hashAlgorithmNam
/// </summary>
public static readonly Guid IsoOidNamespace = new("6ba7b812-9dad-11d1-80b4-00c04fd430c8");

#if !NET8_0_OR_GREATER
// Converts a GUID (expressed as a byte array) to/from network order (MSB-first).
internal static void SwapByteOrder(Span<byte> guid)
{
Expand All @@ -487,6 +509,7 @@ internal static void SwapByteOrder(Span<byte> guid)
SwapBytes(guid, 4, 5);
SwapBytes(guid, 6, 7);
}
#endif

private static void SwapBytes(Span<byte> guid, int left, int right)
{
Expand Down
11 changes: 6 additions & 5 deletions tests/NGuid.Tests/GuidHelpersTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.Buffers.Binary;
using System.Globalization;
using System.Text;

namespace NGuid.Tests;
Expand All @@ -13,8 +12,10 @@ public void SwapByteOrder()
var bytes = guid.ToByteArray();
Assert.Equal([4, 3, 2, 1, 6, 5, 8, 7, 9, 10, 11, 12, 13, 14, 15, 16], bytes);

#if !NET8_0_OR_GREATER
GuidHelpers.SwapByteOrder(bytes);
Assert.Equal([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], bytes);
#endif
}

[Theory]
Expand Down Expand Up @@ -83,7 +84,7 @@ public void CreateV6()
[InlineData("2022-02-22T14:22:22-05:00", "1ec9414c-232a-6b00")] // https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-14#name-example-of-a-uuidv6-value
public void CreateV6FromTimeProvider(string timestamp, string expectedPrefix)
{
var timeProvider = new FixedTimeProvider(DateTimeOffset.Parse(timestamp, CultureInfo.InvariantCulture));
var timeProvider = new FixedTimeProvider(DateTimeOffset.Parse(timestamp, System.Globalization.CultureInfo.InvariantCulture));
var guid = GuidHelpers.CreateVersion6(timeProvider);
Assert.StartsWith(expectedPrefix, guid.ToString("d"), StringComparison.Ordinal);
}
Expand All @@ -108,7 +109,7 @@ public void CreateV7()
[InlineData("2022-02-22T14:22:22-05:00", "017f22e2-79b0-7")] // https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-14#name-example-of-a-uuidv7-value
public void CreateV7FromTimeProvider(string timestamp, string expectedPrefix)
{
var timeProvider = new FixedTimeProvider(DateTimeOffset.Parse(timestamp, CultureInfo.InvariantCulture));
var timeProvider = new FixedTimeProvider(DateTimeOffset.Parse(timestamp, System.Globalization.CultureInfo.InvariantCulture));
var guid = GuidHelpers.CreateVersion7(timeProvider);
Assert.StartsWith(expectedPrefix, guid.ToString("d"), StringComparison.Ordinal);
}
Expand All @@ -129,12 +130,12 @@ public void ConvertV4ToV6() =>
[InlineData("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", "ffffffff-ffff-8fff-bfff-ffffffffffff")]
public void CreateV8(string input, string expected)
{
#if NET8_0_OR_GREATER
#if NET5_0_OR_GREATER
var bytes = Convert.FromHexString(input);
#else
var bytes = new byte[input.Length / 2];
for (var i = 0; i < bytes.Length; i++)
bytes[i] = byte.Parse(input.Substring(i * 2, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture);
bytes[i] = byte.Parse(input.Substring(i * 2, 2), System.Globalization.NumberStyles.HexNumber, System.Globalization.CultureInfo.InvariantCulture);
#endif
var guid = GuidHelpers.CreateVersion8(bytes);
Assert.Equal(new Guid(expected), guid);
Expand Down
2 changes: 1 addition & 1 deletion tests/NGuid.Tests/NGuid.Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net481;net8.0;net9.0</TargetFrameworks>
<TargetFrameworks>net481;net6.0;net8.0;net9.0</TargetFrameworks>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<NoWarn>$(NoWarn);CA1515;CS1591</NoWarn>
Expand Down

0 comments on commit 39c7bc6

Please sign in to comment.