Skip to content

Commit 9dd5a8c

Browse files
committed
nullable value types serialization
1 parent cfc4940 commit 9dd5a8c

File tree

4 files changed

+689
-34
lines changed

4 files changed

+689
-34
lines changed

src/Backdash/Serialization/BinaryBufferReader.cs

Lines changed: 81 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ public void ReadByte(in Span<byte> values)
8282
/// <summary>Reads a list of <see cref="byte"/> from buffer into <paramref name="values"/>.</summary>
8383
public void ReadByte(in List<byte> values) => ReadByte(GetListSpan(in values));
8484

85+
/// <inheritdoc cref="ReadByte()"/>
86+
public byte? ReadNullableByte() => ReadBoolean() ? ReadByte() : null;
87+
8588
/// <summary>Reads single <see cref="sbyte"/> from buffer.</summary>
8689
public sbyte ReadSByte() => unchecked((sbyte)buffer[offset++]);
8790

@@ -91,6 +94,9 @@ public void ReadByte(in Span<byte> values)
9194
/// <summary>Reads a list of <see cref="sbyte"/> from buffer into <paramref name="values"/>.</summary>
9295
public void ReadSByte(in List<sbyte> values) => ReadSByte(GetListSpan(in values));
9396

97+
/// <inheritdoc cref="ReadSByte()"/>
98+
public sbyte? ReadNullableSByte() => ReadBoolean() ? ReadSByte() : null;
99+
94100
/// <summary>Reads single <see cref="bool"/> from buffer.</summary>
95101
public bool ReadBoolean()
96102
{
@@ -105,6 +111,10 @@ public bool ReadBoolean()
105111
/// <summary>Reads a list of <see cref="bool"/> from buffer into <paramref name="values"/>.</summary>
106112
public void ReadBoolean(in List<bool> values) => ReadBoolean(GetListSpan(in values));
107113

114+
115+
/// <inheritdoc cref="ReadBoolean()"/>
116+
public bool? ReadNullableBoolean() => ReadBoolean() ? ReadBoolean() : null;
117+
108118
/// <summary>Reads single <see cref="short"/> from buffer.</summary>
109119
public short ReadInt16() => ReadNumber<short>(false);
110120

@@ -119,6 +129,9 @@ public void ReadInt16(in Span<short> values)
119129
/// <summary>Reads a list of <see cref="short"/> from buffer into <paramref name="values"/>.</summary>
120130
public void ReadInt16(in List<short> values) => ReadInt16(GetListSpan(in values));
121131

132+
/// <inheritdoc cref="ReadInt16()"/>
133+
public short? ReadNullableInt16() => ReadBoolean() ? ReadInt16() : null;
134+
122135
/// <summary>Reads single <see cref="ushort"/> from buffer.</summary>
123136
public ushort ReadUInt16() => ReadNumber<ushort>(true);
124137

@@ -133,6 +146,9 @@ public void ReadUInt16(in Span<ushort> values)
133146
/// <summary>Reads a list of <see cref="ushort"/> from buffer into <paramref name="values"/>.</summary>
134147
public void ReadUInt16(in List<ushort> values) => ReadUInt16(GetListSpan(in values));
135148

149+
/// <inheritdoc cref="ReadUInt16()"/>
150+
public ushort? ReadNullableUInt16() => ReadBoolean() ? ReadUInt16() : null;
151+
136152
/// <summary>Reads single <see cref="char"/> from buffer.</summary>
137153
public char ReadChar() => (char)ReadUInt16();
138154

@@ -150,6 +166,9 @@ public void ReadChar(in Span<char> values)
150166
/// <summary>Reads a list of <see cref="char"/> from buffer into <paramref name="values"/>.</summary>
151167
public void ReadChar(in List<char> values) => ReadChar(GetListSpan(in values));
152168

169+
/// <inheritdoc cref="ReadChar()"/>
170+
public char? ReadNullableChar() => ReadBoolean() ? ReadChar() : null;
171+
153172
/// <summary>Reads single <see cref="char"/> from buffer.</summary>
154173
public char ReadUtf8Char()
155174
{
@@ -158,6 +177,9 @@ public char ReadUtf8Char()
158177
return result[0];
159178
}
160179

180+
/// <inheritdoc cref="ReadUtf8Char()"/>
181+
public char? ReadNullableUtf8Char() => ReadBoolean() ? ReadUtf8Char() : null;
182+
161183
/// <summary>Reads a span of UTF8 <see cref="char"/> from buffer into <paramref name="values"/>.</summary>
162184
public void ReadUtf8String(in Span<char> values)
163185
{
@@ -183,6 +205,9 @@ public void ReadInt32(in Span<int> values)
183205
/// <summary>Reads a list of <see cref="int"/> from buffer into <paramref name="values"/>.</summary>
184206
public void ReadInt32(in List<int> values) => ReadInt32(GetListSpan(in values));
185207

208+
/// <inheritdoc cref="ReadInt32()"/>
209+
public int? ReadNullableInt32() => ReadBoolean() ? ReadInt32() : null;
210+
186211
/// <summary>Reads single <see cref="uint"/> from buffer.</summary>
187212
public uint ReadUInt32() => ReadNumber<uint>(true);
188213

@@ -197,6 +222,9 @@ public void ReadUInt32(in Span<uint> values)
197222
/// <summary>Reads a list of <see cref="uint"/> from buffer into <paramref name="values"/>.</summary>
198223
public void ReadUInt32(in List<uint> values) => ReadUInt32(GetListSpan(in values));
199224

225+
/// <inheritdoc cref="ReadUInt32()"/>
226+
public uint? ReadNullableUInt32() => ReadBoolean() ? ReadUInt32() : null;
227+
200228
/// <summary>Reads single <see cref="long"/> from buffer.</summary>
201229
public long ReadInt64() => ReadNumber<long>(false);
202230

@@ -211,6 +239,9 @@ public void ReadInt64(in Span<long> values)
211239
/// <summary>Reads a list of <see cref="long"/> from buffer into <paramref name="values"/>.</summary>
212240
public void ReadInt64(in List<long> values) => ReadInt64(GetListSpan(in values));
213241

242+
/// <inheritdoc cref="ReadInt64()"/>
243+
public long? ReadNullableInt64() => ReadBoolean() ? ReadInt64() : null;
244+
214245
/// <summary>Reads single <see cref="ulong"/> from buffer.</summary>
215246
public ulong ReadUInt64() => ReadNumber<ulong>(true);
216247

@@ -225,6 +256,9 @@ public void ReadUInt64(in Span<ulong> values)
225256
/// <summary>Reads a list of <see cref="ulong"/> from buffer into <paramref name="values"/>.</summary>
226257
public void ReadUInt64(in List<ulong> values) => ReadUInt64(GetListSpan(in values));
227258

259+
/// <inheritdoc cref="ReadUInt64()"/>
260+
public ulong? ReadNullableUInt64() => ReadBoolean() ? ReadUInt64() : null;
261+
228262
/// <summary>Reads single <see cref="Int128"/> from buffer.</summary>
229263
public Int128 ReadInt128() => ReadNumber<Int128>(false);
230264

@@ -239,6 +273,9 @@ public void ReadInt128(in Span<Int128> values)
239273
/// <summary>Reads a list of <see cref="Int128"/> from buffer into <paramref name="values"/>.</summary>
240274
public void ReadInt128(in List<Int128> values) => ReadInt128(GetListSpan(in values));
241275

276+
/// <inheritdoc cref="ReadInt128()"/>
277+
public Int128? ReadNullableInt128() => ReadBoolean() ? ReadInt128() : null;
278+
242279
/// <summary>Reads single <see cref="UInt128"/> from buffer.</summary>
243280
public UInt128 ReadUInt128() => ReadNumber<UInt128>(true);
244281

@@ -253,6 +290,8 @@ public void ReadUInt128(in Span<UInt128> values)
253290
/// <summary>Reads a list of <see cref="UInt128"/> from buffer into <paramref name="values"/>.</summary>
254291
public void ReadUInt128(in List<UInt128> values) => ReadUInt128(GetListSpan(in values));
255292

293+
/// <inheritdoc cref="ReadUInt128()"/>
294+
public UInt128? ReadNullableUInt128() => ReadBoolean() ? ReadUInt128() : null;
256295

257296
/// <summary>Reads single <see cref="Half"/> from buffer.</summary>
258297
public Half ReadHalf() => BitConverter.Int16BitsToHalf(ReadInt16());
@@ -263,12 +302,19 @@ public void ReadUInt128(in Span<UInt128> values)
263302
/// <summary>Reads a list of <see cref="Half"/> from buffer into <paramref name="values"/>.</summary>
264303
public void ReadHalf(in List<Half> values) => ReadHalf(GetListSpan(in values));
265304

305+
/// <inheritdoc cref="ReadHalf()"/>
306+
public Half? ReadNullableHalf() => ReadBoolean() ? ReadHalf() : null;
266307

267308
/// <inheritdoc cref="ReadFloat()"/>
268309
/// <seealso cref="ReadFloat()"/>
269310
[MethodImpl(MethodImplOptions.AggressiveInlining)]
270311
public float ReadSingle() => ReadFloat();
271312

313+
/// <inheritdoc cref="ReadNullableFloat()"/>
314+
/// <seealso cref="ReadNullableFloat()"/>
315+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
316+
public float? ReadNullableSingle() => ReadNullableFloat();
317+
272318
/// <summary>Reads float 32 <see cref="float"/> from buffer.</summary>
273319
public float ReadFloat() => BitConverter.Int32BitsToSingle(ReadInt32());
274320

@@ -278,6 +324,8 @@ public void ReadUInt128(in Span<UInt128> values)
278324
/// <summary>Reads a list of <see cref="float"/> from buffer into <paramref name="values"/>.</summary>
279325
public void ReadFloat(in List<float> values) => ReadFloat(GetListSpan(in values));
280326

327+
/// <inheritdoc cref="ReadFloat()"/>
328+
public float? ReadNullableFloat() => ReadBoolean() ? ReadFloat() : null;
281329

282330
/// <summary>Reads single <see cref="double"/> from buffer.</summary>
283331
public double ReadDouble() => BitConverter.Int64BitsToDouble(ReadInt64());
@@ -288,6 +336,9 @@ public void ReadUInt128(in Span<UInt128> values)
288336
/// <summary>Reads a list of <see cref="double"/> from buffer into <paramref name="values"/>.</summary>
289337
public void ReadDouble(in List<double> values) => ReadDouble(GetListSpan(in values));
290338

339+
/// <inheritdoc cref="ReadDouble()"/>
340+
public double? ReadNullableDouble() => ReadBoolean() ? ReadDouble() : null;
341+
291342
/// <summary>Reads single <see cref="Guid"/> from buffer.</summary>
292343
public Guid ReadGuid()
293344
{
@@ -314,6 +365,8 @@ public void ReadGuid(in Span<Guid> values)
314365
/// <summary>Reads a list of <see cref="Guid"/> from buffer into <paramref name="values"/>.</summary>
315366
public void ReadGuid(in List<Guid> values) => ReadGuid(GetListSpan(in values));
316367

368+
/// <inheritdoc cref="ReadGuid()"/>
369+
public Guid? ReadNullableGuid() => ReadBoolean() ? ReadGuid() : null;
317370

318371
/// <summary>Reads single <see cref="TimeSpan"/> from buffer.</summary>
319372
public TimeSpan ReadTimeSpan() => new(ReadInt64());
@@ -328,6 +381,8 @@ public void ReadTimeSpan(in Span<TimeSpan> values)
328381
/// <summary>Reads a list of <see cref="TimeSpan"/> from buffer into <paramref name="values"/>.</summary>
329382
public void ReadTimeSpan(in List<TimeSpan> values) => ReadTimeSpan(GetListSpan(in values));
330383

384+
/// <inheritdoc cref="ReadTimeSpan()"/>
385+
public TimeSpan? ReadNullableTimeSpan() => ReadBoolean() ? ReadTimeSpan() : null;
331386

332387
/// <summary>Reads single <see cref="TimeOnly"/> from buffer.</summary>
333388
public TimeOnly ReadTimeOnly() => new(ReadInt64());
@@ -342,6 +397,9 @@ public void ReadTimeOnly(in Span<TimeOnly> values)
342397
/// <summary>Reads a list of <see cref="TimeOnly"/> from buffer into <paramref name="values"/>.</summary>
343398
public void ReadTimeOnly(in List<TimeOnly> values) => ReadTimeOnly(GetListSpan(in values));
344399

400+
/// <inheritdoc cref="ReadTimeOnly()"/>
401+
public TimeOnly? ReadNullableTimeOnly() => ReadBoolean() ? ReadTimeOnly() : null;
402+
345403
/// <summary>Reads single <see cref="DateTime"/> from buffer.</summary>
346404
public DateTime ReadDateTime()
347405
{
@@ -366,6 +424,9 @@ public void ReadDateTime(in Span<DateTime> values)
366424
/// <summary>Reads a list of <see cref="DateTime"/> from buffer into <paramref name="values"/>.</summary>
367425
public void ReadDateTime(in List<DateTime> values) => ReadDateTime(GetListSpan(in values));
368426

427+
/// <inheritdoc cref="ReadDateTime()"/>
428+
public DateTime? ReadNullableDateTime() => ReadBoolean() ? ReadDateTime() : null;
429+
369430
/// <summary>Reads single <see cref="DateTimeOffset"/> from buffer.</summary>
370431
public DateTimeOffset ReadDateTimeOffset()
371432
{
@@ -390,6 +451,8 @@ public void ReadDateTimeOffset(in Span<DateTimeOffset> values)
390451
/// <summary>Reads a list of <see cref="DateTimeOffset"/> from buffer into <paramref name="values"/>.</summary>
391452
public void ReadDateTimeOffset(in List<DateTimeOffset> values) => ReadDateTimeOffset(GetListSpan(in values));
392453

454+
/// <inheritdoc cref="ReadDateTimeOffset()"/>
455+
public DateTimeOffset? ReadNullableDateTimeOffset() => ReadBoolean() ? ReadDateTimeOffset() : null;
393456

394457
/// <summary>Reads single <see cref="DateOnly"/> from buffer.</summary>
395458
public DateOnly ReadDateOnly() => DateOnly.FromDayNumber(ReadInt32());
@@ -404,6 +467,9 @@ public void ReadDateOnly(in Span<DateOnly> values)
404467
/// <summary>Reads a list of <see cref="DateOnly"/> from buffer into <paramref name="values"/>.</summary>
405468
public void ReadDateOnly(in List<DateOnly> values) => ReadDateOnly(GetListSpan(in values));
406469

470+
/// <inheritdoc cref="ReadDateOnly()"/>
471+
public DateOnly? ReadNullableDateOnly() => ReadBoolean() ? ReadDateOnly() : null;
472+
407473
/// <summary>Reads an unmanaged struct from buffer.</summary>
408474
public void ReadStruct<T>(ref T value) where T : unmanaged
409475
{
@@ -424,36 +490,22 @@ public T ReadStruct<T>() where T : unmanaged
424490
return result;
425491
}
426492

427-
/// <summary>Reads an unmanaged struct list from buffer.</summary>
428-
public void ReadStruct<T>(in List<T> values) where T : unmanaged =>
429-
ReadStruct(GetListSpan(in values));
430-
431493
/// <summary>Reads an unmanaged struct span from buffer.</summary>
432494
public void ReadStruct<T>(in Span<T> values) where T : unmanaged =>
433495
ReadByte(MemoryMarshal.AsBytes(values));
434496

497+
/// <summary>Reads an unmanaged struct list from buffer.</summary>
498+
public void ReadStruct<T>(in List<T> values) where T : unmanaged =>
499+
ReadStruct(GetListSpan(in values));
500+
435501
/// <summary>Reads an unmanaged struct from buffer.</summary>
436502
[MethodImpl(MethodImplOptions.AggressiveInlining)]
437503
public void ReadStruct<T>(in T[] values) where T : unmanaged =>
438504
ReadStruct(values.AsSpan());
439505

440-
/// <summary>Reads an unmanaged struct from buffer.</summary>
441-
public T ReadStructUnsafe<T>() where T : struct
442-
{
443-
var size = Unsafe.SizeOf<T>();
444-
if (size > FreeCapacity) size = FreeCapacity;
445-
var result = Mem.ReadStruct<T>(CurrentBuffer[..size]);
446-
Advance(size);
447-
return result;
448-
}
449-
450-
/// <summary>Reads an unmanaged struct from buffer.</summary>
451-
public void ReadStructUnsafe<T>(in Span<T> values) where T : struct
452-
{
453-
ThrowHelpers.ThrowIfTypeIsReferenceOrContainsReferences<T>();
454-
var valuesBytes = MemoryMarshal.AsBytes(values);
455-
ReadByte(in valuesBytes);
456-
}
506+
/// <inheritdoc cref="ReadStruct{T}()"/>
507+
public T? ReadNullableStruct<T>() where T : unmanaged =>
508+
ReadBoolean() ? ReadStruct<T>() : null;
457509

458510
/// <summary>Reads and allocates an <see cref="string"/> from buffer.</summary>
459511
public string ReadString(int size)
@@ -484,6 +536,14 @@ public T ReadNumber<T>(bool isUnsigned) where T : unmanaged, IBinaryInteger<T>
484536
return result;
485537
}
486538

539+
/// <inheritdoc cref="ReadNumber{T}()"/>
540+
public T? ReadNullableNumber<T>() where T : unmanaged, IBinaryInteger<T>, IMinMaxValue<T> =>
541+
ReadBoolean() ? ReadNumber<T>() : null;
542+
543+
/// <inheritdoc cref="ReadNumber{T}(bool)"/>
544+
public T? ReadNullableNumber<T>(bool isUnsigned) where T : unmanaged, IBinaryInteger<T> =>
545+
ReadBoolean() ? ReadNumber<T>(isUnsigned) : null;
546+
487547
/// <summary>Reads a <see cref="IBinarySerializable"/> <paramref name="value"/> from buffer.</summary>
488548
/// <typeparam name="T">A type that implements <see cref="IBinarySerializable"/>.</typeparam>
489549
public void Read<T>(ref T value) where T : IBinarySerializable => value.Deserialize(in this);

0 commit comments

Comments
 (0)