ActivityTraceId
Represents a TraceId whose format is based on a W3C standard.
using System.Buffers.Binary;
using System.Buffers.Text;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace System.Diagnostics
{
public readonly struct ActivityTraceId : IEquatable<ActivityTraceId>
{
private readonly string _hexString;
internal ActivityTraceId(string hexString)
{
_hexString = hexString;
}
public unsafe static ActivityTraceId CreateRandom()
{
Span<byte> span = new Span<byte>(stackalloc byte[16], 16);
Span<byte> span2 = span;
SetToRandomBytes(span2);
return CreateFromBytes(span2);
}
public static ActivityTraceId CreateFromBytes(ReadOnlySpan<byte> idData)
{
if (idData.Length != 16)
throw new ArgumentOutOfRangeException("idData");
return new ActivityTraceId(System.HexConverter.ToString(idData, System.HexConverter.Casing.Lower));
}
public static ActivityTraceId CreateFromUtf8String(ReadOnlySpan<byte> idData)
{
return new ActivityTraceId(idData);
}
public static ActivityTraceId CreateFromString(ReadOnlySpan<char> idData)
{
if (idData.Length != 32 || !IsLowerCaseHexAndNotAllZeros(idData))
throw new ArgumentOutOfRangeException("idData");
return new ActivityTraceId(idData.ToString());
}
[System.Runtime.CompilerServices.NullableContext(1)]
public string ToHexString()
{
return _hexString ?? "00000000000000000000000000000000";
}
[System.Runtime.CompilerServices.NullableContext(1)]
public override string ToString()
{
return ToHexString();
}
public static bool operator ==(ActivityTraceId traceId1, ActivityTraceId traceId2)
{
return traceId1._hexString == traceId2._hexString;
}
public static bool operator !=(ActivityTraceId traceId1, ActivityTraceId traceId2)
{
return traceId1._hexString != traceId2._hexString;
}
public bool Equals(ActivityTraceId traceId)
{
return _hexString == traceId._hexString;
}
[System.Runtime.CompilerServices.NullableContext(2)]
public override bool Equals(object obj)
{
if (obj is ActivityTraceId) {
ActivityTraceId activityTraceId = (ActivityTraceId)obj;
return _hexString == activityTraceId._hexString;
}
return false;
}
public override int GetHashCode()
{
return ToHexString().GetHashCode();
}
private unsafe ActivityTraceId(ReadOnlySpan<byte> idData)
{
if (idData.Length != 32)
throw new ArgumentOutOfRangeException("idData");
Span<ulong> span = new Span<ulong>(stackalloc byte[16], 2);
Span<ulong> span2 = span;
if (!Utf8Parser.TryParse(idData.Slice(0, 16), out span2[0], out int bytesConsumed, 'x'))
_hexString = CreateRandom()._hexString;
else if (!Utf8Parser.TryParse(idData.Slice(16, 16), out span2[1], out bytesConsumed, 'x')) {
_hexString = CreateRandom()._hexString;
} else {
if (BitConverter.IsLittleEndian) {
span2[0] = BinaryPrimitives.ReverseEndianness(span2[0]);
span2[1] = BinaryPrimitives.ReverseEndianness(span2[1]);
}
_hexString = System.HexConverter.ToString(MemoryMarshal.AsBytes(span2), System.HexConverter.Casing.Lower);
}
}
public void CopyTo(Span<byte> destination)
{
SetSpanFromHexChars(ToHexString().AsSpan(), destination);
}
internal unsafe static void SetToRandomBytes(Span<byte> outBytes)
{
Guid guid = Guid.NewGuid();
new ReadOnlySpan<byte>(&guid, sizeof(Guid)).Slice(0, outBytes.Length).CopyTo(outBytes);
}
internal static void SetSpanFromHexChars(ReadOnlySpan<char> charData, Span<byte> outBytes)
{
for (int i = 0; i < outBytes.Length; i++) {
outBytes[i] = HexByteFromChars(charData[i * 2], charData[i * 2 + 1]);
}
}
internal static byte HexByteFromChars(char char1, char char2)
{
return (byte)(HexDigitToBinary(char1) * 16 + HexDigitToBinary(char2));
}
private static byte HexDigitToBinary(char c)
{
if ('0' <= c && c <= '9')
return (byte)(c - 48);
if ('a' <= c && c <= 'f')
return (byte)(c - 87);
throw new ArgumentOutOfRangeException("idData");
}
internal static bool IsLowerCaseHexAndNotAllZeros(ReadOnlySpan<char> idData)
{
bool result = false;
foreach (char c in idData) {
if (!IsHexadecimalLowercaseChar(c))
return false;
if (c != '0')
result = true;
}
return result;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static bool IsHexadecimalLowercaseChar(char c)
{
if ((uint)(c - 48) > 9)
return (uint)(c - 97) <= 5;
return true;
}
}
}