Compare commits

...

3 Commits

8 changed files with 78 additions and 61 deletions

View File

@ -58,6 +58,7 @@ TypeInitializationException.
### Fixed ### Fixed
- X10D: Fixed `decimal.TryWriteBigEndianBytes` and `decimal.TryWriteLittleEndianBytes`.
- X10D.Hosting: Fixed `AddHostedSingleton` not accepting an interface as the service type. - X10D.Hosting: Fixed `AddHostedSingleton` not accepting an interface as the service type.
## [3.3.0] - 2023-08-21 ## [3.3.0] - 2023-08-21

View File

@ -5,7 +5,7 @@ or submit a pull request.
### Pull request guidelines ### Pull request guidelines
This project uses C# 11.0 language features where feasible, and adheres to StyleCop rules with some minor adjustments. This project uses C# 12.0 language features where feasible, and adheres to StyleCop rules with some minor adjustments.
There is an `.editorconfig` included in this repository. For quick and painless pull requests, ensure that the analyzer does not There is an `.editorconfig` included in this repository. For quick and painless pull requests, ensure that the analyzer does not
throw warnings. throw warnings.
@ -17,7 +17,7 @@ convetional commits specification.
Below are a few pointers to which you may refer, but keep in mind this is not an exhaustive list: Below are a few pointers to which you may refer, but keep in mind this is not an exhaustive list:
- Use C# 11.0 features where possible - Use C# 12.0 features where possible
- Try to ensure code is CLS-compliant. Where this is not possible, decorate methods with `CLSCompliantAttribute` and pass `false` - Try to ensure code is CLS-compliant. Where this is not possible, decorate methods with `CLSCompliantAttribute` and pass `false`
- Follow all .NET guidelines and coding conventions. - Follow all .NET guidelines and coding conventions.
See https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/coding-style/coding-conventions See https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/coding-style/coding-conventions

View File

@ -1,6 +1,6 @@
<Project> <Project>
<PropertyGroup> <PropertyGroup>
<LangVersion>11.0</LangVersion> <LangVersion>12.0</LangVersion>
<Optimize>true</Optimize> <Optimize>true</Optimize>
<ImplicitUsings>true</ImplicitUsings> <ImplicitUsings>true</ImplicitUsings>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>

View File

@ -0,0 +1,54 @@
using NUnit.Framework;
using X10D.IO;
namespace X10D.Tests.IO;
[TestFixture]
internal class DecimalTests
{
[Test]
public void GetBigEndianBytes_ShouldReturnBytes_InBigEndian()
{
const decimal value = 1234m;
byte[] expected = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 210];
byte[] bytes = value.GetBigEndianBytes();
CollectionAssert.AreEqual(expected, bytes);
}
[Test]
public void GetLittleEndianBytes_ShouldReturnBytes_InLittleEndian()
{
const decimal value = 1234m;
byte[] expected = [210, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
byte[] bytes = value.GetLittleEndianBytes();
CollectionAssert.AreEqual(expected, bytes);
}
[Test]
public void TryWriteBigEndianBytes_ShouldWriteBytes_InBigEndian()
{
const decimal value = 1234m;
byte[] expected = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 210];
Span<byte> bytes = stackalloc byte[16];
value.TryWriteBigEndianBytes(bytes);
CollectionAssert.AreEqual(expected, bytes.ToArray());
}
[Test]
public void TryWriteLittleEndianBytes_ShouldWriteBytes_InLittleEndian()
{
const decimal value = 1234m;
byte[] expected = [210, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
Span<byte> bytes = stackalloc byte[16];
value.TryWriteLittleEndianBytes(bytes);
CollectionAssert.AreEqual(expected, bytes.ToArray());
}
}

View File

@ -48,9 +48,10 @@ internal partial class StreamTests
Span<byte> actual = stackalloc byte[16]; Span<byte> actual = stackalloc byte[16];
ReadOnlySpan<byte> expected = stackalloc byte[] ReadOnlySpan<byte> expected = stackalloc byte[]
{ {
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x10, 0x00, 0x00 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x68
}; };
int read = stream.Read(actual); int read = stream.Read(actual);
Trace.WriteLine(string.Join(' ', actual.ToArray()));
Assert.That(read, Is.EqualTo(16)); Assert.That(read, Is.EqualTo(16));
CollectionAssert.AreEqual(expected.ToArray(), actual.ToArray()); CollectionAssert.AreEqual(expected.ToArray(), actual.ToArray());

View File

@ -92,14 +92,12 @@ public static class SpanExtensions
} }
// dotcover disable // dotcover disable
//NOSONAR
default: default:
#if NET7_0_OR_GREATER #if NET7_0_OR_GREATER
throw new UnreachableException(string.Format(ExceptionMessages.EnumSizeIsUnexpected, Unsafe.SizeOf<T>())); throw new UnreachableException(string.Format(ExceptionMessages.EnumSizeIsUnexpected, Unsafe.SizeOf<T>()));
#else #else
throw new ArgumentException(string.Format(ExceptionMessages.EnumSizeIsUnexpected, Unsafe.SizeOf<T>())); throw new ArgumentException(string.Format(ExceptionMessages.EnumSizeIsUnexpected, Unsafe.SizeOf<T>()));
#endif #endif
//NOSONAR
// dotcover enable // dotcover enable
} }
} }

View File

@ -1,4 +1,3 @@
using System.Diagnostics;
using System.Diagnostics.Contracts; using System.Diagnostics.Contracts;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -13,11 +12,11 @@ public static class DecimalExtensions
/// Converts the current decimal number into an array of bytes, as little endian. /// Converts the current decimal number into an array of bytes, as little endian.
/// </summary> /// </summary>
/// <param name="value">The <see cref="int" /> value.</param> /// <param name="value">The <see cref="int" /> value.</param>
/// <returns>An array of bytes with length 4.</returns> /// <returns>An array of bytes with length 16.</returns>
[Pure] [Pure]
public static byte[] GetBigEndianBytes(this decimal value) public static byte[] GetBigEndianBytes(this decimal value)
{ {
Span<byte> buffer = stackalloc byte[4]; Span<byte> buffer = stackalloc byte[16];
value.TryWriteBigEndianBytes(buffer); value.TryWriteBigEndianBytes(buffer);
return buffer.ToArray(); return buffer.ToArray();
} }
@ -26,11 +25,11 @@ public static class DecimalExtensions
/// Converts the current decimal number into an array of bytes, as little endian. /// Converts the current decimal number into an array of bytes, as little endian.
/// </summary> /// </summary>
/// <param name="value">The <see cref="int" /> value.</param> /// <param name="value">The <see cref="int" /> value.</param>
/// <returns>An array of bytes with length 4.</returns> /// <returns>An array of bytes with length 16.</returns>
[Pure] [Pure]
public static byte[] GetLittleEndianBytes(this decimal value) public static byte[] GetLittleEndianBytes(this decimal value)
{ {
Span<byte> buffer = stackalloc byte[4]; Span<byte> buffer = stackalloc byte[16];
value.TryWriteLittleEndianBytes(buffer); value.TryWriteLittleEndianBytes(buffer);
return buffer.ToArray(); return buffer.ToArray();
} }
@ -44,23 +43,17 @@ public static class DecimalExtensions
public static bool TryWriteBigEndianBytes(this decimal value, Span<byte> destination) public static bool TryWriteBigEndianBytes(this decimal value, Span<byte> destination)
{ {
Span<int> buffer = stackalloc int[4]; Span<int> buffer = stackalloc int[4];
GetBits(value, buffer); decimal.GetBits(value, buffer);
if (buffer[0].TryWriteBigEndianBytes(destination[..4]) && Span<byte> result = stackalloc byte[16];
buffer[1].TryWriteBigEndianBytes(destination[4..8]) && MemoryMarshal.Cast<int, byte>(buffer).CopyTo(result);
buffer[2].TryWriteBigEndianBytes(destination[8..12]) &&
buffer[3].TryWriteBigEndianBytes(destination[12..])) if (BitConverter.IsLittleEndian)
{ {
if (BitConverter.IsLittleEndian) result.Reverse();
{
destination.Reverse();
}
return true;
} }
destination.Clear(); return result.TryCopyTo(destination);
return false;
} }
/// <summary> /// <summary>
@ -72,44 +65,16 @@ public static class DecimalExtensions
public static bool TryWriteLittleEndianBytes(this decimal value, Span<byte> destination) public static bool TryWriteLittleEndianBytes(this decimal value, Span<byte> destination)
{ {
Span<int> buffer = stackalloc int[4]; Span<int> buffer = stackalloc int[4];
GetBits(value, buffer); decimal.GetBits(value, buffer);
if (buffer[0].TryWriteLittleEndianBytes(destination[..4]) && Span<byte> result = stackalloc byte[16];
buffer[1].TryWriteLittleEndianBytes(destination[4..8]) && MemoryMarshal.Cast<int, byte>(buffer).CopyTo(result);
buffer[2].TryWriteLittleEndianBytes(destination[8..12]) &&
buffer[3].TryWriteLittleEndianBytes(destination[12..])) if (!BitConverter.IsLittleEndian)
{ {
if (!BitConverter.IsLittleEndian) result.Reverse();
{
destination.Reverse();
}
return true;
} }
destination.Clear(); return result.TryCopyTo(destination);
return false;
} }
private static void GetBits(decimal value, Span<int> destination)
{
_ = decimal.GetBits(value, destination);
}
#if !NET5_0_OR_GREATER
private static void WriteBits(Span<int> destination, Span<byte> buffer)
{
var flags = MemoryMarshal.Read<int>(buffer[..4]);
var hi = MemoryMarshal.Read<int>(buffer[4..8]);
var lo = MemoryMarshal.Read<long>(buffer[8..]);
var low = (uint)lo;
var mid = (uint)(lo >> 32);
destination[0] = (int)low;
destination[1] = (int)mid;
destination[2] = hi;
destination[3] = flags;
}
#endif
} }

View File

@ -98,7 +98,6 @@ public static class RuneExtensions
} }
// dotcover disable // dotcover disable
//NOSONAR
default: default:
string exceptionFormat = ExceptionMessages.UnexpectedRuneUtf8SequenceLength; string exceptionFormat = ExceptionMessages.UnexpectedRuneUtf8SequenceLength;
string message = string.Format(CultureInfo.CurrentCulture, exceptionFormat, length); string message = string.Format(CultureInfo.CurrentCulture, exceptionFormat, length);
@ -107,7 +106,6 @@ public static class RuneExtensions
#else #else
throw new InvalidOperationException(message); throw new InvalidOperationException(message);
#endif #endif
//NOSONAR
// dotcover enable // dotcover enable
} }
} }