Skip to content

Commit 769ec1b

Browse files
committed
Add MemoryPackReader. PeekIsNull,
TryPeekObjectHeader, TryPeekUnionHeader, TryPeekCollectionHeader
1 parent 9390e11 commit 769ec1b

File tree

4 files changed

+173
-4
lines changed

4 files changed

+173
-4
lines changed

README.md

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -940,19 +940,31 @@ public readonly partial struct SerializableAnimationCurve
940940

941941
The type to wrap is public, but excluded from serialization (`MemoryPackIgnore`). The properties you want to serialize are private, but included (`MemoryPackInclude`). Two patterns of constructors should also be prepared. The constructor used by the serializer should be private.
942942

943-
As it is, it must be wrapped every time, which is inconvenient. Let's create a custom formatter.
943+
As it is, it must be wrapped every time, which is inconvenient. And also strcut wrapper can not represents null. So let's create a custom formatter.
944944

945945
```csharp
946946
public class AnimationCurveFormatter : MemoryPackFormatter<AnimationCurve>
947947
{
948948
// Unity does not support scoped and TBufferWriter so change signature to `Serialize(ref MemoryPackWriter writer, ref AnimationCurve value)`
949-
public override void Serialize<TBufferWriter>(ref MemoryPackWriter<TBufferWriter> writer, scoped ref AnimationCurve value)
949+
public override void Serialize<TBufferWriter>(ref MemoryPackWriter<TBufferWriter> writer, scoped ref AnimationCurve? value)
950950
{
951+
if (value == null)
952+
{
953+
writer.WriteNullObjectHeader();
954+
return;
955+
}
956+
951957
writer.WritePackable(new SerializableAnimationCurve(value));
952958
}
953959

954-
public override void Deserialize(ref MemoryPackReader reader, scoped ref AnimationCurve value)
960+
public override void Deserialize(ref MemoryPackReader reader, scoped ref AnimationCurve? value)
955961
{
962+
if (reader.PeekIsNull())
963+
{
964+
value = null;
965+
return;
966+
}
967+
956968
var wrapped = reader.ReadPackable<SerializableAnimationCurve>();
957969
value = wrapped.AnimationCurve;
958970
}

src/MemoryPack.Core/MemoryPackReader.cs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,55 @@ public bool TryReadCollectionHeader(out int length)
294294
return length != MemoryPackCode.NullCollection;
295295
}
296296

297+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
298+
public bool PeekIsNull()
299+
{
300+
return TryPeekObjectHeader(out _);
301+
}
302+
303+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
304+
public bool TryPeekObjectHeader(out byte memberCount)
305+
{
306+
memberCount = GetSpanReference(1);
307+
return memberCount != MemoryPackCode.NullObject;
308+
}
309+
310+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
311+
public bool TryPeekUnionHeader(out ushort tag)
312+
{
313+
var firstTag = GetSpanReference(1);
314+
if (firstTag < MemoryPackCode.WideTag)
315+
{
316+
tag = firstTag;
317+
return true;
318+
}
319+
else if (firstTag == MemoryPackCode.WideTag)
320+
{
321+
ref var spanRef = ref GetSpanReference(sizeof(ushort) + 1); // skip firstTag
322+
tag = Unsafe.ReadUnaligned<ushort>(ref Unsafe.Add(ref spanRef, 1));
323+
return true;
324+
}
325+
else
326+
{
327+
tag = 0;
328+
return false;
329+
}
330+
}
331+
332+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
333+
public bool TryPeekCollectionHeader(out int length)
334+
{
335+
length = Unsafe.ReadUnaligned<int>(ref GetSpanReference(4));
336+
337+
// If collection-length is larger than buffer-length, it is invalid data.
338+
if (Remaining < length)
339+
{
340+
MemoryPackSerializationException.ThrowInsufficientBufferUnless(length);
341+
}
342+
343+
return length != MemoryPackCode.NullCollection;
344+
}
345+
297346
/// <summary>
298347
/// no validate collection size, be careful to use.
299348
/// </summary>

src/MemoryPack.Unity/Assets/Plugins/MemoryPack/Runtime/MemoryPack.Core/MemoryPackReader.cs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,55 @@ public bool TryReadCollectionHeader(out int length)
303303
return length != MemoryPackCode.NullCollection;
304304
}
305305

306+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
307+
public bool PeekIsNull()
308+
{
309+
return TryPeekObjectHeader(out _);
310+
}
311+
312+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
313+
public bool TryPeekObjectHeader(out byte memberCount)
314+
{
315+
memberCount = GetSpanReference(1);
316+
return memberCount != MemoryPackCode.NullObject;
317+
}
318+
319+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
320+
public bool TryPeekUnionHeader(out ushort tag)
321+
{
322+
var firstTag = GetSpanReference(1);
323+
if (firstTag < MemoryPackCode.WideTag)
324+
{
325+
tag = firstTag;
326+
return true;
327+
}
328+
else if (firstTag == MemoryPackCode.WideTag)
329+
{
330+
ref var spanRef = ref GetSpanReference(sizeof(ushort) + 1); // skip firstTag
331+
tag = Unsafe.ReadUnaligned<ushort>(ref Unsafe.Add(ref spanRef, 1));
332+
return true;
333+
}
334+
else
335+
{
336+
tag = 0;
337+
return false;
338+
}
339+
}
340+
341+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
342+
public bool TryPeekCollectionHeader(out int length)
343+
{
344+
length = Unsafe.ReadUnaligned<int>(ref GetSpanReference(4));
345+
346+
// If collection-length is larger than buffer-length, it is invalid data.
347+
if (Remaining < length)
348+
{
349+
MemoryPackSerializationException.ThrowInsufficientBufferUnless(length);
350+
}
351+
352+
return length != MemoryPackCode.NullCollection;
353+
}
354+
306355
/// <summary>
307356
/// no validate collection size, be careful to use.
308357
/// </summary>

src/MemoryPack.Unity/Assets/Scripts/SampleOne.cs

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
using MemoryPack;
1+
#nullable disable
2+
3+
using MemoryPack;
24
using System.Collections;
35
using System.Collections.Generic;
46
using UnityEngine;
@@ -20,3 +22,60 @@ public partial class MyPerson
2022
public int Age { get; set; }
2123
public string Name { get; set; }
2224
}
25+
26+
#nullable enable
27+
28+
[MemoryPackable]
29+
public readonly partial struct SerializableAnimationCurve
30+
{
31+
[MemoryPackIgnore]
32+
public readonly AnimationCurve AnimationCurve;
33+
34+
[MemoryPackInclude]
35+
WrapMode preWrapMode => AnimationCurve.preWrapMode;
36+
[MemoryPackInclude]
37+
WrapMode postWrapMode => AnimationCurve.postWrapMode;
38+
[MemoryPackInclude]
39+
Keyframe[] keys => AnimationCurve.keys;
40+
41+
[MemoryPackConstructor]
42+
SerializableAnimationCurve(WrapMode preWrapMode, WrapMode postWrapMode, Keyframe[] keys)
43+
{
44+
var curve = new AnimationCurve(keys);
45+
curve.preWrapMode = preWrapMode;
46+
curve.postWrapMode = postWrapMode;
47+
this.AnimationCurve = curve;
48+
}
49+
50+
public SerializableAnimationCurve(AnimationCurve animationCurve)
51+
{
52+
this.AnimationCurve = animationCurve;
53+
}
54+
}
55+
56+
public class AnimationCurveFormatter : MemoryPackFormatter<AnimationCurve>
57+
{
58+
// Unity does not support scoped and TBufferWriter so change signature to `Serialize(ref MemoryPackWriter writer, ref AnimationCurve value)`
59+
public override void Serialize(ref MemoryPackWriter writer, scoped ref AnimationCurve? value)
60+
{
61+
if (value == null)
62+
{
63+
writer.WriteNullObjectHeader();
64+
return;
65+
}
66+
67+
writer.WritePackable(new SerializableAnimationCurve(value));
68+
}
69+
70+
public override void Deserialize(ref MemoryPackReader reader, scoped ref AnimationCurve? value)
71+
{
72+
if (reader.PeekIsNull())
73+
{
74+
value = null;
75+
return;
76+
}
77+
78+
var wrapped = reader.ReadPackable<SerializableAnimationCurve>();
79+
value = wrapped.AnimationCurve;
80+
}
81+
}

0 commit comments

Comments
 (0)