1
0
mirror of https://github.com/oliverbooth/X10D synced 2024-11-22 14:48:47 +00:00

fix: fix order of bytes in decimal write bytes methods

This commit is contained in:
Oliver Booth 2024-06-12 11:57:27 +01:00
parent e5e27c0afd
commit 68197ef5c7
Signed by: oliverbooth
GPG Key ID: E60B570D1B7557B5
4 changed files with 75 additions and 54 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

@ -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

@ -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);
Span<byte> result = stackalloc byte[16];
MemoryMarshal.Cast<int, byte>(buffer).CopyTo(result);
if (buffer[0].TryWriteBigEndianBytes(destination[..4]) &&
buffer[1].TryWriteBigEndianBytes(destination[4..8]) &&
buffer[2].TryWriteBigEndianBytes(destination[8..12]) &&
buffer[3].TryWriteBigEndianBytes(destination[12..]))
{
if (BitConverter.IsLittleEndian) if (BitConverter.IsLittleEndian)
{ {
destination.Reverse(); result.Reverse();
} }
return true; return result.TryCopyTo(destination);
}
destination.Clear();
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);
Span<byte> result = stackalloc byte[16];
MemoryMarshal.Cast<int, byte>(buffer).CopyTo(result);
if (buffer[0].TryWriteLittleEndianBytes(destination[..4]) &&
buffer[1].TryWriteLittleEndianBytes(destination[4..8]) &&
buffer[2].TryWriteLittleEndianBytes(destination[8..12]) &&
buffer[3].TryWriteLittleEndianBytes(destination[12..]))
{
if (!BitConverter.IsLittleEndian) if (!BitConverter.IsLittleEndian)
{ {
destination.Reverse(); result.Reverse();
} }
return true; return result.TryCopyTo(destination);
} }
destination.Clear();
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
} }