Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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);
}
}
2 changes: 1 addition & 1 deletion src/core-unit/Unit/Unit.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<Description>PrimeFuncPack Core.Unit is a core library for .NET consisting of Unit type targeted for use in functional programming.</Description>
<RootNamespace>System</RootNamespace>
<AssemblyName>PrimeFuncPack.Core.Unit</AssemblyName>
<Version>4.0.0-rc.1</Version>
<Version>4.0.0-rc.2</Version>
</PropertyGroup>

<ItemGroup>
Expand Down
3 changes: 3 additions & 0 deletions src/core-unit/Unit/Unit/Unit.Factory.From.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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>(TResult result) => default;
Expand Down
6 changes: 6 additions & 0 deletions src/core-unit/Unit/Unit/Unit.Factory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
11 changes: 8 additions & 3 deletions src/core-unit/Unit/Unit/Unit.Format.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
#pragma warning disable CA1822 // Mark members as static

using System.Text;

namespace System;

partial struct Unit
Expand All @@ -10,6 +8,13 @@ public string Format(ReadOnlySpan<char> 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<char> format)
=>
UnitFormatter.FormatToUtf8Span(format).ToArray();

public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format)
{
var formatted = UnitFormatter.Format(format);
Expand All @@ -22,7 +27,7 @@ public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan

public bool TryFormat(Span<byte> utf8Destination, out int bytesWritten, ReadOnlySpan<char> 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);
Expand Down
2 changes: 1 addition & 1 deletion src/core-unit/Unit/Unit/Unit.Parse.Static.Explicit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
10 changes: 6 additions & 4 deletions src/core-unit/Unit/UnitExtensions/ToUnit.cs
Original file line number Diff line number Diff line change
@@ -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<TResult>(this TResult result)
=>
Unit.From(result);
Expand Down
3 changes: 3 additions & 0 deletions src/core-unit/Unit/UnitFormatting/UnitFormUtf8.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ internal static class UnitFormUtf8
internal static ReadOnlySpan<byte> JsonObjExtended => new(InnerBytes.JsonObjExtended);
internal static ReadOnlySpan<byte> 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);
Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace System;
partial class UnitFormatter
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static ReadOnlySpan<byte> FormatToUtf8(ReadOnlySpan<char> format)
internal static ReadOnlySpan<byte> FormatToUtf8Span(ReadOnlySpan<char> format)
=>
format switch
{
Expand Down