Skip to content

Commit

Permalink
Adds support for custom serialization and instantiation of objects sp…
Browse files Browse the repository at this point in the history
…ecified by open generic types.
  • Loading branch information
dbolin committed Nov 27, 2023
1 parent 2484274 commit 43400bd
Show file tree
Hide file tree
Showing 10 changed files with 412 additions and 141 deletions.
2 changes: 1 addition & 1 deletion Apex.Serialization/Apex.Serialization.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<TargetFrameworks>net8</TargetFrameworks>
<Version>5.0.0</Version>
<Version>5.0.1</Version>
<Authors>Dominic Bolin</Authors>
<Description>A high performance contract-less binary serializer</Description>
<PackageProjectUrl>https://github.com/dbolin/Apex.Serialization</PackageProjectUrl>
Expand Down
19 changes: 12 additions & 7 deletions Apex.Serialization/Binary.Factory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,19 @@ public static class Binary
{
internal class CustomSerializerDelegate : IEquatable<CustomSerializerDelegate>
{
public readonly Delegate Action;
public readonly MethodInfo InvokeMethodInfo;
public readonly Delegate? Action;
public readonly MethodInfo? MethodInfo;
public readonly Type? CustomContextType;

public CustomSerializerDelegate(Delegate action, MethodInfo invokeMethodInfo, Type? customContextType)
public CustomSerializerDelegate(Delegate action, Type? customContextType)
{
Action = action;
InvokeMethodInfo = invokeMethodInfo;
CustomContextType = customContextType;
}

public CustomSerializerDelegate(MethodInfo methodInfo, Type? customContextType)
{
MethodInfo = methodInfo;
CustomContextType = customContextType;
}

Expand All @@ -29,14 +34,14 @@ public override bool Equals(object? obj)
public bool Equals(CustomSerializerDelegate? other)
{
return other != null &&
EqualityComparer<Delegate>.Default.Equals(Action, other.Action) &&
EqualityComparer<MethodInfo>.Default.Equals(InvokeMethodInfo, other.InvokeMethodInfo) &&
EqualityComparer<Delegate?>.Default.Equals(Action, other.Action) &&
EqualityComparer<MethodInfo?>.Default.Equals(MethodInfo, other.MethodInfo) &&
EqualityComparer<Type?>.Default.Equals(CustomContextType, other.CustomContextType);
}

public override int GetHashCode()
{
return HashCode.Combine(Action, InvokeMethodInfo, CustomContextType);
return HashCode.Combine(Action, CustomContextType);
}
}

Expand Down
20 changes: 20 additions & 0 deletions Apex.Serialization/Binary.Internal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,16 @@ internal T ReadSealedInternal<T>(bool useSerializedVersionId)
return method(ref _stream, this);
}

private void DisallowReadingObjectReference()
{
_allowReadingObjectReference = false;
}

private void AllowReadingObjectReference()
{
_allowReadingObjectReference = true;
}

private bool ReadObjectRefHeader<T>(bool checkSerializedVersionId, out T result)
{
result = default!;
Expand All @@ -186,6 +196,8 @@ private bool ReadObjectRefHeader<T>(bool checkSerializedVersionId, out T result)

if (Settings.SerializationMode == Mode.Graph)
{
CheckReadingObjectReference();

var refNo = _stream.Read<int>();
if (refNo != -1)
{
Expand All @@ -199,6 +211,14 @@ private bool ReadObjectRefHeader<T>(bool checkSerializedVersionId, out T result)
return false;
}

private void CheckReadingObjectReference()
{
if (!_allowReadingObjectReference)
{
throw new InvalidOperationException("Unable to read an object reference in graph mode during custom instantiation");
}
}

internal bool WriteObjectRef(object value)
{
ref var index = ref _savedObjectLookup!.GetOrAddValueRef(value);
Expand Down
2 changes: 2 additions & 0 deletions Apex.Serialization/Binary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ internal sealed partial class Binary<TStream, TSettingGen> : ISerializer, IBinar
private readonly IBinaryReader _binaryReader;

private object _customContext;
private bool _allowReadingObjectReference = true;

#pragma warning disable CS8618 // Non-nullable field is uninitialized.
internal Binary(ImmutableSettings settings, TStream stream)
Expand Down Expand Up @@ -128,6 +129,7 @@ public T Read<T>(Stream inputStream)

if (Settings.SerializationMode == Mode.Graph)
{
_allowReadingObjectReference = true;
_loadedObjectRefs.Clear();
if (_internedObjects.Count > 0)
{
Expand Down
1 change: 1 addition & 0 deletions Apex.Serialization/Internal/DynamicCode.Arrays.cs
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ private static Expression ReadArrayGeneral(ParameterExpression output, Expressio
{
var refIndex = Expression.Variable(typeof(int), "refIndex");
readValue = Expression.Block(
Expression.Call(output, CheckReadingObjectReference),
ReserveConstantSize(stream, 5),
Expression.IfThenElse(
Expression.Equal(Expression.Call(stream, BinaryStreamMethods<TStream>.GenericMethods<byte>.ReadValueMethodInfo), Expression.Constant((byte)0)),
Expand Down
9 changes: 9 additions & 0 deletions Apex.Serialization/Internal/DynamicCode.Helpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,15 @@ internal static bool IsBlittable(Type elementType)
private static readonly MethodInfo CustomContextGetter =
typeof(TBinary).GetMethod("GetCustomContext", InstanceFlags)!;

private static readonly MethodInfo DisallowReadingObjectReference =
typeof(TBinary).GetMethod("DisallowReadingObjectReference", InstanceFlags)!;

private static readonly MethodInfo AllowReadingObjectReference =
typeof(TBinary).GetMethod("AllowReadingObjectReference", InstanceFlags)!;

private static readonly MethodInfo CheckReadingObjectReference =
typeof(TBinary).GetMethod("CheckReadingObjectReference", InstanceFlags)!;

private static readonly MethodInfo CheckSerializedVersionUniqueIdMethod =
typeof(TBinary).GetMethod("CheckSerializedVersionUniqueId", InstanceFlags, new Type[] { })!;
private static readonly MethodInfo WriteSerializedVersionUniqueIdMethod =
Expand Down
Loading

0 comments on commit 43400bd

Please sign in to comment.