Skip to content

Commit acf8c66

Browse files
committed
Support for mutable structures as BufferWriter.
1 parent ca28202 commit acf8c66

File tree

2 files changed

+70
-9
lines changed

2 files changed

+70
-9
lines changed

src/MemoryPack.Core/MemoryPackSerializer.Serialize.cs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -92,11 +92,12 @@ public static unsafe void Serialize<T, TBufferWriter>(in TBufferWriter bufferWri
9292
where TBufferWriter : class, IBufferWriter<byte>
9393
#endif
9494
{
95+
ref var bufferWriterRef = ref Unsafe.AsRef(in bufferWriter);
9596
if (!RuntimeHelpers.IsReferenceOrContainsReferences<T>())
9697
{
97-
var buffer = bufferWriter.GetSpan(Unsafe.SizeOf<T>());
98+
var buffer = bufferWriterRef.GetSpan(Unsafe.SizeOf<T>());
9899
Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(buffer), value);
99-
bufferWriter.Advance(Unsafe.SizeOf<T>());
100+
bufferWriterRef.Advance(Unsafe.SizeOf<T>());
100101
return;
101102
}
102103
#if NET7_0_OR_GREATER
@@ -105,29 +106,30 @@ public static unsafe void Serialize<T, TBufferWriter>(in TBufferWriter bufferWri
105106
{
106107
if (value == null)
107108
{
108-
var span = bufferWriter.GetSpan(4);
109+
var span = bufferWriterRef.GetSpan(4);
109110
MemoryPackCode.NullCollectionData.CopyTo(span);
110-
bufferWriter.Advance(4);
111+
bufferWriterRef.Advance(4);
111112
return;
112113
}
113114

114115
var srcArray = ((Array)(object)value!);
115116
var length = srcArray.Length;
116117
if (length == 0)
117118
{
118-
var span = bufferWriter.GetSpan(4);
119+
var span = bufferWriterRef.GetSpan(4);
119120
MemoryPackCode.ZeroCollectionData.CopyTo(span);
120-
bufferWriter.Advance(4);
121+
bufferWriterRef.Advance(4);
121122
return;
122123
}
124+
123125
var dataSize = elementSize * length;
124-
var destSpan = bufferWriter.GetSpan(dataSize + 4);
126+
var destSpan = bufferWriterRef.GetSpan(dataSize + 4);
125127
ref var head = ref MemoryMarshal.GetReference(destSpan);
126128

127129
Unsafe.WriteUnaligned(ref head, length);
128130
Unsafe.CopyBlockUnaligned(ref Unsafe.Add(ref head, 4), ref MemoryMarshal.GetArrayDataReference(srcArray), (uint)dataSize);
129131

130-
bufferWriter.Advance(dataSize + 4);
132+
bufferWriterRef.Advance(dataSize + 4);
131133
return;
132134
}
133135
#endif
@@ -141,7 +143,7 @@ public static unsafe void Serialize<T, TBufferWriter>(in TBufferWriter bufferWri
141143

142144
try
143145
{
144-
var writer = new MemoryPackWriter<TBufferWriter>(ref Unsafe.AsRef(in bufferWriter), state);
146+
var writer = new MemoryPackWriter<TBufferWriter>(ref bufferWriterRef, state);
145147
Serialize(ref writer, value);
146148
}
147149
finally
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
using System;
2+
using System.Buffers;
3+
using MemoryPack.Tests.Models;
4+
5+
namespace MemoryPack.Tests;
6+
7+
public class SerializerStructBufferWriterTest
8+
{
9+
[Fact]
10+
public void Serialize_ShouldSupportStructAsBufferWriter_WhenValueIsNotReferenceAndNotContainsReferences()
11+
{
12+
var writer = new TestBufferWriter();
13+
MemoryPackSerializer.Serialize(writer, 16);
14+
Assert.Equal(4, writer.WrittenSize);
15+
}
16+
17+
[Fact]
18+
public void Serialize_ShouldSupportStructAsBufferWriter_WhenValueIsUnmanagedSZArray()
19+
{
20+
var writer = new TestBufferWriter();
21+
MemoryPackSerializer.Serialize(writer, new UnmanagedStruct[] { new() { X = 1, Y = 2, Z = 3 } });
22+
Assert.Equal(16, writer.WrittenSize);
23+
}
24+
25+
[Fact]
26+
public void Serialize_ShouldSupportStructAsBufferWriter_WhenFormatterRequired()
27+
{
28+
var writer = new TestBufferWriter();
29+
MemoryPackSerializer.Serialize(writer, new TestData(1));
30+
Assert.Equal(5, writer.WrittenSize);
31+
}
32+
}
33+
34+
[MemoryPackable]
35+
public partial record TestData(int A);
36+
37+
public struct TestBufferWriter : IBufferWriter<byte>
38+
{
39+
public int WrittenSize = 0;
40+
41+
public TestBufferWriter()
42+
{
43+
}
44+
45+
public void Advance(int count)
46+
{
47+
WrittenSize += count;
48+
}
49+
50+
public Memory<byte> GetMemory(int sizeHint = 0)
51+
{
52+
throw new InvalidOperationException();
53+
}
54+
55+
public Span<byte> GetSpan(int sizeHint = 0)
56+
{
57+
return new byte[sizeHint];
58+
}
59+
}

0 commit comments

Comments
 (0)