diff --git a/src/core-unit/Unit.Tests/UnitFormatTests/UnitFormatTests.Format.Utf8.cs b/src/core-unit/Unit.Tests/UnitFormatTests/UnitFormatTests.Format.Utf8.cs
new file mode 100644
index 00000000..302f81e8
--- /dev/null
+++ b/src/core-unit/Unit.Tests/UnitFormatTests/UnitFormatTests.Format.Utf8.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Text;
+using Xunit;
+
+namespace PrimeFuncPack.Core.Tests;
+
+partial class UnitFormatTests
+{
+ [Theory]
+ [MemberData(nameof(ExpectedFormatCases))]
+ public static void FormatToUtf8_ExpectCorrespondingResult(string? format, string expected)
+ {
+ var expectedBytes = Encoding.UTF8.GetBytes(expected);
+
+ var source = default(Unit);
+ var actualBytes = source.FormatToUtf8(format);
+
+ Assert.Equal(expectedBytes, actualBytes);
+ }
+}
diff --git a/src/core-unit/Unit/Unit.csproj b/src/core-unit/Unit/Unit.csproj
index ba78ed38..c3689020 100644
--- a/src/core-unit/Unit/Unit.csproj
+++ b/src/core-unit/Unit/Unit.csproj
@@ -19,7 +19,7 @@
PrimeFuncPack Core.Unit is a core library for .NET consisting of Unit type targeted for use in functional programming.
System
PrimeFuncPack.Core.Unit
- 4.0.0-rc.1
+ 4.0.0-rc.2
diff --git a/src/core-unit/Unit/Unit/Unit.Factory.From.cs b/src/core-unit/Unit/Unit/Unit.Factory.From.cs
index dc780e87..ba684c72 100644
--- a/src/core-unit/Unit/Unit/Unit.Factory.From.cs
+++ b/src/core-unit/Unit/Unit/Unit.Factory.From.cs
@@ -7,6 +7,9 @@ namespace System;
partial struct Unit
{
// We maintain that Unit can be derived from any input value.
+ //
+ // This factory is for use in method group conversion instead of lambda expressions
+ // like "_ => default(Unit)", "_ => new Unit()", or "_ => Unit.Value".
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Unit From(TResult result) => default;
diff --git a/src/core-unit/Unit/Unit/Unit.Factory.cs b/src/core-unit/Unit/Unit/Unit.Factory.cs
index 33b714eb..6aad7c75 100644
--- a/src/core-unit/Unit/Unit/Unit.Factory.cs
+++ b/src/core-unit/Unit/Unit/Unit.Factory.cs
@@ -4,8 +4,14 @@ namespace System;
partial struct Unit
{
+ // This singleton value is for use when it's needed to emphasize that Unit is being used.
+ // In other cases, prefer "default(Unit)" or "new Unit()" for better performance.
+
public static readonly Unit Value;
+ // This factory is for use in method group conversion instead of lambda expressions
+ // like "() => default(Unit)", "() => new Unit()", or "() => Unit.Value".
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Unit Get() => default;
}
diff --git a/src/core-unit/Unit/Unit/Unit.Format.cs b/src/core-unit/Unit/Unit/Unit.Format.cs
index 8f0e8d10..1db10da0 100644
--- a/src/core-unit/Unit/Unit/Unit.Format.cs
+++ b/src/core-unit/Unit/Unit/Unit.Format.cs
@@ -1,7 +1,5 @@
#pragma warning disable CA1822 // Mark members as static
-using System.Text;
-
namespace System;
partial struct Unit
@@ -10,6 +8,13 @@ public string Format(ReadOnlySpan format)
=>
UnitFormatter.Format(format);
+ // We use a design with byte array result and copying the result bytes for following:
+ // - to provide to the user a possibility to work with both bytes and a span over them;
+ // - not to expose the inner cache state despite it's protected by ReadOnlySpan.
+ public byte[] FormatToUtf8(ReadOnlySpan format)
+ =>
+ UnitFormatter.FormatToUtf8Span(format).ToArray();
+
public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format)
{
var formatted = UnitFormatter.Format(format);
@@ -22,7 +27,7 @@ public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan
public bool TryFormat(Span utf8Destination, out int bytesWritten, ReadOnlySpan format)
{
- var utf8Formatted = UnitFormatter.FormatToUtf8(format);
+ var utf8Formatted = UnitFormatter.FormatToUtf8Span(format);
// Call TryCopyTo instead of CopyTo not to duplicate the length check here
var result = utf8Formatted.TryCopyTo(utf8Destination);
diff --git a/src/core-unit/Unit/Unit/Unit.Parse.Static.Explicit.cs b/src/core-unit/Unit/Unit/Unit.Parse.Static.Explicit.cs
index a4714d9e..56892239 100644
--- a/src/core-unit/Unit/Unit/Unit.Parse.Static.Explicit.cs
+++ b/src/core-unit/Unit/Unit/Unit.Parse.Static.Explicit.cs
@@ -3,7 +3,7 @@
partial struct Unit
{
// We maintain that Unit can be derived from any input value.
-
+ //
// For the string versions we follow the contract which defines fail on null input,
// to keep consistency between Parse and TryParse methods, taking into account that
// TryParse has [NotNullWhen(true)] attribute on the input parameter.
diff --git a/src/core-unit/Unit/UnitExtensions/ToUnit.cs b/src/core-unit/Unit/UnitExtensions/ToUnit.cs
index 7f662ce8..e8c303bf 100644
--- a/src/core-unit/Unit/UnitExtensions/ToUnit.cs
+++ b/src/core-unit/Unit/UnitExtensions/ToUnit.cs
@@ -1,10 +1,12 @@
-using System.Runtime.CompilerServices;
-
-namespace System;
+namespace System;
partial class UnitExtensions
{
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ // We maintain that Unit can be derived from any input value.
+ // Unit.From is being called instead of returning default(Unit) for the sake of clarity.
+ //
+ // This extension is for more convenient syntax when converting to Unit from a result value.
+
public static Unit ToUnit(this TResult result)
=>
Unit.From(result);
diff --git a/src/core-unit/Unit/UnitFormatting/UnitFormUtf8.cs b/src/core-unit/Unit/UnitFormatting/UnitFormUtf8.cs
index b6e1dfc0..43f17be5 100644
--- a/src/core-unit/Unit/UnitFormatting/UnitFormUtf8.cs
+++ b/src/core-unit/Unit/UnitFormatting/UnitFormUtf8.cs
@@ -17,6 +17,8 @@ internal static class UnitFormUtf8
internal static ReadOnlySpan JsonObjExtended => new(InnerBytes.JsonObjExtended);
internal static ReadOnlySpan EmptyExtended => new(InnerBytes.EmptyExtended);
+ // We initialize the byte arrays inline with no static ctor to obtain and cache them
+ // lazily only on demand, and also isolate them in a nested class for thread-safety.
private static class InnerBytes
{
internal static readonly byte[] General = InnerGetBytes(UnitForm.General);
@@ -29,6 +31,7 @@ private static class InnerBytes
internal static readonly byte[] JsonObjExtended = InnerGetBytes(UnitForm.JsonObjExtended);
internal static readonly byte[] EmptyExtended = InnerGetBytes(UnitForm.EmptyExtended);
+ // We use the most proven method to obtain UTF-8 bytes.
private static byte[] InnerGetBytes(string s)
=>
Encoding.UTF8.GetBytes(s);
diff --git a/src/core-unit/Unit/UnitFormatting/UnitFormatter.FormatToUtf8.cs b/src/core-unit/Unit/UnitFormatting/UnitFormatter.FormatToUtf8.cs
index 798a4604..51d961b2 100644
--- a/src/core-unit/Unit/UnitFormatting/UnitFormatter.FormatToUtf8.cs
+++ b/src/core-unit/Unit/UnitFormatting/UnitFormatter.FormatToUtf8.cs
@@ -5,7 +5,7 @@ namespace System;
partial class UnitFormatter
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static ReadOnlySpan FormatToUtf8(ReadOnlySpan format)
+ internal static ReadOnlySpan FormatToUtf8Span(ReadOnlySpan format)
=>
format switch
{