diff --git a/.editorconfig b/.editorconfig
index c8104ec..413befe 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -80,6 +80,9 @@ csharp_style_expression_bodied_properties = true
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
+# Namespace Declaration Style
+csharp_style_namespace_declarations = block_scoped
+
# Null-checking preferences
csharp_style_conditional_delegate_call = true:suggestion
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index afa8679..dff77a5 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -4,6 +4,7 @@ on:
push:
branches:
- main
+ - 'release/**'
paths-ignore:
- '**.md'
- '**/renovate.json'
@@ -16,7 +17,7 @@ on:
jobs:
unit-tests:
name: Unit Tests
- runs-on: ubuntu-latest
+ runs-on: windows-latest
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
@@ -25,37 +26,31 @@ jobs:
with:
fetch-depth: 0
show-progress: false
- - name: NuGet Cache
- uses: actions/cache@v3
- with:
- path: ~/.nuget/packages
- key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
- restore-keys: ${{ runner.os}}-nuget
- name: Install .NET SDK
uses: actions/setup-dotnet@v4
with:
global-json-file: global.json
- - name: Build
- run: dotnet build -c release
- name: Test
run: |
- dotnet test -c release --no-restore --no-build \
- --logger:trx \
- --results-directory ${{ runner.temp }}/TestResults \
- -p:CollectCoverage=true \
- -p:CoverletOutputFormat=opencover \
- -p:CoverletOutput=${{ runner.temp }}/coverage.opencover.xml
+ dotnet test -c release `
+ --logger:trx `
+ --results-directory ${{ runner.temp }}\TestResults `
+ -p:CollectCoverage=true `
+ -p:CoverletOutputFormat=opencover `
+ -p:CoverletOutput=${{ github.workspace }}\CodeCoverage\coverage.opencover.xml
- name: Publish Test Results
uses: dorny/test-reporter@v1
if: success() || failure()
with:
name: Test Results
- path: ${{ runner.temp }}/TestResults/*.trx
+ path: ${{ runner.temp }}\TestResults\*.trx
reporter: dotnet-trx
+ path-replace-backslashes: true
- name: Codacy Coverage
if: always()
uses: codacy/codacy-coverage-reporter-action@v1
with:
project-token: ${{ secrets.CODACY_TOKEN }}
- coverage-reports: ${{ runner.temp }}/coverage.opencover.xml
+ coverage-reports: CodeCoverage/coverage.opencover.*.xml
+
\ No newline at end of file
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index 670eed8..00556f3 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -9,7 +9,7 @@ on:
jobs:
release:
name: Release
- runs-on: ubuntu-latest
+ runs-on: windows-latest
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
@@ -18,23 +18,17 @@ jobs:
with:
fetch-depth: 0
show-progress: false
- - name: NuGet Cache
- uses: actions/cache@v3
- with:
- path: ~/.nuget/packages
- key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
- restore-keys: ${{ runner.os}}-nuget
- name: Install .NET SDK
uses: actions/setup-dotnet@v4
with:
global-json-file: global.json
- name: Install GitVersion
- uses: gittools/actions/gitversion/setup@v0.10.2
+ uses: gittools/actions/gitversion/setup@v1.1.1
with:
versionSpec: '5.x'
- name: Determine Version
id: gitversion
- uses: gittools/actions/gitversion/execute@v0.10.2
+ uses: gittools/actions/gitversion/execute@v1.1.1
with:
useConfigFile: true
- name: Restore
diff --git a/Directory.Build.props b/Directory.Build.props
index 5abc857..c2cb8fb 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -2,12 +2,7 @@
0.0.1
Copyright (c) 2023 Visus Development Team
- enable
- enable
- true
-
-
-
- true
+ 12
+ enable
diff --git a/Directory.Packages.props b/Directory.Packages.props
index e9bcea9..a0fdced 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -1,19 +1,22 @@
-
- true
- true
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/renovate.json b/renovate.json
index 86ce457..606436f 100644
--- a/renovate.json
+++ b/renovate.json
@@ -1,10 +1,15 @@
{
"extends": [
- "config:base",
+ "mergeConfidence:all-badges",
+ "config:recommended",
":disableDependencyDashboard",
":gitSignOff"
],
"assigneesFromCodeOwners": true,
+ "timezone": "America/New_York",
+ "schedule": [
+ "before 5am"
+ ],
"packageRules": [
{
"matchPackagePatterns": [
@@ -21,8 +26,7 @@
],
"automerge": true,
"automergeType": "pr",
- "platformAutomerge": true,
- "ignoreTests": true
+ "platformAutomerge": true
},
{
"matchPackagePatterns": [
diff --git a/src/cuid.net/Abstractions/FingerprintVersion.cs b/src/cuid.net/Abstractions/FingerprintVersion.cs
index 049079d..eeb76bf 100644
--- a/src/cuid.net/Abstractions/FingerprintVersion.cs
+++ b/src/cuid.net/Abstractions/FingerprintVersion.cs
@@ -1,8 +1,9 @@
-namespace Visus.Cuid.Abstractions;
-
-internal enum FingerprintVersion : byte
+namespace Visus.Cuid.Abstractions
{
- None = 0,
- One = 1,
- Two = 2
+ internal enum FingerprintVersion : byte
+ {
+ None = 0,
+ One = 1,
+ Two = 2
+ }
}
diff --git a/src/cuid.net/Cuid.cs b/src/cuid.net/Cuid.cs
index c1e6ec8..f4d29ad 100644
--- a/src/cuid.net/Cuid.cs
+++ b/src/cuid.net/Cuid.cs
@@ -1,427 +1,461 @@
-namespace Visus.Cuid;
-
-using System.Buffers.Binary;
-using System.Diagnostics.CodeAnalysis;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using System.Text;
-using System.Text.Json.Serialization;
-using System.Xml;
-using System.Xml.Schema;
-using System.Xml.Serialization;
-using Abstractions;
-using Extensions;
-using Serialization.Json.Converters;
-
-///
-/// Represents a collision resistant unique identifier (CUID).
-///
-[StructLayout(LayoutKind.Sequential)]
-[JsonConverter(typeof(CuidConverter))]
-[XmlRoot("cuid")]
-[Obsolete(Obsoletions.CuidMessage, DiagnosticId = Obsoletions.CuidDiagId)]
-public readonly struct Cuid : IComparable, IComparable, IEquatable, IXmlSerializable
+namespace Visus.Cuid
{
- ///
- /// A read-only instance of structure whose values are all zeros.
- ///
- public static readonly Cuid Empty;
-
- private const int BlockSize = 4;
-
- private const string Prefix = "c";
-
- private const int ValueLength = 25;
-
- private readonly ulong _counter;
-
- private readonly string _fingerprint = default!;
-
- private readonly ulong _random;
-
- private readonly long _timestamp;
+ using System;
+ using System.Buffers.Binary;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.Diagnostics.CodeAnalysis;
+ using System.Linq;
+ using System.Runtime.CompilerServices;
+ using System.Runtime.InteropServices;
+ using System.Text;
+ using System.Text.Json.Serialization;
+ using System.Threading;
+ using System.Xml;
+ using System.Xml.Schema;
+ using System.Xml.Serialization;
+ using Abstractions;
+ using CommunityToolkit.Diagnostics;
+ using Extensions;
+ using Serialization.Json.Converters;
///
- /// Initializes a new instance of the structure by using the value represented by the specified
- /// string.
+ /// Represents a collision resistant unique identifier (CUID).
///
- ///
- /// A string that contains a CUID.
- ///
- public Cuid(string c)
+ [StructLayout(LayoutKind.Sequential)]
+ [JsonConverter(typeof(CuidConverter))]
+ [XmlRoot("cuid")]
+#if NET6_0_OR_GREATER
+ [Obsolete(Obsoletions.CuidMessage, DiagnosticId = Obsoletions.CuidDiagId)]
+#else
+ [Obsolete(Obsoletions.CuidMessage)]
+#endif
+ public readonly struct Cuid : IComparable, IComparable, IEquatable, IXmlSerializable
{
- ArgumentNullException.ThrowIfNull(c);
-
- CuidResult result = new();
+ ///
+ /// A read-only instance of structure whose values are all zeros.
+ ///
+ public static readonly Cuid Empty;
- _ = TryParseCuid(c, true, ref result);
+ private const int BlockSize = 4;
- this = result.ToCuid();
- }
-
- ///
- /// Initializes a new instance of the structure.
- ///
- /// A new CUID object.
- public static Cuid NewCuid()
- {
- CuidResult result = new()
- {
- _counter = Counter.Instance.Value,
- _fingerprint = Context.IdentityFingerprint,
- _random = BinaryPrimitives.ReadUInt64LittleEndian(Utils.GenerateRandom()),
- _timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
- };
-
- return result.ToCuid();
- }
+ private const string Prefix = "c";
- ///
- /// Indicates whether the values of two specified objects are equal.
- ///
- /// The first object to compare.
- /// The second object to compare.
- /// true if left and right are equal; otherwise, false.
- public static bool operator ==(Cuid left, Cuid right)
- {
- return left.Equals(right);
- }
+ private const int ValueLength = 25;
- ///
- /// Compares two values to determine which is greater.
- ///
- /// The first object to compare.
- /// The second object to compare.
- /// true if left is greater than right; otherwise, false.
- public static bool operator >(Cuid left, Cuid right)
- {
- return left.CompareTo(right) > 0;
- }
+ private readonly ulong _counter;
- ///
- /// Compares two values to determine which is greater or equal.
- ///
- /// The first object to compare.
- /// The second object to compare.
- /// true if left is greater than or equal to right; otherwise, false.
- public static bool operator >=(Cuid left, Cuid right)
- {
- return left.CompareTo(right) >= 0;
- }
+ private readonly byte[] _fingerprint;
- ///
- /// Indicates whether the values of two specified objects are not equal.
- ///
- /// The first object to compare.
- /// The second object to compare.
- /// true if left and right are not equal; otherwise, false.
- public static bool operator !=(Cuid left, Cuid right)
- {
- return !left.Equals(right);
- }
+ private readonly ulong _random;
- ///
- /// Compares two values to determine which is less.
- ///
- /// The first object to compare.
- /// The second object to compare.
- /// true if left is less than right; otherwise, false.
- public static bool operator <(Cuid left, Cuid right)
- {
- return left.CompareTo(right) < 0;
- }
+ private readonly long _timestamp;
- ///
- /// Compares two values to determine which is less or equal.
- ///
- /// The first object to compare.
- /// The second object to compare.
- /// true if left is less than or equal to right; otherwise, false.
- public static bool operator <=(Cuid left, Cuid right)
- {
- return left.CompareTo(right) <= 0;
- }
+ ///
+ /// Initializes a new instance of the structure by using the value represented by the specified
+ /// string.
+ ///
+ ///
+ /// A string that contains a CUID.
+ ///
+ public Cuid(string c)
+ {
+ Guard.IsNotNullOrWhiteSpace(c);
+ CuidResult result = new();
- ///
- /// Converts the string representation of a CUID to the equivalent structure.
- ///
- /// The string to convert.
- /// A structure that contains the value that was parsed.
- public static Cuid Parse(string input)
- {
- ArgumentNullException.ThrowIfNull(input);
+ _ = TryParseCuid(c.AsSpan(), true, ref result);
- return Parse((ReadOnlySpan) input);
- }
+ this = result.ToCuid();
+ }
- ///
- /// Converts a read-only character span that represents a CUID to the equivalent structure.
- ///
- /// A read-only span containing the bytes representing a CUID.
- /// A structure that contains the value that was parsed.
- [SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
- public static Cuid Parse(ReadOnlySpan input)
- {
- CuidResult result = new();
+ ///
+ /// Initializes a new instance of the structure.
+ ///
+ /// A new CUID object.
+ public static Cuid NewCuid()
+ {
+ CuidResult result = new()
+ {
+ _counter = Counter.Instance.Value,
+ _fingerprint = Context.IdentityFingerprint,
+ _random = BinaryPrimitives.ReadInt64LittleEndian(Utils.GenerateRandom()),
+ _timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
+ };
- _ = TryParseCuid(input, true, ref result);
+ return result.ToCuid();
+ }
- return result.ToCuid();
- }
+ ///
+ /// Indicates whether the values of two specified objects are equal.
+ ///
+ /// The first object to compare.
+ /// The second object to compare.
+ /// true if left and right are equal; otherwise, false.
+ public static bool operator ==(Cuid left, Cuid right)
+ {
+ return left.Equals(right);
+ }
- ///
- /// Converts the specified read-only span of characters containing the representation of a CUID to the equivalent
- /// structure.
- ///
- /// A span containing the characters representing the CUID to convert.
- ///
- /// When this method returns, contains the parsed value. If the method returns true,
- /// result contains a valid Guid. If the method returns false, result equals .
- ///
- /// true if the parse operation was successful; otherwise, false.
- public static bool TryParse(ReadOnlySpan input, out Cuid result)
- {
- CuidResult parseResult = new();
- if ( TryParseCuid(input, false, ref parseResult) )
+ ///
+ /// Compares two values to determine which is greater.
+ ///
+ /// The first object to compare.
+ /// The second object to compare.
+ /// true if left is greater than right; otherwise, false.
+ public static bool operator >(Cuid left, Cuid right)
{
- result = parseResult.ToCuid();
- return true;
+ return left.CompareTo(right) > 0;
}
- result = default;
- return false;
- }
+ ///
+ /// Compares two values to determine which is greater or equal.
+ ///
+ /// The first object to compare.
+ /// The second object to compare.
+ /// true if left is greater than or equal to right; otherwise, false.
+ public static bool operator >=(Cuid left, Cuid right)
+ {
+ return left.CompareTo(right) >= 0;
+ }
- ///
- /// Converts the string representation of a CUID to the equivalent structure.
- ///
- /// A string containing the CUID to convert.
- ///
- /// When this method returns, contains the parsed value. If the method returns true,
- /// result contains a valid Guid. If the method returns false, result equals .
- ///
- /// true if the parse operation was successful; otherwise, false.
- public static bool TryParse([NotNullWhen(true)] string? input, out Cuid result)
- {
- if ( input is not null )
+ ///
+ /// Indicates whether the values of two specified objects are not equal.
+ ///
+ /// The first object to compare.
+ /// The second object to compare.
+ /// true if left and right are not equal; otherwise, false.
+ public static bool operator !=(Cuid left, Cuid right)
{
- return TryParse((ReadOnlySpan) input, out result);
+ return !left.Equals(right);
}
- result = default;
- return false;
- }
+ ///
+ /// Compares two values to determine which is less.
+ ///
+ /// The first object to compare.
+ /// The second object to compare.
+ /// true if left is less than right; otherwise, false.
+ public static bool operator <(Cuid left, Cuid right)
+ {
+ return left.CompareTo(right) < 0;
+ }
- ///
- public int CompareTo(Cuid other)
- {
- int cComparison = _counter.CompareTo(other._counter);
- if ( cComparison != 0 )
+ ///
+ /// Compares two values to determine which is less or equal.
+ ///
+ /// The first object to compare.
+ /// The second object to compare.
+ /// true if left is less than or equal to right; otherwise, false.
+ public static bool operator <=(Cuid left, Cuid right)
{
- return cComparison;
+ return left.CompareTo(right) <= 0;
}
- int fComparison = string.Compare(_fingerprint, other._fingerprint, StringComparison.OrdinalIgnoreCase);
- if ( fComparison != 0 )
+ ///
+ /// Converts the string representation of a CUID to the equivalent structure.
+ ///
+ /// The string to convert.
+ /// A structure that contains the value that was parsed.
+ public static Cuid Parse(string input)
{
- return fComparison;
+ return string.IsNullOrWhiteSpace(input) ? Empty : Parse(input.AsSpan());
}
- int rComparison = _random.CompareTo(other._random);
- return rComparison != 0 ? rComparison : _timestamp.CompareTo(other._timestamp);
- }
+ ///
+ /// Converts a read-only character span that represents a CUID to the equivalent structure.
+ ///
+ /// A read-only span containing the bytes representing a CUID.
+ /// A structure that contains the value that was parsed.
+ [SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
+ public static Cuid Parse(ReadOnlySpan input)
+ {
+ CuidResult result = new();
- ///
- public int CompareTo(object? obj)
- {
- if ( ReferenceEquals(null, obj) )
+ _ = TryParseCuid(input, true, ref result);
+
+ return result.ToCuid();
+ }
+
+ ///
+ /// Converts the specified read-only span of characters containing the representation of a CUID to the equivalent
+ /// structure.
+ ///
+ /// A span containing the characters representing the CUID to convert.
+ ///
+ /// When this method returns, contains the parsed value. If the method returns true,
+ /// result contains a valid Guid. If the method returns false, result equals .
+ ///
+ /// true if the parse operation was successful; otherwise, false.
+ public static bool TryParse(ReadOnlySpan input, out Cuid result)
{
- return 1;
+ CuidResult parseResult = new();
+
+ if ( TryParseCuid(input, false, ref parseResult) )
+ {
+ result = parseResult.ToCuid();
+ return true;
+ }
+
+ result = default;
+ return false;
}
- return obj is Cuid other
- ? CompareTo(other)
- : throw new ArgumentException($"Object must be of type {nameof(Cuid)}");
- }
+ ///
+ /// Converts the string representation of a CUID to the equivalent structure.
+ ///
+ /// A string containing the CUID to convert.
+ ///
+ /// When this method returns, contains the parsed value. If the method returns true,
+ /// result contains a valid Guid. If the method returns false, result equals .
+ ///
+ /// true if the parse operation was successful; otherwise, false.
+#if NET6_0_OR_GREATER
+ public static bool TryParse([NotNullWhen(true)] string? input, out Cuid result)
+#else
+ public static bool TryParse([AllowNull] string input, out Cuid result)
+#endif
+ {
+ if ( !string.IsNullOrWhiteSpace(input) )
+ {
+ return TryParse(input.AsSpan(), out result);
+ }
- ///
- public bool Equals(Cuid other)
- {
- return _counter == other._counter &&
- string.Equals(_fingerprint, other._fingerprint, StringComparison.OrdinalIgnoreCase) &&
- _random == other._random &&
- _timestamp == other._timestamp;
- }
+ result = default;
+ return false;
+ }
- ///
- public override bool Equals(object? obj)
- {
- return obj is Cuid other && Equals(other);
- }
+ ///
+#if NET6_0_OR_GREATER
+ public int CompareTo(object? obj)
+#else
+ public int CompareTo(object obj)
+#endif
+ {
+ if ( ReferenceEquals(null, obj) )
+ {
+ return 1;
+ }
- ///
- public override int GetHashCode()
- {
- HashCode hashCode = new();
+ return obj is Cuid other
+ ? CompareTo(other)
+ : throw new ArgumentException($"Object must be of type {nameof(Cuid)}");
+ }
+
+ ///
+ public bool Equals(Cuid other)
+ {
+ if ( _fingerprint == null )
+ {
+ return _counter == other._counter &&
+ _random == other._random &&
+ _timestamp == other._timestamp;
+ }
- hashCode.Add(_counter);
- hashCode.Add(_fingerprint, StringComparer.OrdinalIgnoreCase);
- hashCode.Add(_random);
- hashCode.Add(_timestamp);
+ return _counter == other._counter &&
+ _fingerprint.SequenceEqual(other._fingerprint) &&
+ _random == other._random &&
+ _timestamp == other._timestamp;
+ }
- return hashCode.ToHashCode();
- }
+ ///
+#if NET6_0_OR_GREATER
+ public override bool Equals(object? obj)
+#else
+ public override bool Equals(object obj)
+#endif
+ {
+ return obj is Cuid other && Equals(other);
+ }
- ///
- /// Returns a string representation of the value of this instance.
- ///
- /// The value of this .
- public override string ToString()
- {
- return string.Create(25, ( _t: _timestamp, _c: _counter, _f: _fingerprint, _r: _random ),
- (dest, buffer) =>
- {
- Prefix.WriteTo(ref dest);
+ ///
+ public override int GetHashCode()
+ {
+ return HashCode.Combine(_counter, StructuralComparisons.StructuralEqualityComparer.GetHashCode(_fingerprint), _random, _timestamp);
+ }
- Utils.Encode((ulong) buffer._t)
- .WriteTo(ref dest);
+ ///
+ public void ReadXml(XmlReader reader)
+ {
+ reader.Read();
- Utils.Encode(buffer._c)
- .TrimPad(BlockSize)
- .WriteTo(ref dest);
+ CuidResult result = new();
- buffer._f.WriteTo(ref dest);
+ _ = TryParseCuid(reader.Value.AsSpan(), true, ref result);
- Utils.Encode(buffer._r)
- .TrimPad(BlockSize * 2)
- .WriteTo(ref dest);
- });
- }
+ Unsafe.AsRef(in this) = result.ToCuid();
+ }
- private static bool IsAlphaNum(ReadOnlySpan input)
- {
- foreach ( char t in input )
+ ///
+ /// Returns a string representation of the value of this instance.
+ ///
+ /// The value of this .
+ public override string ToString()
{
- if ( !char.IsLetterOrDigit(t) )
- {
- return false;
- }
+#if NET6_0_OR_GREATER
+ return string.Create(25, ( _t: _timestamp, _c: _counter, _f: _fingerprint, _r: _random ),
+ (dest, buffer) =>
+ {
+ Prefix.WriteTo(ref dest);
+
+ Utils.Encode((ulong) buffer._t)
+ .WriteTo(ref dest);
+
+ Utils.Encode(buffer._c)
+ .TrimPad(BlockSize)
+ .WriteTo(ref dest);
+
+ Encoding.UTF8.GetString(buffer._f).WriteTo(ref dest);
+
+ Utils.Encode(buffer._r)
+ .TrimPad(BlockSize * 2)
+ .WriteTo(ref dest);
+ });
+#else
+ List items =
+ [
+ Prefix,
+ Utils.Encode((ulong) _timestamp),
+ Utils.Encode(_counter).TrimPad(BlockSize),
+ Encoding.UTF8.GetString(_fingerprint),
+ Utils.Encode(_random).TrimPad(BlockSize * 2)
+ ];
+
+ return string.Join(string.Empty, items);
+#endif
}
- return true;
- }
+ ///
+ public void WriteXml(XmlWriter writer)
+ {
+ writer.WriteString(ToString());
+ }
- private static bool TryParseCuid(ReadOnlySpan cuidString, bool throwException, ref CuidResult result)
- {
- cuidString = cuidString.Trim();
- if ( cuidString.Length != ValueLength || !cuidString.StartsWith(Prefix) || !IsAlphaNum(cuidString) )
+ private static bool IsAlphaNum(ReadOnlySpan input)
{
- if ( throwException )
+ foreach ( char t in input )
{
- result.SetFailure(Resources.Resources.Format_CuidUnrecognized);
+ if ( !char.IsLetterOrDigit(t) )
+ {
+ return false;
+ }
}
- return false;
+ return true;
}
- ReadOnlySpan timestamp = cuidString[1..9];
- ReadOnlySpan counter = cuidString[9..^12];
- ReadOnlySpan fingerprint = cuidString[13..^8];
- ReadOnlySpan random = cuidString[^8..];
-
- result._counter = Utils.Decode(counter);
- result._fingerprint = fingerprint.ToString();
- result._random = Utils.Decode(random);
- result._timestamp = (long) Utils.Decode(timestamp);
+ private static bool TryParseCuid(ReadOnlySpan cuidString, bool throwException, ref CuidResult result)
+ {
+ cuidString = cuidString.Trim();
+ if ( cuidString.Length != ValueLength || !cuidString.StartsWith(Prefix.AsSpan()) || !IsAlphaNum(cuidString) )
+ {
+ if ( throwException )
+ {
+ result.SetFailure(Resources.Resources.Format_CuidUnrecognized);
+ }
- return true;
- }
+ return false;
+ }
- [ExcludeFromCodeCoverage]
- XmlSchema? IXmlSerializable.GetSchema()
- {
- return null;
- }
+ ReadOnlySpan timestamp = cuidString[1..9];
+ ReadOnlySpan counter = cuidString[9..^12];
+ ReadOnlySpan fingerprint = cuidString[13..^8];
+ ReadOnlySpan random = cuidString[^8..];
- ///
- public void ReadXml(XmlReader reader)
- {
- reader.Read();
-
- CuidResult result = new();
-
- _ = TryParseCuid(reader.Value, true, ref result);
+ result._counter = Utils.Decode(counter);
+ result._fingerprint = Encoding.UTF8.GetBytes(fingerprint.ToString());
+ result._random = Utils.Decode(random);
+ result._timestamp = Utils.Decode(timestamp);
- Unsafe.AsRef(in this) = result.ToCuid();
- }
+ return true;
+ }
- ///
- public void WriteXml(XmlWriter writer)
- {
- writer.WriteString(ToString());
- }
-
- [SuppressMessage("ReSharper", "InconsistentNaming")]
- [StructLayout(LayoutKind.Explicit)]
- private struct CuidResult
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public readonly Cuid ToCuid()
+ [ExcludeFromCodeCoverage]
+#if NET6_0_OR_GREATER
+ XmlSchema? IXmlSerializable.GetSchema()
+#else
+ XmlSchema IXmlSerializable.GetSchema()
+#endif
{
- CuidResult result = this;
- return Unsafe.As(ref Unsafe.AsRef(ref result));
+ return null;
}
- #pragma warning disable CA1822
- // ReSharper disable once MemberCanBeMadeStatic.Local
- internal readonly void SetFailure(string message)
+ [SuppressMessage("ReSharper", "InconsistentNaming")]
+ [StructLayout(LayoutKind.Explicit)]
+ private struct CuidResult
{
- throw new FormatException(message);
- }
- #pragma warning restore CA1822
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public readonly Cuid ToCuid()
+ {
+#if NET8_0_OR_GREATER
+ CuidResult result = this;
+ return Unsafe.As(ref Unsafe.AsRef(ref result));
+#else
+ return Unsafe.As(ref Unsafe.AsRef(in this));
+#endif
+ }
- #pragma warning disable S4487
- [FieldOffset(8)] internal ulong _counter;
+ #pragma warning disable CA1822
+ // ReSharper disable once MemberCanBeMadeStatic.Local
+ internal readonly void SetFailure(string message)
+ {
+ throw new FormatException(message);
+ }
+ #pragma warning restore CA1822
- [FieldOffset(0)] internal string _fingerprint;
+ #pragma warning disable S4487
+ [FieldOffset(8)]
+ internal long _counter;
- [FieldOffset(16)] internal ulong _random;
+ [FieldOffset(0)]
+ internal byte[] _fingerprint;
- [FieldOffset(24)] internal long _timestamp;
- #pragma warning restore S4487
- }
+ [FieldOffset(16)]
+ internal long _random;
- private static class Context
- {
- public static readonly string IdentityFingerprint = GenerateFingerprint();
+ [FieldOffset(24)]
+ internal long _timestamp;
+ #pragma warning restore S4487
+ }
- private static string GenerateFingerprint()
+ private static class Context
{
- byte[] identity = Fingerprint.Generate(FingerprintVersion.One);
-
- return Encoding.UTF8.GetString(identity);
+ public static readonly byte[] IdentityFingerprint = Fingerprint.Generate(FingerprintVersion.One);
}
- }
- private sealed class Counter
- {
- // ReSharper disable once InconsistentNaming
- private static readonly Lazy _counter = new(() => new Counter());
- private static readonly ulong DiscreteValues = (ulong) Math.Pow(36, 4);
+ private sealed class Counter
+ {
+ // ReSharper disable once InconsistentNaming
+ private static readonly Lazy _counter = new(() => new Counter());
- private volatile uint _value;
+ private static readonly long DiscreteValues = (long) Math.Pow(36, 4);
- public static Counter Instance => _counter.Value;
+ private volatile int _value;
- public uint Value
- {
- get
+ public static Counter Instance => _counter.Value;
+
+ public int Value
{
- _value = _value < DiscreteValues ? _value : 0;
- Interlocked.Increment(ref _value);
+ get
+ {
+ _value = _value < DiscreteValues ? _value : 0;
+ Interlocked.Increment(ref _value);
- return _value;
+ return _value;
+ }
}
}
+
+ ///
+ public int CompareTo(Cuid other)
+ {
+ int counterComparison = _counter.CompareTo(other._counter);
+ if ( counterComparison != 0 )
+ {
+ return counterComparison;
+ }
+
+ int randomComparison = _random.CompareTo(other._random);
+ return randomComparison != 0 ? randomComparison : _timestamp.CompareTo(other._timestamp);
+ }
}
}
diff --git a/src/cuid.net/Cuid2.cs b/src/cuid.net/Cuid2.cs
index e9e559b..654f1aa 100644
--- a/src/cuid.net/Cuid2.cs
+++ b/src/cuid.net/Cuid2.cs
@@ -1,149 +1,169 @@
-namespace Visus.Cuid;
-
-using System.Buffers.Binary;
-using System.Runtime.InteropServices;
-using NSec.Cryptography;
-
-///
-/// Represents a collision resistant unique identifier (CUID).
-///
-[StructLayout(LayoutKind.Sequential)]
-public readonly struct Cuid2 : IEquatable
+namespace Visus.Cuid
{
- private const int DefaultLength = 24;
+ using System;
+ using System.Buffers.Binary;
+ using System.Collections;
+ using System.Diagnostics.CodeAnalysis;
+ using System.Linq;
+ using System.Runtime.InteropServices;
+ using System.Threading;
+ using CommunityToolkit.Diagnostics;
+ using Org.BouncyCastle.Crypto.Digests;
- private readonly ulong _counter = Counter.Instance.Value;
+ ///
+ /// Represents a collision resistant unique identifier (CUID).
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public readonly struct Cuid2 : IEquatable
+ {
+ private const int DefaultLength = 24;
- private readonly byte[] _fingerprint;
+ private readonly long _counter;
- private readonly int _maxLength;
+ private readonly byte[] _fingerprint;
- private readonly char _prefix;
+ private readonly int _maxLength;
- private readonly byte[] _random;
+ private readonly char _prefix;
- private readonly long _timestamp;
+ private readonly byte[] _random;
- ///
- /// Initializes a new instance of the structure.
- ///
- /// The structure will initialize with a default maximum length of 24.
- /// A new CUID object.
- public Cuid2()
- : this(DefaultLength)
- {
- }
+ private readonly long _timestamp;
- ///
- /// Initializes a new instance of the structure.
- ///
- /// Defines the maximum string length value of .
- /// The value defined for cannot be less than 4 or greater than 32.
- ///
- /// The value of was less than 4 or greater
- /// than 32.
- ///
- public Cuid2(int maxLength)
- {
- if ( maxLength is < 4 or > 32 )
+ ///
+ /// Initializes a new instance of the structure.
+ ///
+ /// The structure will initialize with a default maximum length of 24.
+ /// A new CUID object.
+ public Cuid2()
+ : this(DefaultLength)
{
- throw new ArgumentOutOfRangeException(nameof(maxLength),
- string.Format(Resources.Resources.Arg_Cuid2IntCtor, "4", "32"));
}
+
+ ///
+ /// Initializes a new instance of the structure.
+ ///
+ /// Defines the maximum string length value of .
+ /// The value defined for cannot be less than 4 or greater than 32.
+ ///
+ /// The value of was less than 4 or greater
+ /// than 32.
+ ///
+ public Cuid2(int maxLength)
+ {
+ Guard.IsInRange(maxLength, 4, 33);
- _maxLength = maxLength;
-
- _fingerprint = Context.IdentityFingerprint;
- _prefix = Utils.GenerateCharacterPrefix();
- _random = Utils.GenerateRandom(maxLength);
- _timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
- }
-
- ///
- /// Indicates whether the values of two specified objects are equal.
- ///
- /// The first object to compare.
- /// The second object to compare.
- /// true if left and right are equal; otherwise, false.
- public static bool operator ==(Cuid2 left, Cuid2 right)
- {
- return left.Equals(right);
- }
+ _counter = Counter.Instance.Value;
+ _maxLength = maxLength;
- ///
- /// Indicates whether the values of two specified objects are not equal.
- ///
- /// The first object to compare.
- /// The second object to compare.
- /// true if left and right are not equal; otherwise, false.
- public static bool operator !=(Cuid2 left, Cuid2 right)
- {
- return !left.Equals(right);
- }
+ _fingerprint = Context.IdentityFingerprint;
+ _prefix = Utils.GenerateCharacterPrefix();
+ _random = Utils.GenerateRandom(maxLength);
+ _timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
+ }
- ///
- public bool Equals(Cuid2 other)
- {
- return _counter == other._counter &&
- _fingerprint.Equals(other._fingerprint) &&
- _prefix == other._prefix &&
- _random.Equals(other._random) &&
- _timestamp == other._timestamp;
- }
+ ///
+ /// Indicates whether the values of two specified objects are equal.
+ ///
+ /// The first object to compare.
+ /// The second object to compare.
+ /// true if left and right are equal; otherwise, false.
+ public static bool operator ==(Cuid2 left, Cuid2 right)
+ {
+ return left.Equals(right);
+ }
- ///
- public override bool Equals(object? obj)
- {
- return obj is Cuid2 other && Equals(other);
- }
+ ///
+ /// Indicates whether the values of two specified objects are not equal.
+ ///
+ /// The first object to compare.
+ /// The second object to compare.
+ /// true if left and right are not equal; otherwise, false.
+ public static bool operator !=(Cuid2 left, Cuid2 right)
+ {
+ return !left.Equals(right);
+ }
- ///
- public override int GetHashCode()
- {
- return HashCode.Combine(_counter, _fingerprint, _prefix, _random, _timestamp);
- }
+ ///
+ [SuppressMessage("ReSharper", "SimplifyConditionalTernaryExpression")]
+ public bool Equals(Cuid2 other)
+ {
+ return ( _counter == other._counter &&
+ _fingerprint == null ) || ( _fingerprint.SequenceEqual(other._fingerprint) &&
+ _prefix == other._prefix &&
+ _random == null ) || ( _random.SequenceEqual(other._random) &&
+ _timestamp == other._timestamp );
+ }
- ///
- /// Returns a string representation of the value of this instance.
- ///
- /// The value of this .
- public override string ToString()
- {
- Span buffer = stackalloc byte[16];
+ ///
+#if NET6_0_OR_GREATER
+ public override bool Equals(object? obj)
+#else
+ public override bool Equals(object obj)
+#endif
+ {
+ return obj is Cuid2 other && Equals(other);
+ }
- BinaryPrimitives.WriteInt64LittleEndian(buffer[..8], _timestamp);
- BinaryPrimitives.WriteUInt64LittleEndian(buffer[^8..], _counter);
+ ///
+ public override int GetHashCode()
+ {
+ return HashCode.Combine(_counter, StructuralComparisons.StructuralEqualityComparer.GetHashCode(_fingerprint), _prefix, _random, _timestamp);
+ }
- IncrementalHash.Initialize(HashAlgorithm.Sha512, out IncrementalHash state);
+ ///
+ /// Returns a string representation of the value of this instance.
+ ///
+ /// The value of this .
+ public override string ToString()
+ {
+ if ( _counter == 0 ||
+ _fingerprint == null ||
+ _maxLength == 0 ||
+ _prefix == char.MinValue ||
+ _random == null ||
+ _timestamp == 0 )
+ {
+ return new string('0', DefaultLength);
+ }
- IncrementalHash.Update(ref state, buffer);
- IncrementalHash.Update(ref state, _fingerprint);
- IncrementalHash.Update(ref state, _random);
+ Span buffer = stackalloc byte[16];
- byte[] hash = IncrementalHash.Finalize(ref state);
+ BinaryPrimitives.WriteInt64LittleEndian(buffer[..8], _timestamp);
+ BinaryPrimitives.WriteInt64LittleEndian(buffer[^8..], _counter);
- return _prefix + Utils.Encode(hash)[..( _maxLength - 1 )];
- }
+ Sha3Digest digest = new(512);
- private static class Context
- {
- public static readonly byte[] IdentityFingerprint = Fingerprint.Generate();
- }
+ digest.BlockUpdate(buffer.ToArray(), 0, buffer.Length);
+ digest.BlockUpdate(_fingerprint, 0, _fingerprint.Length);
+ digest.BlockUpdate(_random, 0, _random.Length);
- private sealed class Counter
- {
- // ReSharper disable once InconsistentNaming
- private static readonly Lazy _counter = new(() => new Counter());
+ byte[] hash = new byte[digest.GetByteLength()];
+ digest.DoFinal(hash, 0);
- private ulong _value;
+ return _prefix + Utils.Encode(hash)[..( _maxLength - 1 )];
+ }
- private Counter()
+ private static class Context
{
- _value = BinaryPrimitives.ReadUInt64LittleEndian(Utils.GenerateRandom()) * 476782367;
+ public static readonly byte[] IdentityFingerprint = Fingerprint.Generate();
}
- public static Counter Instance => _counter.Value;
+ private sealed class Counter
+ {
+ // ReSharper disable once InconsistentNaming
+ private static readonly Lazy _counter = new(() => new Counter());
+
+ private long _value;
- public ulong Value => Interlocked.Increment(ref _value);
+ private Counter()
+ {
+ _value = BinaryPrimitives.ReadInt64LittleEndian(Utils.GenerateRandom()) * 476782367;
+ }
+
+ public static Counter Instance => _counter.Value;
+
+ public long Value => Interlocked.Increment(ref _value);
+ }
}
}
diff --git a/src/cuid.net/Extensions/StringExtensions.cs b/src/cuid.net/Extensions/StringExtensions.cs
index b49ebe4..54a1be0 100644
--- a/src/cuid.net/Extensions/StringExtensions.cs
+++ b/src/cuid.net/Extensions/StringExtensions.cs
@@ -1,22 +1,25 @@
-namespace Visus.Cuid.Extensions;
-
-internal static class StringExtensions
+namespace Visus.Cuid.Extensions
{
- internal static string TrimPad(this string source, int size)
- {
- return string.IsNullOrWhiteSpace(source)
- ? string.Empty
- : source.PadLeft(9, '0')[^size..];
- }
+ using System;
- internal static void WriteTo(this string source, ref Span destination)
+ internal static class StringExtensions
{
- source.AsSpan().WriteToInternal(ref destination);
- }
+ internal static string TrimPad(this string source, int size)
+ {
+ return string.IsNullOrWhiteSpace(source)
+ ? string.Empty
+ : source.PadLeft(9, '0')[^size..];
+ }
- private static void WriteToInternal(this ReadOnlySpan source, ref Span destination)
- {
- source.CopyTo(destination);
- destination = destination[source.Length..];
+ internal static void WriteTo(this string source, ref Span destination)
+ {
+ source.AsSpan().WriteToInternal(ref destination);
+ }
+
+ private static void WriteToInternal(this ReadOnlySpan source, ref Span destination)
+ {
+ source.CopyTo(destination);
+ destination = destination[source.Length..];
+ }
}
}
diff --git a/src/cuid.net/Fingerprint.cs b/src/cuid.net/Fingerprint.cs
index f2839b9..16c3766 100644
--- a/src/cuid.net/Fingerprint.cs
+++ b/src/cuid.net/Fingerprint.cs
@@ -1,86 +1,116 @@
-namespace Visus.Cuid;
-
-using System.Buffers.Binary;
-using System.Globalization;
-using System.Text;
-using Abstractions;
-using Extensions;
-
-internal static class Fingerprint
+namespace Visus.Cuid
{
- public static byte[] Generate(FingerprintVersion version = FingerprintVersion.Two)
- {
- return version == FingerprintVersion.One
- ? GenerateLegacyIdentity()
- : GenerateIdentity();
- }
-
- private static byte[] GenerateIdentity()
+ using System;
+ using System.Buffers.Binary;
+ using System.Globalization;
+ using System.Linq;
+ using System.Text;
+ using Abstractions;
+ using Extensions;
+#if NETSTANDARD2_0 || NET472
+ using System.Diagnostics;
+ using System.Runtime.InteropServices;
+#endif
+
+ internal static class Fingerprint
{
- byte[] identity = Encoding.UTF8.GetBytes(RetrieveSystemName());
-
- Span buffer = stackalloc byte[identity.Length + 40];
-
- identity.CopyTo(buffer[..identity.Length]);
-
- BinaryPrimitives.WriteInt32LittleEndian(
- buffer.Slice(identity.Length + 1, 4),
- Environment.ProcessId
- );
-
- BinaryPrimitives.WriteInt32LittleEndian(
- buffer.Slice(identity.Length + 6, 4),
- Environment.CurrentManagedThreadId
- );
-
- Utils.GenerateRandom(32).CopyTo(buffer[^32..]);
+ public static byte[] Generate(FingerprintVersion version = FingerprintVersion.Two)
+ {
+ return version == FingerprintVersion.One
+ ? GenerateLegacyIdentity()
+ : GenerateIdentity();
+ }
- return buffer.ToArray();
- }
+ private static byte[] GenerateIdentity()
+ {
+ byte[] identity = Encoding.UTF8.GetBytes(RetrieveSystemName());
- private static byte[] GenerateLegacyIdentity()
- {
- string machineName = RetrieveSystemName();
+ Span buffer = stackalloc byte[identity.Length + 40];
- int machineIdentifier = machineName.Length + 36;
- machineIdentifier = machineName.Aggregate(machineIdentifier, (i, c) => i + c);
+ identity.CopyTo(buffer[..identity.Length]);
- string result = string.Create(4, machineIdentifier, (dest, _) =>
- {
- Environment.ProcessId
- .ToString(CultureInfo.InvariantCulture)
- .TrimPad(2).WriteTo(ref dest);
- machineIdentifier.ToString(CultureInfo.InvariantCulture)
- .TrimPad(2).WriteTo(ref dest);
- });
+#if NET6_0_OR_GREATER
+ BinaryPrimitives.WriteInt32LittleEndian(
+ buffer.Slice(identity.Length + 1, 4),
+ Environment.ProcessId
+ );
+#else
+ BinaryPrimitives.WriteInt32LittleEndian(
+ buffer.Slice(identity.Length + 1, 4),
+ Process.GetCurrentProcess().Id
+ );
+#endif
- return Encoding.UTF8.GetBytes(result);
- }
+ BinaryPrimitives.WriteInt32LittleEndian(
+ buffer.Slice(identity.Length + 6, 4),
+ Environment.CurrentManagedThreadId
+ );
- private static string GenerateSystemName()
- {
- byte[] bytes = Utils.GenerateRandom(32);
- string hostname = Convert.ToHexString(bytes).ToUpperInvariant();
+ Utils.GenerateRandom(32).CopyTo(buffer[^32..]);
- return OperatingSystem.IsWindows()
- ? hostname[..15] // windows hostnames are limited to 15 characters
- : hostname;
- }
+ return buffer.ToArray();
+ }
- private static string RetrieveSystemName()
- {
- string machineName;
- try
+ private static byte[] GenerateLegacyIdentity()
{
- machineName = !string.IsNullOrWhiteSpace(Environment.MachineName)
- ? Environment.MachineName
- : GenerateSystemName();
+ string machineName = RetrieveSystemName();
+
+ int machineIdentifier = machineName.Length + 36;
+ machineIdentifier = machineName.Aggregate(machineIdentifier, (i, c) => i + c);
+
+#if NET6_0_OR_GREATER
+ string result = string.Create(4, machineIdentifier, (dest, _) =>
+ {
+ Environment.ProcessId
+ .ToString(CultureInfo.InvariantCulture)
+ .TrimPad(2).WriteTo(ref dest);
+ machineIdentifier.ToString(CultureInfo.InvariantCulture)
+ .TrimPad(2).WriteTo(ref dest);
+ });
+#else
+ StringBuilder sb = new();
+
+ sb.Append(Process.GetCurrentProcess().Id.ToString(CultureInfo.InvariantCulture).TrimPad(2));
+ sb.Append(machineIdentifier.ToString(CultureInfo.InvariantCulture).TrimPad(2));
+
+ string result = sb.ToString();
+#endif
+
+ return Encoding.UTF8.GetBytes(result);
}
- catch ( InvalidOperationException )
+
+ private static string GenerateSystemName()
{
- machineName = GenerateSystemName();
+ byte[] bytes = Utils.GenerateRandom(32);
+
+#if NET6_0_OR_GREATER
+ string hostname = Convert.ToHexString(bytes).ToUpperInvariant();
+ return OperatingSystem.IsWindows()
+ ? hostname[..15] // windows hostnames are limited to 15 characters
+ : hostname;
+#else
+ string hostname = BitConverter.ToString(bytes);
+ return RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
+ ? hostname[..15]
+ : hostname;
+#endif
}
- return machineName;
+ private static string RetrieveSystemName()
+ {
+ string machineName;
+ try
+ {
+ machineName = !string.IsNullOrWhiteSpace(Environment.MachineName)
+ ? Environment.MachineName
+ : GenerateSystemName();
+ }
+ catch ( InvalidOperationException )
+ {
+ machineName = GenerateSystemName();
+ }
+
+ return machineName;
+ }
}
}
diff --git a/src/cuid.net/Obsoletions.cs b/src/cuid.net/Obsoletions.cs
index 1d094d0..dec1265 100644
--- a/src/cuid.net/Obsoletions.cs
+++ b/src/cuid.net/Obsoletions.cs
@@ -1,7 +1,8 @@
-namespace Visus.Cuid;
-
-internal static class Obsoletions
+namespace Visus.Cuid
{
- internal const string CuidDiagId = "VISLIB0001";
- internal const string CuidMessage = "Cuid is deprecated and should not be used. Use Cuid2 instead.";
+ internal static class Obsoletions
+ {
+ internal const string CuidDiagId = "VISLIB0001";
+ internal const string CuidMessage = "Cuid is deprecated and should not be used. Use Cuid2 instead.";
+ }
}
diff --git a/src/cuid.net/Resources/Resources.resx b/src/cuid.net/Resources/Resources.resx
index 7a91191..e34853a 100644
--- a/src/cuid.net/Resources/Resources.resx
+++ b/src/cuid.net/Resources/Resources.resx
@@ -1,7 +1,8 @@
-
diff --git a/src/cuid.net/Serialization/Json/Converters/CuidConverter.cs b/src/cuid.net/Serialization/Json/Converters/CuidConverter.cs
index 9a44ba1..54e9c32 100644
--- a/src/cuid.net/Serialization/Json/Converters/CuidConverter.cs
+++ b/src/cuid.net/Serialization/Json/Converters/CuidConverter.cs
@@ -1,21 +1,26 @@
-#pragma warning disable VISLIB0001
-namespace Visus.Cuid.Serialization.Json.Converters;
-
-using System.Text.Json;
-using System.Text.Json.Serialization;
-
-///
-public class CuidConverter : JsonConverter
+#if NETSTANDARD2_0 || NET472
+#pragma warning disable CS0618 // Type or member is obsolete
+#endif
+#pragma warning disable VISLIB0001
+namespace Visus.Cuid.Serialization.Json.Converters
{
- ///
- public override Cuid Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
- {
- return Cuid.Parse(reader.GetString()!);
- }
+ using System;
+ using System.Text.Json;
+ using System.Text.Json.Serialization;
///
- public override void Write(Utf8JsonWriter writer, Cuid value, JsonSerializerOptions options)
+ public class CuidConverter : JsonConverter
{
- writer.WriteStringValue(value.ToString());
+ ///
+ public override Cuid Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ return Cuid.Parse(reader.GetString()!);
+ }
+
+ ///
+ public override void Write(Utf8JsonWriter writer, Cuid value, JsonSerializerOptions options)
+ {
+ writer.WriteStringValue(value.ToString());
+ }
}
}
diff --git a/src/cuid.net/Utils.cs b/src/cuid.net/Utils.cs
index 179eed0..bcc35f8 100644
--- a/src/cuid.net/Utils.cs
+++ b/src/cuid.net/Utils.cs
@@ -1,76 +1,126 @@
-namespace Visus.Cuid;
-
-using System.Numerics;
-using System.Security.Cryptography;
-
-internal static class Utils
+namespace Visus.Cuid
{
- private static readonly BigInteger BigRadix = new(36);
+ using System;
+ using System.Linq;
+ using System.Numerics;
+ using System.Runtime.CompilerServices;
+ using System.Security.Cryptography;
- private static readonly double BitsPerDigit = Math.Log(36, 2);
+ internal static class Utils
+ {
+#if NET6_0_OR_GREATER
+ private static readonly BigInteger BigRadix = new(36);
+#else
+ private static readonly BigInteger BigRadix = new BigInteger(36);
+#endif
- private const int Radix = 36;
+ private static readonly double BitsPerDigit = Math.Log(36, 2);
- private static readonly Random Random = new();
+ private const int Radix = 36;
- internal static ulong Decode(ReadOnlySpan input)
- {
- return input.ToString()
- .Select(s => s is >= '0' and <= '9' ? s - '0' : 10 + s - 'a')
- .Aggregate((ulong) 0, (i, c) => ( i * Radix ) + (uint) c);
- }
+#if NET6_0_OR_GREATER
+ private static readonly Random Random = new();
+#else
+ private static readonly Random Random = new Random();
+#endif
- internal static string Encode(ReadOnlySpan value)
- {
- if ( value.IsEmpty )
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static long Decode(ReadOnlySpan input)
{
- return string.Empty;
+#if NET6_0_OR_GREATER
+ return input.ToString()
+ .Select(s => s is >= '0' and <= '9' ? s - '0' : 10 + s - 'a')
+ .Aggregate((long) 0, (i, c) => ( i * Radix ) + c);
+#else
+ return input.ToString()
+ .Select(s => s >= '0' && s <= '9' ? s - '0' : 10 + s - 'a')
+ .Aggregate((long) 0, (i, c) => ( i * Radix ) + c);
+#endif
}
- int length = (int) Math.Ceiling(value.Length * 8 / BitsPerDigit);
- int i = length;
- Span buffer = stackalloc char[length];
-
- BigInteger d = new(value, true);
- while ( !d.IsZero )
+ internal static string Encode(ReadOnlySpan value)
{
- d = BigInteger.DivRem(d, BigRadix, out BigInteger r);
- int c = (int) r;
- buffer[--i] = (char) ( c is >= 0 and <= 9 ? c + 48 : c + 'a' - 10 );
+ if ( value.IsEmpty )
+ {
+ return string.Empty;
+ }
+
+ int length = (int) Math.Ceiling(value.Length * 8 / BitsPerDigit);
+ int i = length;
+ Span buffer = stackalloc char[length];
+
+#if NET6_0_OR_GREATER
+ BigInteger d = new(value, true);
+#else
+ byte[] unsigned = value.ToArray().Concat(new byte[] { 00 }).ToArray();
+ BigInteger d = new(unsigned);
+#endif
+ while ( !d.IsZero )
+ {
+ d = BigInteger.DivRem(d, BigRadix, out BigInteger r);
+ int c = (int) r;
+
+ buffer[--i] = (char) ( c is >= 0 and <= 9 ? c + 48 : c + 'a' - 10 );
+ }
+
+#if NET6_0_OR_GREATER
+ return new string(buffer.Slice(i, length - i));
+#else
+ return new string(buffer.Slice(i, length - i).ToArray());
+#endif
}
- return new string(buffer.Slice(i, length - i));
- }
-
- internal static string Encode(ulong value)
- {
- if ( value is 0 )
+ internal static string Encode(ulong value)
{
- return string.Empty;
+ if ( value is 0 )
+ {
+ return string.Empty;
+ }
+
+ const int length = 32;
+ int i = length;
+ Span buffer = stackalloc char[length];
+
+ do
+ {
+ ulong c = value % Radix;
+
+#if NET6_0_OR_GREATER
+ buffer[--i] = (char) ( c is >= 0 and <= 9 ? c + 48 : c + 'a' - 10 );
+#else
+ c += (ulong) ( c <= 9 ? 48 : 'a' - 10 );
+ buffer[--i] = (char) c;
+#endif
+
+ value /= Radix;
+ } while ( value > 0 );
+
+#if NET6_0_OR_GREATER
+ return new string(buffer.Slice(i, length - i));
+#else
+ return new string(buffer.Slice(i, length - i).ToArray());
+#endif
}
- const int length = 32;
- int i = length;
- Span buffer = stackalloc char[length];
-
- do
+ internal static char GenerateCharacterPrefix()
{
- ulong c = value % Radix;
- buffer[--i] = (char) ( c is >= 0 and <= 9 ? c + 48 : c + 'a' - 10 );
- value /= Radix;
- } while ( value > 0 );
-
- return new string(buffer.Slice(i, length - i));
- }
-
- internal static char GenerateCharacterPrefix()
- {
- int c = Random.Next(26);
- return c > 13 ? char.ToLowerInvariant((char) ( 'a' + c )) : (char) ( 'a' + c );
- }
+ int c = Random.Next(26);
+ return c > 13 ? char.ToLowerInvariant((char) ( 'a' + c )) : (char) ( 'a' + c );
+ }
- internal static byte[] GenerateRandom(int length = 8)
- {
- return RandomNumberGenerator.GetBytes(length);
+#if NET6_0_OR_GREATER
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+#endif
+ internal static byte[] GenerateRandom(int length = 8)
+ {
+#if NET6_0_OR_GREATER
+ return RandomNumberGenerator.GetBytes(length);
+#else
+ byte[] seed = new byte[length];
+ RandomNumberGenerator.Create().GetBytes(seed);
+
+ return seed;
+#endif
+ }
}
}
diff --git a/src/cuid.net/cuid.net.csproj b/src/cuid.net/cuid.net.csproj
index 064cb68..9cdc255 100644
--- a/src/cuid.net/cuid.net.csproj
+++ b/src/cuid.net/cuid.net.csproj
@@ -1,7 +1,7 @@
- net8.0
+ net472;netstandard2.0;net6.0;net8.0
Visus.Cuid
Copyright (c) 2023 Visus Development Team
@@ -13,10 +13,13 @@
.NET implementation of collision-resistant ids
+
+ true
+
+
$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb
true
- true
true
true
MIT
@@ -34,6 +37,9 @@
+
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
@@ -42,7 +48,11 @@
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
diff --git a/src/cuid.net/packages.lock.json b/src/cuid.net/packages.lock.json
deleted file mode 100644
index 5a61db6..0000000
--- a/src/cuid.net/packages.lock.json
+++ /dev/null
@@ -1,53 +0,0 @@
-{
- "version": 2,
- "dependencies": {
- "net8.0": {
- "Microsoft.CodeAnalysis.NetAnalyzers": {
- "type": "Direct",
- "requested": "[8.0.0, )",
- "resolved": "8.0.0",
- "contentHash": "DxiTgkCl3CGq1rYmBX2wjY7XGbxiBdL4J+/AJIAFLKy5z70NxhnVRnPghnicXZ8oF6JKVXlW3xwznRbI3ioEKg=="
- },
- "Microsoft.NET.ILLink.Tasks": {
- "type": "Direct",
- "requested": "[8.0.4, )",
- "resolved": "8.0.4",
- "contentHash": "PZb5nfQ+U19nhnmnR9T1jw+LTmozhuG2eeuzuW5A7DqxD/UXW2ucjmNJqnqOuh8rdPzM3MQXoF8AfFCedJdCUw=="
- },
- "Microsoft.SourceLink.GitHub": {
- "type": "Direct",
- "requested": "[8.0.0, )",
- "resolved": "8.0.0",
- "contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==",
- "dependencies": {
- "Microsoft.Build.Tasks.Git": "8.0.0",
- "Microsoft.SourceLink.Common": "8.0.0"
- }
- },
- "NSec.Cryptography": {
- "type": "Direct",
- "requested": "[24.4.0, )",
- "resolved": "24.4.0",
- "contentHash": "R89OF0T5OY9QnPRoTsMCaPKMqtXcWKZSWAO4zyUaFHI+ZRMgXU7WaIwg/rPP3vOfdaLl8HdUHWkDB+2B9FOO7g==",
- "dependencies": {
- "libsodium": "[1.0.19, 1.0.20)"
- }
- },
- "libsodium": {
- "type": "Transitive",
- "resolved": "1.0.19",
- "contentHash": "tupm/HViwBN6Knd/gckR+cLaJGR39GLmiU4iDMM5hp/1BoczMr8fwJhSU+3/C2V4hi9nBK/4FICRKtTLU30TCA=="
- },
- "Microsoft.Build.Tasks.Git": {
- "type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ=="
- },
- "Microsoft.SourceLink.Common": {
- "type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw=="
- }
- }
- }
-}
\ No newline at end of file
diff --git a/tests/cuid.net.tests/ApiFacts.cs b/tests/cuid.net.tests/ApiFacts.cs
index 7044a12..6787c93 100644
--- a/tests/cuid.net.tests/ApiFacts.cs
+++ b/tests/cuid.net.tests/ApiFacts.cs
@@ -1,24 +1,29 @@
-namespace Visus.Cuid.Tests;
-
-using System.Diagnostics.CodeAnalysis;
-using System.Runtime.CompilerServices;
-using PublicApiGenerator;
-
-[ExcludeFromCodeCoverage]
-public class ApiFacts
+namespace Visus.Cuid.Tests
{
- [Fact]
- [MethodImpl(MethodImplOptions.NoInlining)]
- public async Task Cuid_NoBreakingChanges_Async()
+ using System.Diagnostics.CodeAnalysis;
+ using System.Runtime.CompilerServices;
+ using System.Threading.Tasks;
+ using PublicApiGenerator;
+ using Xunit;
+#if NET6_0_OR_GREATER
+ using VerifyXunit;
+#endif
+
+ [ExcludeFromCodeCoverage]
+ public class ApiFacts
{
- var api = typeof(Cuid2).Assembly.GeneratePublicApi(new ApiGeneratorOptions
+#if NET6_0_OR_GREATER
+ [Fact]
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public async Task Cuid_NoBreakingChanges_Async()
{
- ExcludeAttributes = new[]
+ var api = typeof(Cuid2).Assembly.GeneratePublicApi(new ApiGeneratorOptions
{
- "System.Runtime.Versioning.TargetFrameworkAttribute", "System.Reflection.AssemblyMetadataAttribute"
- }
- });
+ ExcludeAttributes = ["System.Runtime.Versioning.TargetFrameworkAttribute", "System.Reflection.AssemblyMetadataAttribute"]
+ });
- await Verify(api);
+ await Verifier.Verify(api);
+ }
+#endif
}
}
diff --git a/tests/cuid.net.tests/Cuid2Facts.cs b/tests/cuid.net.tests/Cuid2Facts.cs
index a87caf3..b98929d 100644
--- a/tests/cuid.net.tests/Cuid2Facts.cs
+++ b/tests/cuid.net.tests/Cuid2Facts.cs
@@ -1,54 +1,61 @@
-namespace Visus.Cuid.Tests;
-
-using System.Diagnostics.CodeAnalysis;
-
-[ExcludeFromCodeCoverage]
-public class Cuid2Facts
+namespace Visus.Cuid.Tests
{
- [Fact]
- public void Cuid2_Constructor()
+ using System;
+ using System.Diagnostics;
+ using System.Diagnostics.CodeAnalysis;
+ using System.Linq;
+ using Xunit;
+
+ [ExcludeFromCodeCoverage]
+ public class Cuid2Facts
{
- var cuid = new Cuid2();
+ [Fact]
+ public void Cuid2_Constructor()
+ {
+ var cuid = new Cuid2();
- var cuidString = cuid.ToString();
+ var cuidString = cuid.ToString();
- var result = cuidString.Length == 24
- && cuidString.All(char.IsLetterOrDigit);
+ var result = cuidString.Length == 24
+ && cuidString.All(char.IsLetterOrDigit);
- Assert.True(result);
- }
+ Debug.WriteLine(result);
- [Fact]
- public void Cuid2_Constructor_DefinedLength()
- {
- var cuid = new Cuid2(10);
+ Assert.True(result);
+ }
- var cuidString = cuid.ToString();
+ [Fact]
+ public void Cuid2_Constructor_DefinedLength()
+ {
+ var cuid = new Cuid2(10);
- var result = cuidString.Length == 10
- && cuidString.All(char.IsLetterOrDigit);
+ var cuidString = cuid.ToString();
- Assert.True(result);
- }
+ var result = cuidString.Length == 10
+ && cuidString.All(char.IsLetterOrDigit);
- [Fact]
- public void Cuid2_Constructor_ThrowsArgumentOutOfRangeException()
- {
- Assert.Throws(() => new Cuid2(64));
- }
+ Assert.True(result);
+ }
- [Fact]
- public void Cuid2_Equality()
- {
- var c1 = new Cuid2();
- var c2 = new Cuid2();
+ [Fact]
+ public void Cuid2_Constructor_ThrowsArgumentOutOfRangeException()
+ {
+ Assert.Throws(() => new Cuid2(64));
+ }
+
+ [Fact]
+ public void Cuid2_Equality()
+ {
+ var c1 = new Cuid2(10);
+ var c2 = new Cuid2(10);
- Assert.False(c1.Equals(c2));
- Assert.False(c1.Equals((object) c2));
+ Assert.False(c1.Equals(c2));
+ Assert.False(c1.Equals((object) c2));
- Assert.False(c1 == c2);
- Assert.True(c1 != c2);
+ Assert.False(c1 == c2);
+ Assert.True(c1 != c2);
- Assert.False(c1.GetHashCode() == c2.GetHashCode());
+ Assert.False(c1.GetHashCode() == c2.GetHashCode());
+ }
}
}
diff --git a/tests/cuid.net.tests/CuidFacts.cs b/tests/cuid.net.tests/CuidFacts.cs
index 509f66d..b0cb399 100644
--- a/tests/cuid.net.tests/CuidFacts.cs
+++ b/tests/cuid.net.tests/CuidFacts.cs
@@ -1,229 +1,273 @@
-#pragma warning disable VISLIB0001
-namespace Visus.Cuid.Tests;
-
-using System.Diagnostics.CodeAnalysis;
-using System.Text;
-using System.Text.Json;
-using System.Xml;
-using System.Xml.Serialization;
-
-[ExcludeFromCodeCoverage]
-public class CuidFacts
+#if NETSTANDARD2_0 || NET472
+#pragma warning disable CS0618 // Type or member is obsolete
+#endif
+#pragma warning disable VISLIB0001
+namespace Visus.Cuid.Tests
{
- // _t _c _f _r
- // c lbqylg5v 0001 08mn 7kmn0t1e
- private const string CuidString = "clbqylg5v000108mn7kmn0t1e";
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics.CodeAnalysis;
+ using System.IO;
+ using System.Linq;
+ using System.Text;
+ using System.Text.Json;
+ using System.Xml;
+ using System.Xml.Serialization;
+ using Xunit;
+
+ [ExcludeFromCodeCoverage]
+ public class CuidFacts
+ {
+ // _t _c _f _r
+ // c lbqylg5v 0001 08mn 7kmn0t1e
+ private const string CuidString = "clbqylg5v000108mn7kmn0t1e";
- private const string InvalidCuidString = "xSQcDXq7N6YTJZ7i1zNXCA==";
+ private const string InvalidCuidString = "xSQcDXq7N6YTJZ7i1zNXCA==";
- [Fact]
- public void Cuid_ConstructFromString()
- {
- var cuid = new Cuid(CuidString);
+ [Fact]
+ public void Cuid_ConstructFromString()
+ {
+ var cuid = new Cuid(CuidString);
- Assert.Equal(CuidString, cuid.ToString());
- }
+ Assert.Equal(CuidString, cuid.ToString());
+ }
- [Fact]
- public void Cuid_ConstructFromString_ThrowsFormatException()
- {
- Assert.Throws(() => new Cuid(InvalidCuidString));
- }
+ [Fact]
+ public void Cuid_ConstructFromString_ThrowsFormatException()
+ {
+ Assert.Throws(() => new Cuid(InvalidCuidString));
+ }
- [Fact]
- public void Cuid_Equality()
- {
- var c1 = new Cuid(CuidString);
- var c2 = new Cuid(CuidString);
+ [Fact]
+ public void Cuid_Constructor_IsCuidEmpty()
+ {
+ var cuid = new Cuid();
+ Assert.Equal(cuid, Cuid.Empty);
+ }
- Assert.True(c1 == c2);
- }
+ [Fact]
+ public void Cuid_Equality()
+ {
+ var c1 = new Cuid(CuidString);
+ var c2 = new Cuid(CuidString);
- [Fact]
- public void Cuid_Equals()
- {
- var c1 = new Cuid(CuidString);
- var c2 = new Cuid(CuidString);
+ Assert.True(c1 == c2);
+ }
- Assert.True(c1.Equals(c2));
- Assert.True(c1.Equals((object) c2));
+ [Fact]
+ public void Cuid_Equals()
+ {
+ var c1 = new Cuid(CuidString);
+ var c2 = new Cuid(CuidString);
- Assert.True(c1.CompareTo(null) > 0);
- Assert.True(c1.CompareTo(c2) == 0);
- Assert.True(c1.CompareTo((object) c2) == 0);
+ Assert.True(c1.Equals(c2));
+ Assert.True(c1.Equals((object) c2));
- Assert.True(c1 >= c2);
- Assert.True(c1 <= c2);
+ Assert.True(c1.CompareTo(null) > 0);
+ Assert.Equal(0, c1.CompareTo(c2));
+ Assert.Equal(0, c1.CompareTo((object) c2));
- Assert.True(c1.GetHashCode() == c2.GetHashCode());
- }
+ Assert.True(c1 >= c2);
+ Assert.True(c1 <= c2);
- [Fact]
- public void Cuid_GreaterThan()
- {
- var c1 = new Cuid("clbqylg5v000108mn7kmn0t1e");
- var c2 = new Cuid("clbqylg5v000208mn7kmn0t1e");
+ Assert.True(c1.GetHashCode() == c2.GetHashCode());
+ }
- Assert.True(c2 > c1);
- }
+ [Fact]
+ public void Cuid_GreaterThan()
+ {
+ var c1 = new Cuid("clbqylg5v000108mn7kmn0t1e");
+ var c2 = new Cuid("clbqylg5v000208mn7kmn0t1e");
- [Fact]
- public void Cuid_Inequality()
- {
- var c1 = new Cuid();
- var c2 = new Cuid(CuidString);
+ Assert.True(c2 > c1);
+ }
- Assert.False(c1 == c2);
- }
+ [Fact]
+ public void Cuid_Inequality()
+ {
+ var c1 = new Cuid();
+ var c2 = new Cuid(CuidString);
- [Fact]
- public void Cuid_Json_Deserialize()
- {
- var result = JsonSerializer.Deserialize($"\"{CuidString}\"");
+ Assert.False(c1 == c2);
+ }
- Assert.Equal(CuidString, result.ToString());
- }
+ [Fact]
+ public void Cuid_Json_Deserialize()
+ {
+ var result = JsonSerializer.Deserialize($"\"{CuidString}\"");
- [Fact]
- public void Cuid_Json_Serialize()
- {
- var cuid = new Cuid(CuidString);
+ Assert.Equal(CuidString, result.ToString());
+ }
- var result = JsonSerializer.Serialize(cuid);
+ [Fact]
+ public void Cuid_Json_Serialize()
+ {
+ var cuid = new Cuid(CuidString);
- Assert.Equal($"\"{CuidString}\"", result);
- }
+ var result = JsonSerializer.Serialize(cuid);
- [Fact]
- public void Cuid_LessThan()
- {
- var c1 = new Cuid("clbqylg5v000108mn7kmn0t1e");
- var c2 = new Cuid("clbqylg5v000208mn7kmn0t1e");
+ Assert.Equal($"\"{CuidString}\"", result);
+ }
- Assert.True(c1 < c2);
- }
+ [Fact]
+ public void Cuid_LessThan()
+ {
+ var c1 = new Cuid("clbqylg5v000108mn7kmn0t1e");
+ var c2 = new Cuid("clbqylg5v000208mn7kmn0t1e");
- [Fact]
- public void Cuid_NewCuid()
- {
- var cuid = Cuid.NewCuid();
+ Assert.True(c1 < c2);
+ }
- var cuidString = cuid.ToString();
+ [Fact]
+ public void Cuid_NewCuid()
+ {
+ var cuid = Cuid.NewCuid();
- var result = cuidString.Length == 25
- && cuidString.All(char.IsLetterOrDigit)
- && cuid != Cuid.Empty;
+ var cuidString = cuid.ToString();
- Assert.True(result);
- }
+ var result = cuidString.Length == 25
+ && cuidString.All(char.IsLetterOrDigit)
+ && cuid != Cuid.Empty;
- [Fact]
- public void Cuid_NotEquals()
- {
- var c1 = new Cuid();
- var c2 = new Cuid(CuidString);
+ Assert.True(result);
+ }
- Assert.False(c1.Equals(c2));
- Assert.False(c1.Equals((object) c2));
+ [Fact]
+ public void Cuid_NotEquals()
+ {
+ var c1 = new Cuid();
+ var c2 = new Cuid(CuidString);
- Assert.False(c1.CompareTo(c2) == 0);
- Assert.False(c1.CompareTo((object) c2) == 0);
+ Assert.False(c1.Equals(c2));
+ Assert.False(c1.Equals((object) c2));
- Assert.False(c1.GetHashCode() == c2.GetHashCode());
- }
+ Assert.False(c1.CompareTo(c2) == 0);
+ Assert.False(c1.CompareTo((object) c2) == 0);
- [Fact]
- public void Cuid_Parse()
- {
- var cuid = Cuid.Parse(CuidString);
+ Assert.False(c1.GetHashCode() == c2.GetHashCode());
+ }
- Assert.Equal(CuidString, cuid.ToString());
- }
+ [Fact]
+ public void Cuid_Parse()
+ {
+ var cuid = Cuid.Parse(CuidString);
- [Fact]
- public void Cuid_Parse_ThrowsFormatException()
- {
- Assert.Throws(() => Cuid.Parse(InvalidCuidString));
- }
+ Assert.Equal(CuidString, cuid.ToString());
+ }
- [Fact]
- public void Cuid_TryParse_Null_ReturnsFalse()
- {
- var result = Cuid.TryParse(null, out _);
+ [Fact]
+ public void Cuid_Parse_ThrowsFormatException()
+ {
+ Assert.Throws(() => Cuid.Parse(InvalidCuidString));
+ }
- Assert.False(result);
- }
+ [Fact]
+ public void Cuid_TryParse_Null_ReturnsFalse()
+ {
+#if NET6_0_OR_GREATER
+ var result = Cuid.TryParse(null, out _);
+#else
+ var result = Cuid.TryParse((string) null, out _);
+#endif
- [Fact]
- public void Cuid_TryParse_ReturnsFalse()
- {
- var result = Cuid.TryParse(InvalidCuidString, out var cuid);
+ Assert.False(result);
+ }
- Assert.False(result);
- Assert.Equal(cuid, Cuid.Empty);
- }
+ [Fact]
+ public void Cuid_TryParse_ReturnsFalse()
+ {
+ var result = Cuid.TryParse(InvalidCuidString, out var cuid);
- [Fact]
- public void Cuid_TryParse_ReturnsTrue()
- {
- var result = Cuid.TryParse(CuidString, out var cuid);
+ Assert.False(result);
+ Assert.Equal(cuid, Cuid.Empty);
+ }
- Assert.True(result);
- Assert.Equal(CuidString, cuid.ToString());
- }
+ [Fact]
+ public void Cuid_TryParse_ReturnsTrue()
+ {
+ var result = Cuid.TryParse(CuidString, out var cuid);
- [Fact]
- public void Cuid_Uniqueness()
- {
- var cuids = new HashSet();
+ Assert.True(result);
+ Assert.Equal(CuidString, cuid.ToString());
+ }
- for ( var i = 0; i < 1000000; i++ )
+ [Fact]
+ public void Cuid_Uniqueness()
{
- var cuid = Cuid.NewCuid();
- if ( cuids.Contains(cuid) )
+ var cuids = new HashSet();
+
+ for ( var i = 0; i < 1000000; i++ )
{
- Assert.Fail($"Collision detected at iteration {i}");
- }
+ var cuid = Cuid.NewCuid();
+ if ( cuids.Contains(cuid) )
+ {
+ Assert.Fail($"Collision detected at iteration {i}");
+ }
- cuids.Add(cuid);
+ cuids.Add(cuid);
+ }
}
- }
- [Fact]
- public void Cuid_Xml_Deserialize()
- {
- const string xml = "clbqylg5v000108mn7kmn0t1e";
+ [Fact]
+ public void Cuid_Xml_Deserialize()
+ {
+ const string xml = "clbqylg5v000108mn7kmn0t1e";
- var expected = new Cuid(CuidString);
+ var expected = new Cuid(CuidString);
- var serializer = new XmlSerializer(typeof(Cuid));
+ var serializer = new XmlSerializer(typeof(Cuid));
- using var stringReader = new StringReader(xml);
- using var xmlReader = XmlReader.Create(stringReader);
+#if NET6_0_OR_GREATER
+ using var stringReader = new StringReader(xml);
+ using var xmlReader = XmlReader.Create(stringReader);
- var cuid = serializer.Deserialize(xmlReader);
+ var cuid = serializer.Deserialize(xmlReader);
- Assert.Equal(expected, cuid);
- }
+ Assert.Equal(expected, cuid);
+#else
+ using ( var stringReader = new StringReader(xml) )
+ {
+ using ( var xmlReader = XmlReader.Create(stringReader) )
+ {
+ var cuid = serializer.Deserialize(xmlReader);
- [Fact]
- public void Cuid_Xml_Serialize()
- {
- const string expected = "clbqylg5v000108mn7kmn0t1e";
- var cuid = new Cuid(CuidString);
+ Assert.Equal(expected, cuid);
+ }
+ }
+#endif
+ }
- var serializer = new XmlSerializer(typeof(Cuid));
- var settings = new XmlWriterSettings
+ [Fact]
+ public void Cuid_Xml_Serialize()
{
- Indent = false,
- Encoding = new UnicodeEncoding(false, false)
- };
+ const string expected = "clbqylg5v000108mn7kmn0t1e";
+ var cuid = new Cuid(CuidString);
- using var stringWriter = new StringWriter();
- using var xmlWriter = XmlWriter.Create(stringWriter, settings);
+ var serializer = new XmlSerializer(typeof(Cuid));
+ var settings = new XmlWriterSettings
+ {
+ Indent = false,
+ Encoding = new UnicodeEncoding(false, false)
+ };
- serializer.Serialize(xmlWriter, cuid);
+#if NET6_0_OR_GREATER
+ using var stringWriter = new StringWriter();
+ using var xmlWriter = XmlWriter.Create(stringWriter, settings);
- Assert.Equal(expected, stringWriter.ToString());
+ serializer.Serialize(xmlWriter, cuid);
+
+ Assert.Equal(expected, stringWriter.ToString());
+#else
+ using ( var stringWriter = new StringWriter() )
+ {
+ using ( var xmlWriter = XmlWriter.Create(stringWriter, settings) )
+ {
+ serializer.Serialize(xmlWriter, cuid);
+
+ Assert.Equal(expected, stringWriter.ToString());
+ }
+ }
+#endif
+ }
}
}
diff --git a/tests/cuid.net.tests/Usings.cs b/tests/cuid.net.tests/Usings.cs
deleted file mode 100644
index c802f44..0000000
--- a/tests/cuid.net.tests/Usings.cs
+++ /dev/null
@@ -1 +0,0 @@
-global using Xunit;
diff --git a/tests/cuid.net.tests/cuid.net.tests.csproj b/tests/cuid.net.tests/cuid.net.tests.csproj
index 8009bf4..af8a90b 100644
--- a/tests/cuid.net.tests/cuid.net.tests.csproj
+++ b/tests/cuid.net.tests/cuid.net.tests.csproj
@@ -1,8 +1,7 @@
- net8.0
-
+ net472;net6.0;net8.0
false
Visus.Cuid.Tests
Library
@@ -12,16 +11,17 @@
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
+
+
+
-
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
diff --git a/tests/cuid.net.tests/packages.lock.json b/tests/cuid.net.tests/packages.lock.json
deleted file mode 100644
index 1e56ea8..0000000
--- a/tests/cuid.net.tests/packages.lock.json
+++ /dev/null
@@ -1,223 +0,0 @@
-{
- "version": 2,
- "dependencies": {
- "net8.0": {
- "coverlet.collector": {
- "type": "Direct",
- "requested": "[6.0.2, )",
- "resolved": "6.0.2",
- "contentHash": "bJShQ6uWRTQ100ZeyiMqcFlhP7WJ+bCuabUs885dJiBEzMsJMSFr7BOyeCw4rgvQokteGi5rKQTlkhfQPUXg2A=="
- },
- "coverlet.msbuild": {
- "type": "Direct",
- "requested": "[6.0.2, )",
- "resolved": "6.0.2",
- "contentHash": "8b4jBNH7mcQy1otyQErjjIUuGD74XxKZ1wvDufbY7jhWwckl7wIa+icjwdPYeI0aYMS4Tp63LIZvyMFjWwOMDw=="
- },
- "Microsoft.CodeAnalysis.NetAnalyzers": {
- "type": "Direct",
- "requested": "[8.0.0, )",
- "resolved": "8.0.0",
- "contentHash": "DxiTgkCl3CGq1rYmBX2wjY7XGbxiBdL4J+/AJIAFLKy5z70NxhnVRnPghnicXZ8oF6JKVXlW3xwznRbI3ioEKg=="
- },
- "Microsoft.NET.Test.Sdk": {
- "type": "Direct",
- "requested": "[17.9.0, )",
- "resolved": "17.9.0",
- "contentHash": "7GUNAUbJYn644jzwLm5BD3a2p9C1dmP8Hr6fDPDxgItQk9hBs1Svdxzz07KQ/UphMSmgza9AbijBJGmw5D658A==",
- "dependencies": {
- "Microsoft.CodeCoverage": "17.9.0",
- "Microsoft.TestPlatform.TestHost": "17.9.0"
- }
- },
- "PublicApiGenerator": {
- "type": "Direct",
- "requested": "[11.1.0, )",
- "resolved": "11.1.0",
- "contentHash": "iHU9N149uYirtVxGZh8dKIGv1CpecHD+5E2NVx1c490LqGyWCORZ52DpVqgjNs1rGluT1LNasRNBBjARssGcIg==",
- "dependencies": {
- "Mono.Cecil": "0.11.5",
- "System.CodeDom": "8.0.0"
- }
- },
- "Verify.Xunit": {
- "type": "Direct",
- "requested": "[24.2.0, )",
- "resolved": "24.2.0",
- "contentHash": "qyN2PWmhog5185n0xFzRIM4Is9Dgukq24Vdph3t+Df/g1rVeB0hMzb0HFWk3HvDRh3fuvTJN6orNnJYBXnFN1w==",
- "dependencies": {
- "Verify": "24.2.0",
- "xunit.abstractions": "2.0.3",
- "xunit.extensibility.execution": "2.8.0"
- }
- },
- "xunit": {
- "type": "Direct",
- "requested": "[2.8.0, )",
- "resolved": "2.8.0",
- "contentHash": "US3a3twJziAif1kFPGdk9fALwILHxV0n1roX5j67bN/d3o4DGNLHnV3tr5ZX+uinVrzfkf0avH3zGX8JPBC0qA==",
- "dependencies": {
- "xunit.analyzers": "1.13.0",
- "xunit.assert": "2.8.0",
- "xunit.core": "[2.8.0]"
- }
- },
- "xunit.runner.visualstudio": {
- "type": "Direct",
- "requested": "[2.8.0, )",
- "resolved": "2.8.0",
- "contentHash": "mqQbS2zr8dfgSWxkNOC6UTzO8JoqpTmM5+FFn2XR/2nVmx2JvEY0YbM5pt2FmXVg9YVe+jKUPHd6KrroyCl67w=="
- },
- "Argon": {
- "type": "Transitive",
- "resolved": "0.17.0",
- "contentHash": "TC/5P8sb2AKeC6dLAEx7ex1sr2IiQOI0tZ8yV6J3QT8qp7bUfP/blmwrgZ/zIab84XQ+XScT1zUeok96iZ7ReQ=="
- },
- "DiffEngine": {
- "type": "Transitive",
- "resolved": "15.4.0",
- "contentHash": "2UTLer/h9u6zKTEXuHmgG7lQPjUiOP7YuIWKY5XP25v7uCDQmJXQnyaNbW6g4JzG5gyMhgbulVYPyqaglwP1zw==",
- "dependencies": {
- "EmptyFiles": "8.2.0",
- "System.Management": "8.0.0"
- }
- },
- "EmptyFiles": {
- "type": "Transitive",
- "resolved": "8.2.0",
- "contentHash": "LnZLh5IPCc0zDjVWnta9pwLR9UxH0Ki08iru+2BRZ2tMigZDSlQQ9u3GnEjaDemaSCJwKLQyf3lsnVnbVldQ/g=="
- },
- "libsodium": {
- "type": "Transitive",
- "resolved": "1.0.19",
- "contentHash": "tupm/HViwBN6Knd/gckR+cLaJGR39GLmiU4iDMM5hp/1BoczMr8fwJhSU+3/C2V4hi9nBK/4FICRKtTLU30TCA=="
- },
- "Microsoft.CodeCoverage": {
- "type": "Transitive",
- "resolved": "17.9.0",
- "contentHash": "RGD37ZSrratfScYXm7M0HjvxMxZyWZL4jm+XgMZbkIY1UPgjUpbNA/t+WTGj/rC/0Hm9A3IrH3ywbKZkOCnoZA=="
- },
- "Microsoft.TestPlatform.ObjectModel": {
- "type": "Transitive",
- "resolved": "17.9.0",
- "contentHash": "1ilw/8vgmjLyKU+2SKXKXaOqpYFJCQfGqGz+x0cosl981VzjrY74Sv6qAJv+neZMZ9ZMxF3ArN6kotaQ4uvEBw==",
- "dependencies": {
- "System.Reflection.Metadata": "1.6.0"
- }
- },
- "Microsoft.TestPlatform.TestHost": {
- "type": "Transitive",
- "resolved": "17.9.0",
- "contentHash": "Spmg7Wx49Ya3SxBjyeAR+nQpjMTKZwTwpZ7KyeOTIqI/WHNPnBU4HUvl5kuHPQAwGWqMy4FGZja1HvEwvoaDiA==",
- "dependencies": {
- "Microsoft.TestPlatform.ObjectModel": "17.9.0",
- "Newtonsoft.Json": "13.0.1"
- }
- },
- "Mono.Cecil": {
- "type": "Transitive",
- "resolved": "0.11.5",
- "contentHash": "fxfX+0JGTZ8YQeu1MYjbBiK2CYTSzDyEeIixt+yqKKTn7FW8rv7JMY70qevup4ZJfD7Kk/VG/jDzQQTpfch87g=="
- },
- "Newtonsoft.Json": {
- "type": "Transitive",
- "resolved": "13.0.1",
- "contentHash": "ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A=="
- },
- "SimpleInfoName": {
- "type": "Transitive",
- "resolved": "2.2.0",
- "contentHash": "jZwJajqdF56n0HcwvM8wqrwhr8tBqp7E3dWVoa5XWMC4tqSXP4+rIfYipeVIavRUI5MSj5vYPCdwtF3h4RJvxA=="
- },
- "System.CodeDom": {
- "type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "WTlRjL6KWIMr/pAaq3rYqh0TJlzpouaQ/W1eelssHgtlwHAH25jXTkUphTYx9HaIIf7XA6qs/0+YhtLEQRkJ+Q=="
- },
- "System.IO.Hashing": {
- "type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "ne1843evDugl0md7Fjzy6QjJrzsjh46ZKbhf8GwBXb5f/gw97J4bxMs0NQKifDuThh/f0bZ0e62NPl1jzTuRqA=="
- },
- "System.Management": {
- "type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "jrK22i5LRzxZCfGb+tGmke2VH7oE0DvcDlJ1HAKYU8cPmD8XnpUT0bYn2Gy98GEhGjtfbR/sxKTVb+dE770pfA==",
- "dependencies": {
- "System.CodeDom": "8.0.0"
- }
- },
- "System.Reflection.Metadata": {
- "type": "Transitive",
- "resolved": "1.6.0",
- "contentHash": "COC1aiAJjCoA5GBF+QKL2uLqEBew4JsCkQmoHKbN3TlOZKa2fKLz5CpiRQKDz0RsAOEGsVKqOD5bomsXq/4STQ=="
- },
- "Verify": {
- "type": "Transitive",
- "resolved": "24.2.0",
- "contentHash": "PlWBOlByTPNp9cEc22TZ6I04yfbqICKDMJOw1k+6eWomVl1qSOhbc8QITBkoNspOsSb4oyrkYusjd3DspFerPg==",
- "dependencies": {
- "Argon": "0.17.0",
- "DiffEngine": "15.4.0",
- "SimpleInfoName": "2.2.0",
- "System.IO.Hashing": "8.0.0"
- }
- },
- "xunit.abstractions": {
- "type": "Transitive",
- "resolved": "2.0.3",
- "contentHash": "pot1I4YOxlWjIb5jmwvvQNbTrZ3lJQ+jUGkGjWE3hEFM0l5gOnBWS+H3qsex68s5cO52g+44vpGzhAt+42vwKg=="
- },
- "xunit.analyzers": {
- "type": "Transitive",
- "resolved": "1.13.0",
- "contentHash": "Pai9YnDV71/Ox14nBHB6/f62iyPyLbmUG/YYMiA4dfdFZvr0gIYE9yGxSr0i5Tr3INK75wgL2MCUNEKpeiZ2Fw=="
- },
- "xunit.assert": {
- "type": "Transitive",
- "resolved": "2.8.0",
- "contentHash": "lwf7Dy5/5HbDkaPx1YrGXCByytCEEcIn+KPI74jh2BD/RU/7RhO8c+S3k0Ph+Mr7+cLf338fl+o6UcgPCLa6PA=="
- },
- "xunit.core": {
- "type": "Transitive",
- "resolved": "2.8.0",
- "contentHash": "McSTFGTETCxLpmJKE9TWi9FtFthrRbpRrjz2V2g8sK2wRt1+JHs15vwi+B+nfftFkV9aFWIXZfzZM95TIGZNIA==",
- "dependencies": {
- "xunit.extensibility.core": "[2.8.0]",
- "xunit.extensibility.execution": "[2.8.0]"
- }
- },
- "xunit.extensibility.core": {
- "type": "Transitive",
- "resolved": "2.8.0",
- "contentHash": "eBJv9xQeY0p5z+C/L1tFjUFYqtl5pQqIEYCGTMl+MbRzA7sOlgYKwJE//vEePBp+mgBh7NjD0Qhz0liZBYM27w==",
- "dependencies": {
- "xunit.abstractions": "2.0.3"
- }
- },
- "xunit.extensibility.execution": {
- "type": "Transitive",
- "resolved": "2.8.0",
- "contentHash": "TyyrZesHB9ODZMS9c73OqiBz4x0vL944JCkSPBWW5w6PF2LlUfdfXRjjOhoIOuY6lTmEgl07rS4/Jot9mCYnpg==",
- "dependencies": {
- "xunit.extensibility.core": "[2.8.0]"
- }
- },
- "cuid.net": {
- "type": "Project",
- "dependencies": {
- "NSec.Cryptography": "[24.4.0, )"
- }
- },
- "NSec.Cryptography": {
- "type": "CentralTransitive",
- "requested": "[24.4.0, )",
- "resolved": "24.4.0",
- "contentHash": "R89OF0T5OY9QnPRoTsMCaPKMqtXcWKZSWAO4zyUaFHI+ZRMgXU7WaIwg/rPP3vOfdaLl8HdUHWkDB+2B9FOO7g==",
- "dependencies": {
- "libsodium": "[1.0.19, 1.0.20)"
- }
- }
- }
- }
-}
\ No newline at end of file