diff --git a/src/Backdash.Analyzers/SourceGenerationHelper.cs b/src/Backdash.Analyzers/SourceGenerationHelper.cs
index 33e2dcc8..3841996e 100644
--- a/src/Backdash.Analyzers/SourceGenerationHelper.cs
+++ b/src/Backdash.Analyzers/SourceGenerationHelper.cs
@@ -82,10 +82,11 @@ void BuildValueMember(ClassMember member)
);
reads.Append(tab2);
+
reads.AppendLine(
member.Type is INamedTypeSymbol { EnumUnderlyingType: { } underTypeRead }
- ? $"result.{member.Name} = ({member.Type.Name})binaryReader.Read{underTypeRead.Name}();"
- : $"result.{member.Name} = binaryReader.Read{member.Type.Name}();"
+ ? $"result.{member.Name} = ({member.Type.Name})binaryReader.Read{GetMethodSuffix(underTypeRead)}();"
+ : $"result.{member.Name} = binaryReader.Read{GetMethodSuffix(member.Type)}();"
);
}
}
@@ -145,8 +146,8 @@ void BuildArrayMember(ITypeSymbol itemType, ClassMember member)
reads.Append(tab3);
reads.AppendLine(
itemType is INamedTypeSymbol { EnumUnderlyingType: { } underTypeRead }
- ? $"result.{member.Name}[i] = ({itemType.Name})binaryReader.Read{underTypeRead.Name}();"
- : $"result.{member.Name}[i] = binaryReader.Read{itemType.Name}();"
+ ? $"result.{member.Name}[i] = ({itemType.Name})binaryReader.Read{GetMethodSuffix(underTypeRead)}();"
+ : $"result.{member.Name}[i] = binaryReader.Read{GetMethodSuffix(itemType)}();"
);
}
@@ -158,6 +159,14 @@ void BuildArrayMember(ITypeSymbol itemType, ClassMember member)
}
}
+ static string GetMethodSuffix(ITypeSymbol type)
+ {
+ if (type.Name is "Single")
+ return "Float";
+
+ return type.Name;
+ }
+
static bool IsArrayLike(ITypeSymbol memberType, out ITypeSymbol elementType)
{
elementType = memberType;
diff --git a/src/Backdash/Network/Endianness.cs b/src/Backdash/Network/Endianness.cs
index d046a643..41635560 100644
--- a/src/Backdash/Network/Endianness.cs
+++ b/src/Backdash/Network/Endianness.cs
@@ -1,7 +1,7 @@
namespace Backdash.Network;
///
-/// Defines a endianness value
+/// Defines an endianness value
///
public enum Endianness : byte
{
diff --git a/src/Backdash/Serialization/BinaryBufferReader.cs b/src/Backdash/Serialization/BinaryBufferReader.cs
index e16ae346..92b175ec 100644
--- a/src/Backdash/Serialization/BinaryBufferReader.cs
+++ b/src/Backdash/Serialization/BinaryBufferReader.cs
@@ -196,16 +196,6 @@ public bool ReadBoolean()
///
public Half? ReadNullableHalf() => ReadBoolean() ? ReadHalf() : null;
- ///
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public float ReadSingle() => ReadFloat();
-
- ///
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public float? ReadNullableSingle() => ReadNullableFloat();
-
/// Reads float 32 from the buffer.
public float ReadFloat() => BitConverter.Int32BitsToSingle(ReadInt32());
@@ -353,8 +343,11 @@ public T ReadNumber(bool isUnsigned) where T : unmanaged, IBinaryInteger
}
///
- public void ReadNumber(ref T value, bool isUnsigned) where T : unmanaged, IBinaryInteger =>
- value = ReadNumber(isUnsigned);
+ public void ReadNumber(ref T value, bool isUnsigned) where T : unmanaged, IBinaryInteger
+ {
+ numberSerializer.Read(ref value, CurrentBuffer, isUnsigned, out var written);
+ Advance(written);
+ }
///
public void ReadNumber(ref T? value, bool isUnsigned) where T : unmanaged, IBinaryInteger =>
@@ -595,13 +588,13 @@ public void Read(in StringBuilder values)
public void Read(ref bool? value) => value = ReadNullableBoolean();
///
- public void Read(ref short value) => value = ReadInt16();
+ public void Read(ref short value) => ReadNumber(ref value, false);
///
public void Read(ref short? value) => value = ReadNullableInt16();
///
- public void Read(ref ushort value) => value = ReadUInt16();
+ public void Read(ref ushort value) => ReadNumber(ref value, true);
///
public void Read(ref ushort? value) => value = ReadNullableUInt16();
@@ -613,37 +606,37 @@ public void Read(in StringBuilder values)
public void Read(ref char? value) => value = ReadNullableChar();
///
- public void Read(ref int value) => value = ReadInt32();
+ public void Read(ref int value) => ReadNumber(ref value, false);
///
public void Read(ref int? value) => value = ReadNullableInt32();
///
- public void Read(ref uint value) => value = ReadUInt32();
+ public void Read(ref uint value) => ReadNumber(ref value, true);
///
public void Read(ref uint? value) => value = ReadNullableUInt32();
///
- public void Read(ref long value) => value = ReadInt64();
+ public void Read(ref long value) => ReadNumber(ref value, false);
///
public void Read(ref long? value) => value = ReadNullableInt64();
///
- public void Read(ref ulong value) => value = ReadUInt64();
+ public void Read(ref ulong value) => ReadNumber(ref value, true);
///
public void Read(ref ulong? value) => value = ReadNullableUInt64();
///
- public void Read(ref Int128 value) => value = ReadInt128();
+ public void Read(ref Int128 value) => ReadNumber(ref value, false);
///
public void Read(ref Int128? value) => value = ReadNullableInt128();
///
- public void Read(ref UInt128 value) => value = ReadUInt128();
+ public void Read(ref UInt128 value) => ReadNumber(ref value, true);
///
public void Read(ref UInt128? value) => value = ReadNullableUInt128();
@@ -963,20 +956,25 @@ public T ReadAsByte() where T : unmanaged
///
public void ReadAsByte(ref T value) where T : unmanaged => Read(ref Unsafe.As(ref value));
- ///
- public void ReadAsByte(ref T? value) where T : unmanaged => Read(ref Unsafe.As(ref value));
-
///
public void ReadAsByte(in Span values) where T : unmanaged => Read(MemoryMarshal.Cast(values));
///
public void ReadAsByte(in List values) where T : unmanaged => ReadAsByte(GetListSpan(in values));
+ ///
+ public void ReadAsByte(ref T? value) where T : unmanaged => value = ReadAsNullableByte();
+
///
public T? ReadAsNullableByte() where T : unmanaged
{
- var value = ReadNullableByte();
- return Unsafe.As(ref value);
+ if (ReadBoolean())
+ {
+ var value = ReadByte();
+ return Unsafe.As(ref value);
+ }
+
+ return null;
}
/// Reads a from buffer and reinterprets it as .
@@ -989,22 +987,26 @@ public T ReadAsSByte() where T : unmanaged
///
public void ReadAsSByte(ref T value) where T : unmanaged => Read(ref Unsafe.As(ref value));
- ///
- public void ReadAsSByte(ref T? value) where T : unmanaged => Read(ref Unsafe.As(ref value));
-
///
public void ReadAsSByte(in Span values) where T : unmanaged => Read(MemoryMarshal.Cast(values));
///
public void ReadAsSByte(in List values) where T : unmanaged => ReadAsSByte(GetListSpan(in values));
+ ///
+ public void ReadAsSByte(ref T? value) where T : unmanaged => value = ReadAsNullableSByte();
+
///
public T? ReadAsNullableSByte() where T : unmanaged
{
- var value = ReadNullableSByte();
- return Unsafe.As(ref value);
- }
+ if (ReadBoolean())
+ {
+ var value = ReadSByte();
+ return Unsafe.As(ref value);
+ }
+ return null;
+ }
/// Reads a from buffer and reinterprets it as .
public T ReadAsInt16() where T : unmanaged
@@ -1016,20 +1018,25 @@ public T ReadAsInt16() where T : unmanaged
///
public void ReadAsInt16(ref T value) where T : unmanaged => Read(ref Unsafe.As(ref value));
- ///
- public void ReadAsInt16(ref T? value) where T : unmanaged => Read(ref Unsafe.As(ref value));
-
///
public void ReadAsInt16(in Span values) where T : unmanaged => Read(MemoryMarshal.Cast(values));
///
public void ReadAsInt16(in List values) where T : unmanaged => ReadAsInt16(GetListSpan(in values));
+ ///
+ public void ReadAsInt16(ref T? value) where T : unmanaged => value = ReadAsNullableInt16();
+
///
public T? ReadAsNullableInt16() where T : unmanaged
{
- var value = ReadNullableInt16();
- return Unsafe.As(ref value);
+ if (ReadBoolean())
+ {
+ var value = ReadInt16();
+ return Unsafe.As(ref value);
+ }
+
+ return null;
}
/// Reads a from buffer and reinterprets it as .
@@ -1042,20 +1049,25 @@ public T ReadAsUInt16() where T : unmanaged
///
public void ReadAsUInt16(ref T value) where T : unmanaged => Read(ref Unsafe.As(ref value));
- ///
- public void ReadAsUInt16(ref T? value) where T : unmanaged => Read(ref Unsafe.As(ref value));
-
///
public void ReadAsUInt16(in Span values) where T : unmanaged => Read(MemoryMarshal.Cast(values));
///
public void ReadAsUInt16(in List values) where T : unmanaged => ReadAsUInt16(GetListSpan(in values));
+ ///
+ public void ReadAsUInt16(ref T? value) where T : unmanaged => value = ReadAsNullableUInt16();
+
///
public T? ReadAsNullableUInt16() where T : unmanaged
{
- var value = ReadNullableUInt16();
- return Unsafe.As(ref value);
+ if (ReadBoolean())
+ {
+ var value = ReadUInt16();
+ return Unsafe.As(ref value);
+ }
+
+ return null;
}
/// Reads a from buffer and reinterprets it as .
@@ -1068,20 +1080,25 @@ public T ReadAsInt32() where T : unmanaged
///
public void ReadAsInt32(ref T value) where T : unmanaged => Read(ref Unsafe.As(ref value));
- ///
- public void ReadAsInt32(ref T? value) where T : unmanaged => Read(ref Unsafe.As(ref value));
-
///
public void ReadAsInt32(in Span values) where T : unmanaged => Read(MemoryMarshal.Cast(values));
///
public void ReadAsInt32(in List values) where T : unmanaged => ReadAsInt32(GetListSpan(in values));
+ ///
+ public void ReadAsInt32(ref T? value) where T : unmanaged => value = ReadAsNullableInt32();
+
///
public T? ReadAsNullableInt32() where T : unmanaged
{
- var value = ReadNullableInt32();
- return Unsafe.As(ref value);
+ if (ReadBoolean())
+ {
+ var value = ReadInt32();
+ return Unsafe.As(ref value);
+ }
+
+ return null;
}
/// Reads a from buffer and reinterprets it as .
@@ -1094,20 +1111,25 @@ public T ReadAsUInt32() where T : unmanaged
///
public void ReadAsUInt32(ref T value) where T : unmanaged => Read(ref Unsafe.As(ref value));
- ///
- public void ReadAsUInt32(ref T? value) where T : unmanaged => Read(ref Unsafe.As(ref value));
-
///
public void ReadAsUInt32(in Span values) where T : unmanaged => Read(MemoryMarshal.Cast(values));
///
public void ReadAsUInt32(in List values) where T : unmanaged => ReadAsUInt32(GetListSpan(in values));
+ ///
+ public void ReadAsUInt32(ref T? value) where T : unmanaged => value = ReadAsNullableUInt32();
+
///
public T? ReadAsNullableUInt32() where T : unmanaged
{
- var value = ReadNullableUInt32();
- return Unsafe.As(ref value);
+ if (ReadBoolean())
+ {
+ var value = ReadUInt32();
+ return Unsafe.As(ref value);
+ }
+
+ return null;
}
/// Reads a from buffer and reinterpret it as .
@@ -1120,20 +1142,25 @@ public T ReadAsInt64() where T : unmanaged
///
public void ReadAsInt64(ref T value) where T : unmanaged => Read(ref Unsafe.As(ref value));
- ///
- public void ReadAsInt64(ref T? value) where T : unmanaged => Read(ref Unsafe.As(ref value));
-
///
public void ReadAsInt64(in Span values) where T : unmanaged => Read(MemoryMarshal.Cast(values));
///
public void ReadAsInt64(in List values) where T : unmanaged => ReadAsInt64(GetListSpan(in values));
+ ///
+ public void ReadAsInt64(ref T? value) where T : unmanaged => value = ReadAsNullableInt64();
+
///
public T? ReadAsNullableInt64() where T : unmanaged
{
- var value = ReadNullableInt64();
- return Unsafe.As(ref value);
+ if (ReadBoolean())
+ {
+ var value = ReadInt64();
+ return Unsafe.As(ref value);
+ }
+
+ return null;
}
/// Reads a from buffer and reinterprets it as .
@@ -1146,20 +1173,25 @@ public T ReadAsUInt64() where T : unmanaged
///
public void ReadAsUInt64(ref T value) where T : unmanaged => Read(ref Unsafe.As(ref value));
- ///
- public void ReadAsUInt64(ref T? value) where T : unmanaged => Read(ref Unsafe.As(ref value));
-
///
public void ReadAsUInt64(in Span values) where T : unmanaged => Read(MemoryMarshal.Cast(values));
///
public void ReadAsUInt64(in List values) where T : unmanaged => ReadAsUInt64(GetListSpan(in values));
+ ///
+ public void ReadAsUInt64(ref T? value) where T : unmanaged => value = ReadAsNullableUInt64();
+
///
public T? ReadAsNullableUInt64() where T : unmanaged
{
- var value = ReadNullableUInt64();
- return Unsafe.As(ref value);
+ if (ReadBoolean())
+ {
+ var value = ReadUInt64();
+ return Unsafe.As(ref value);
+ }
+
+ return null;
}
/// Reads a from buffer and reinterpret it as .
@@ -1172,20 +1204,26 @@ public T ReadAsInt128() where T : unmanaged
///
public void ReadAsInt128(ref T value) where T : unmanaged => Read(ref Unsafe.As(ref value));
- ///
- public void ReadAsInt128(ref T? value) where T : unmanaged => Read(ref Unsafe.As(ref value));
-
///
public void ReadAsInt128(in Span values) where T : unmanaged => Read(MemoryMarshal.Cast(values));
///
public void ReadAsInt128(in List values) where T : unmanaged => ReadAsInt128(GetListSpan(in values));
+
+ ///
+ public void ReadAsInt128(ref T? value) where T : unmanaged => value = ReadAsNullableInt128();
+
///
public T? ReadAsNullableInt128() where T : unmanaged
{
- var value = ReadNullableInt128();
- return Unsafe.As(ref value);
+ if (ReadBoolean())
+ {
+ var value = ReadInt128();
+ return Unsafe.As(ref value);
+ }
+
+ return null;
}
/// Reads a from buffer and reinterprets it as .
@@ -1198,19 +1236,24 @@ public T ReadAsUInt128() where T : unmanaged
///
public void ReadAsUInt128(ref T value) where T : unmanaged => Read(ref Unsafe.As(ref value));
- ///
- public void ReadAsUInt128(ref T? value) where T : unmanaged => Read(ref Unsafe.As(ref value));
-
///
public void ReadAsUInt128(in Span values) where T : unmanaged => Read(MemoryMarshal.Cast(values));
///
public void ReadAsUInt128(in List values) where T : unmanaged => ReadAsUInt128(GetListSpan(in values));
+ ///
+ public void ReadAsUInt128(ref T? value) where T : unmanaged => value = ReadAsNullableUInt128();
+
///
public T? ReadAsNullableUInt128() where T : unmanaged
{
- var value = ReadNullableUInt128();
- return Unsafe.As(ref value);
+ if (ReadBoolean())
+ {
+ var value = ReadUInt128();
+ return Unsafe.As(ref value);
+ }
+
+ return null;
}
}
diff --git a/src/Backdash/Serialization/Internal/EndiannessSerializer.cs b/src/Backdash/Serialization/Internal/EndiannessSerializer.cs
index bceff106..5b29c246 100644
--- a/src/Backdash/Serialization/Internal/EndiannessSerializer.cs
+++ b/src/Backdash/Serialization/Internal/EndiannessSerializer.cs
@@ -36,6 +36,14 @@ public T Read(ReadOnlySpan buffer, bool isUnsigned, out int bytesRead)
return T.ReadBigEndian(buffer[..bytesRead], isUnsigned);
}
+ public void Read(ref T value, ReadOnlySpan buffer, bool isUnsigned, out int bytesRead)
+ where T : unmanaged, IBinaryInteger
+ {
+ bytesRead = Unsafe.SizeOf();
+ if (!T.TryReadBigEndian(buffer[..bytesRead], isUnsigned, out value))
+ throw new OverflowException();
+ }
+
public bool Write(Span buffer, T value, out int size)
where T : unmanaged, IBinaryInteger
{
@@ -67,6 +75,14 @@ public T Read(ReadOnlySpan buffer, bool isUnsigned, out int bytesRead)
return T.ReadLittleEndian(buffer[..bytesRead], isUnsigned);
}
+ public void Read(ref T value, ReadOnlySpan buffer, bool isUnsigned, out int bytesRead)
+ where T : unmanaged, IBinaryInteger
+ {
+ bytesRead = Unsafe.SizeOf();
+ if (!T.TryReadLittleEndian(buffer[..bytesRead], isUnsigned, out value))
+ throw new OverflowException();
+ }
+
public bool Write(Span buffer, T value, out int size)
where T : unmanaged, IBinaryInteger
{
@@ -112,6 +128,10 @@ int Write(ArrayBufferWriter buffer, T value) where T : unmanaged, IBina
/// Reads number from the buffer
T Read(ReadOnlySpan buffer, bool isUnsigned, out int bytesRead) where T : unmanaged, IBinaryInteger;
+ /// Reads number from the buffer
+ void Read(ref T value, ReadOnlySpan buffer, bool isUnsigned, out int bytesRead)
+ where T : unmanaged, IBinaryInteger;
+
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
T Read(in ReadOnlySpan buffer, out int bytesRead)
diff --git a/tests/Backdash.Tests/Specs/Unit/Serialization/BinaryBufferReadWriteNullableValues.cs b/tests/Backdash.Tests/Specs/Unit/Serialization/BinaryBufferReadWriteNullableValues.cs
index 85ccac93..13c5024e 100644
--- a/tests/Backdash.Tests/Specs/Unit/Serialization/BinaryBufferReadWriteNullableValues.cs
+++ b/tests/Backdash.Tests/Specs/Unit/Serialization/BinaryBufferReadWriteNullableValues.cs
@@ -873,6 +873,25 @@ public bool TestUInt128(UInt128Enum? value, UInt128Enum? read, Endianness endian
return value == read;
}
+
+ [PropertyTest]
+ public void TestBagInt64Ref(Bag.S8? value, Bag.S8? read, Endianness endianness)
+ {
+ var size = Setup(value, endianness, out var writer);
+ writer.WriteAsInt64(in value);
+
+ var reader = GetReader(writer);
+ reader.ReadAsInt64(ref read);
+ reader.ReadCount.Should().Be(size);
+
+ ResetRead();
+ Bag.S8? otherRead = null;
+ reader.ReadAsInt64(ref otherRead);
+ reader.ReadCount.Should().Be(size);
+ otherRead.Should().Be(read);
+
+ value.Should().BeEquivalentTo(read);
+ }
}
public static int Setup(T? value, Endianness endianness, out BinaryBufferWriter writer) where T : unmanaged
diff --git a/tests/Backdash.Tests/TestUtils/Types/TestData.cs b/tests/Backdash.Tests/TestUtils/Types/TestData.cs
index 8a428cdb..3280cca7 100644
--- a/tests/Backdash.Tests/TestUtils/Types/TestData.cs
+++ b/tests/Backdash.Tests/TestUtils/Types/TestData.cs
@@ -371,3 +371,8 @@ public enum Int64Enum : long
public record struct Int128Enum(Int128 Value);
public record struct UInt128Enum(UInt128 Value);
+
+public static class Bag
+{
+ public record struct S8(int A, int B);
+}