diff --git a/README.md b/README.md index 36f6199..e71c4d6 100644 --- a/README.md +++ b/README.md @@ -204,7 +204,7 @@ Converts the ULID to a canonical string representation. Format arguments are ign `==`, `!=`, `<`, `<=`, `>`, `>=`. - Implements standard comparison and equality methods:\ `CompareTo`, `Equals`, `GetHashCode`. -- Provides implicit operators to and from `Guid`. +- Provides implicit operators to and from `Guid` and `string`. ### GenerationOptions @@ -448,11 +448,11 @@ Job=DefaultJob | ToGuid | Ulid | 0.7462 ns | 0.0117 ns | - | - | | ToGuid | NUlid | 0.2691 ns | 0.0070 ns | - | - | -| ToString | ByteAetherUlid | 12.2227 ns | 0.2543 ns | 0.0096 | 80 B | -| ToString | NetUlid | 23.7706 ns | 0.2422 ns | 0.0095 | 80 B | -| ToString | Ulid | 11.1126 ns | 0.2121 ns | 0.0096 | 80 B | -| ToString | NUlid | 28.9672 ns | 0.1506 ns | 0.0095 | 80 B | -| ToString | Guid | 7.2446 ns | 0.0341 ns | 0.0115 | 96 B | +| ToString | ByteAetherUlid | 12.254 ns | 0.2822 ns | 0.0096 | 80 B | +| ToString | NetUlid | 26.314 ns | 0.2748 ns | 0.0095 | 80 B | +| ToString | Ulid | 12.373 ns | 0.1887 ns | 0.0096 | 80 B | +| ToString | NUlid | 27.661 ns | 0.2090 ns | 0.0095 | 80 B | +| ToString | Guid | 7.208 ns | 0.0447 ns | 0.0115 | 96 B | | CompareTo | ByteAetherUlid | 0.0007 ns | 0.0022 ns | - | - | | CompareTo | NetUlid | 3.6812 ns | 0.0298 ns | - | - | diff --git a/src/ByteAether.Ulid.Tests/Ulid.Comparable.Tests.cs b/src/ByteAether.Ulid.Tests/Ulid.Comparable.Tests.cs index 715c1a3..a1981df 100644 --- a/src/ByteAether.Ulid.Tests/Ulid.Comparable.Tests.cs +++ b/src/ByteAether.Ulid.Tests/Ulid.Comparable.Tests.cs @@ -75,7 +75,7 @@ public void CompareTo_NullUlid_ShouldReturnPositive() var ulid = Ulid.New(); // Act - var comparisonResult = ulid.CompareTo(null); + var comparisonResult = ulid.CompareTo((object?)null); // Assert Assert.True(comparisonResult > 0); diff --git a/src/ByteAether.Ulid.Tests/Ulid.Equatable.Tests.cs b/src/ByteAether.Ulid.Tests/Ulid.Equatable.Tests.cs index cecbf27..a652dd8 100644 --- a/src/ByteAether.Ulid.Tests/Ulid.Equatable.Tests.cs +++ b/src/ByteAether.Ulid.Tests/Ulid.Equatable.Tests.cs @@ -65,7 +65,7 @@ public void Equals_Null_ShouldReturnFalse() var ulid = Ulid.New(); // Act & Assert - Assert.False(ulid.Equals(null)); + Assert.False(ulid.Equals((object?)null)); } [Fact] @@ -89,4 +89,4 @@ public void Equals_SameAsObject_ShouldReturnTrue() // Act & Assert Assert.True(ulid1.Equals((object)ulid2)); } -} +} \ No newline at end of file diff --git a/src/ByteAether.Ulid.Tests/Ulid.String.Tests.cs b/src/ByteAether.Ulid.Tests/Ulid.String.Tests.cs index 5622a56..615cdb3 100644 --- a/src/ByteAether.Ulid.Tests/Ulid.String.Tests.cs +++ b/src/ByteAether.Ulid.Tests/Ulid.String.Tests.cs @@ -3,7 +3,7 @@ namespace ByteAether.Ulid.Tests; public class UlidStringTests { - private static readonly string _goodUlidString = "01F8MECHZX3TBDSZG8P8X7XRMM"; + private const string _goodUlidString = "01F8MECHZX3TBDSZG8P8X7XRMM"; [Fact] public void ToString_ShouldReturnExpectedString() @@ -221,7 +221,7 @@ public void TryParse_ReadOnlySpanByte_InvalidInput_ShouldReturnFalse(string inpu [Fact] public void ToString_WrongLetters_ShouldReplaceWithCorrect() { - // Crockford's Base32 subtitution test + // Crockford's Base32 substitution test var inputChars = new[] { 'O', 'o', 'I', 'i', 'L', 'l', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'v', 'w', 'x', 'y', 'z' }; var outputChars = new[] { '0', '0', '1', '1', '1', '1', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'V', 'W', 'X', 'Y', 'Z' }; @@ -236,4 +236,4 @@ public void ToString_WrongLetters_ShouldReplaceWithCorrect() Assert.Equal(outputString, resultString); } } -} +} \ No newline at end of file diff --git a/src/ByteAether.Ulid/PACKAGE.md b/src/ByteAether.Ulid/PACKAGE.md index 1853ea7..be3b843 100644 --- a/src/ByteAether.Ulid/PACKAGE.md +++ b/src/ByteAether.Ulid/PACKAGE.md @@ -137,7 +137,7 @@ Create from existing `Guid`. `==`, `!=`, `<`, `<=`, `>`, `>=`. - Implements standard comparison and equality methods:\ `CompareTo`, `Equals`, `GetHashCode`. -- Provides implicit operators to and from `Guid`. +- Provides implicit operators to and from `Guid` and `string`. ### GenerationOptions diff --git a/src/ByteAether.Ulid/Ulid.String.cs b/src/ByteAether.Ulid/Ulid.String.cs index cb7e331..f2d8d43 100644 --- a/src/ByteAether.Ulid/Ulid.String.cs +++ b/src/ByteAether.Ulid/Ulid.String.cs @@ -2,9 +2,6 @@ using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Text; -#if !(NETSTANDARD2_1_OR_GREATER || NETCOREAPP) -using System.Runtime.InteropServices; -#endif namespace ByteAether.Ulid; @@ -82,17 +79,28 @@ public readonly partial struct Ulid #else [MethodImpl(MethodImplOptions.AggressiveInlining)] #endif - public readonly string ToString(string? format = null, IFormatProvider? formatProvider = null) + public readonly string ToString(string? format, IFormatProvider? formatProvider) => ToString(); + + /// + /// Returns a string representation of the current instance of in its canonical Crockford's Base32 format.' + /// + /// Crockford's Base32 representation of the ULID +#if NET5_0_OR_GREATER + [SkipLocalsInit] +#endif +#if NETCOREAPP3_0_OR_GREATER + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] +#else + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public override readonly string ToString() { #if NETSTANDARD2_1_OR_GREATER || NETCOREAPP return string.Create(UlidStringLength, this, (span, ulid) => ulid.TryFill(span, _base32Chars)); #else Span span = stackalloc char[UlidStringLength]; TryFill(span, _base32Chars); - unsafe - { - return new string((char*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(span)), 0, UlidStringLength); - } + return span.ToString(); #endif } @@ -385,4 +393,28 @@ private bool TryFill(Span span, T[] map) return true; } + + /// + /// Allows implicit conversion of to . + /// + /// + /// +#if NETCOREAPP3_0_OR_GREATER + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] +#else + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public static implicit operator string(Ulid ulid) => ulid.ToString(); + + /// + /// Allows implicit conversion of to . + /// + /// + /// +#if NETCOREAPP3_0_OR_GREATER + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] +#else + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public static implicit operator Ulid(string str) => Parse(str); } \ No newline at end of file