Refactor AcBinarySerializer to use declared type dispatch
- All serialization APIs now use the declared type (typeof(T) or explicit Type) for dispatch, not value.GetType() - Added non-generic overloads for Serialize, SerializeChunked, and SerializeChunkedFramed with Type parameter for runtime scenarios - ScanForDuplicates accepts optional TypeMetadataWrapper to avoid redundant lookups - Simplified generated writer path and improved wrapper usage - Benchmarks updated to use new API and cache serialized data - Minor cleanups: removed unused usings, improved comments, inlined logic - Ensures consistent, predictable, and more performant type dispatch across all serialization entry points
This commit is contained in:
parent
d4e4c4480a
commit
cf92370bea
|
|
@ -29,6 +29,7 @@ public sealed class AcBinaryBenchmark<T> : ISerializerBenchmark where T : class
|
||||||
_order = order;
|
_order = order;
|
||||||
_options = options;
|
_options = options;
|
||||||
OptionsPreset = optionsPreset;
|
OptionsPreset = optionsPreset;
|
||||||
|
|
||||||
_serialized = AcBinarySerializer.Serialize(order, options);
|
_serialized = AcBinarySerializer.Serialize(order, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -42,6 +43,7 @@ public sealed class AcBinaryBenchmark<T> : ISerializerBenchmark where T : class
|
||||||
{
|
{
|
||||||
var bytes = AcBinarySerializer.Serialize(_order, _options);
|
var bytes = AcBinarySerializer.Serialize(_order, _options);
|
||||||
var roundTripped = AcBinaryDeserializer.Deserialize<T>(bytes, _options);
|
var roundTripped = AcBinaryDeserializer.Deserialize<T>(bytes, _options);
|
||||||
|
|
||||||
return RoundTripValidator.DeepEqualsViaJson(_order, roundTripped);
|
return RoundTripValidator.DeepEqualsViaJson(_order, roundTripped);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ public sealed class AcBinaryBufferWriterBenchmark<T> : ISerializerBenchmark wher
|
||||||
_order = order;
|
_order = order;
|
||||||
_options = options;
|
_options = options;
|
||||||
OptionsPreset = optionsPreset;
|
OptionsPreset = optionsPreset;
|
||||||
|
|
||||||
_serialized = AcBinarySerializer.Serialize(order, options);
|
_serialized = AcBinarySerializer.Serialize(order, options);
|
||||||
|
|
||||||
// Measure ONLY the BufferWriter infrastructure setup on the serialize side (excluding the
|
// Measure ONLY the BufferWriter infrastructure setup on the serialize side (excluding the
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using static AyCode.Core.Helpers.JsonUtilities;
|
|
||||||
|
|
||||||
namespace AyCode.Core.Serializers.Binaries;
|
namespace AyCode.Core.Serializers.Binaries;
|
||||||
|
|
||||||
|
|
@ -18,25 +17,20 @@ public static partial class AcBinarySerializer
|
||||||
/// so no dictionary lookup overhead. SGen types call generated ScanForDuplicates
|
/// so no dictionary lookup overhead. SGen types call generated ScanForDuplicates
|
||||||
/// which bypasses the entire runtime scan path.
|
/// which bypasses the entire runtime scan path.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static void ScanForDuplicates<TOutput>(object value, Type type, BinarySerializationContext<TOutput> context)
|
private static void ScanForDuplicates<TOutput>(object value, Type type, BinarySerializationContext<TOutput> context, TypeMetadataWrapper<BinarySerializeTypeMetadata>? wrapper = null)
|
||||||
where TOutput : struct, IBinaryOutputBase
|
where TOutput : struct, IBinaryOutputBase
|
||||||
{
|
{
|
||||||
if (!context.HasCaching)
|
if (!context.HasCaching) return;
|
||||||
return;
|
|
||||||
|
|
||||||
var wrapper = context.GetWrapper(type);
|
wrapper ??= context.GetWrapper(type);
|
||||||
|
|
||||||
// SGen path: wrapper.GeneratedWriter is cached (no registry lookup per call).
|
// SGen path: wrapper.GeneratedWriter is cached (no registry lookup per call).
|
||||||
// Generated ScanForDuplicates handles HasCaching + ScanObject + SortWritePlan.
|
// Generated ScanForDuplicates handles HasCaching + ScanObject + SortWritePlan.
|
||||||
var genWriter = wrapper.GeneratedWriter;
|
var genWriter = wrapper.GeneratedWriter;
|
||||||
if (genWriter != null && context.Options.UseGeneratedCode)
|
|
||||||
{
|
|
||||||
genWriter.ScanObject(value, context);
|
|
||||||
context.SortWritePlan();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ScanValue(value, wrapper, context);
|
if (genWriter != null && context.Options.UseGeneratedCode) genWriter.ScanObject(value, context);
|
||||||
|
else ScanValue(value, wrapper, context);
|
||||||
|
|
||||||
context.SortWritePlan();
|
context.SortWritePlan();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -281,8 +281,7 @@ public static partial class AcBinarySerializer
|
||||||
internal static void Register(Type type, IGeneratedBinaryWriter writer) => Writers[type] = writer;
|
internal static void Register(Type type, IGeneratedBinaryWriter writer) => Writers[type] = writer;
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
internal static IGeneratedBinaryWriter? TryGet(Type type) =>
|
internal static IGeneratedBinaryWriter? TryGet(Type type) => Writers.GetValueOrDefault(type);
|
||||||
Writers.TryGetValue(type, out var writer) ? writer : null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -312,85 +311,40 @@ public static partial class AcBinarySerializer
|
||||||
/// Uses ArrayBinaryOutput for byte[] result path.
|
/// Uses ArrayBinaryOutput for byte[] result path.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static byte[] Serialize<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] T>(T value, AcBinarySerializerOptions options)
|
public static byte[] Serialize<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] T>(T value, AcBinarySerializerOptions options)
|
||||||
{
|
=> Serialize(value, typeof(T), options);
|
||||||
if (value == null) return [BinaryTypeCode.Null];
|
|
||||||
|
|
||||||
var runtimeType = value.GetType();
|
public static byte[] Serialize(object? value, AcBinarySerializerOptions options)
|
||||||
var context = AcquireArrayOutputContext(options);
|
=> value == null ? [BinaryTypeCode.Null] : Serialize(value, value.GetType(), options);
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// SGen fast path: skip IQueryable/Expression check + WriteValue dispatch chain.
|
|
||||||
// If root type has a GeneratedWriter it cannot be IQueryable/Expression/primitive/collection.
|
|
||||||
if (options.UseGeneratedCode)
|
|
||||||
{
|
|
||||||
var wrapper = context.GetWrapper(runtimeType);
|
|
||||||
if (wrapper.GeneratedWriter != null)
|
|
||||||
{
|
|
||||||
ScanForDuplicates(value, runtimeType, context);
|
|
||||||
context.WriteHeader();
|
|
||||||
WriteObject(value, wrapper, context);
|
|
||||||
|
|
||||||
if (options.UseCompression != Lz4CompressionMode.None)
|
|
||||||
return Lz4.Compress(context.Output.AsSpan(context._buffer, context._position), options.UseCompression);
|
|
||||||
return context.Output.ToArray(context._buffer, context._position);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Full path: IQueryable/Expression conversion, primitive/collection dispatch
|
|
||||||
var actualValue = ConvertExpressionValue(value, ref runtimeType);
|
|
||||||
ScanForDuplicates(actualValue, runtimeType, context);
|
|
||||||
context.WriteHeader();
|
|
||||||
WriteValue(actualValue, runtimeType, context);
|
|
||||||
|
|
||||||
if (options.UseCompression != Lz4CompressionMode.None)
|
|
||||||
return Lz4.Compress(context.Output.AsSpan(context._buffer, context._position), options.UseCompression);
|
|
||||||
return context.Output.ToArray(context._buffer, context._position);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ReturnContext(context, options);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Non-generic <c>Type</c>-based <see cref="Serialize{T}(T, AcBinarySerializerOptions)"/>. For
|
/// Non-generic <c>Type</c>-based <see cref="Serialize{T}(T, AcBinarySerializerOptions)"/>. For
|
||||||
/// runtime-typed scenarios (plugin frameworks, ASP.NET ModelBinding, MVC formatters). The
|
/// runtime-typed scenarios (plugin frameworks, ASP.NET ModelBinding, MVC formatters). The
|
||||||
/// <paramref name="type"/> parameter is the declared-type hint; the body uses
|
/// <paramref name="type"/> parameter is the declared type used for dispatch — identical semantics
|
||||||
/// <c>value.GetType()</c> for the runtime polymorphism path, identical to the generic version.
|
/// to the generic version where <c>typeof(T)</c> is the dispatch type.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static byte[] Serialize(object? value, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] Type type, AcBinarySerializerOptions options)
|
public static byte[] Serialize(object? value, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] Type type, AcBinarySerializerOptions options)
|
||||||
{
|
{
|
||||||
if (value == null) return [BinaryTypeCode.Null];
|
if (value == null) return [BinaryTypeCode.Null];
|
||||||
|
|
||||||
var runtimeType = value.GetType();
|
|
||||||
var context = AcquireArrayOutputContext(options);
|
var context = AcquireArrayOutputContext(options);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (options.UseGeneratedCode)
|
// Full path: IQueryable/Expression conversion, primitive/collection dispatch
|
||||||
{
|
var actualValue = value; //ConvertExpressionValue(value, ref runtimeType);
|
||||||
var wrapper = context.GetWrapper(runtimeType);
|
var wrapper = context.GetWrapper(type);
|
||||||
if (wrapper.GeneratedWriter != null)
|
|
||||||
{
|
ScanForDuplicates(actualValue, type, context, wrapper);
|
||||||
ScanForDuplicates(value, runtimeType, context);
|
|
||||||
context.WriteHeader();
|
context.WriteHeader();
|
||||||
WriteObject(value, wrapper, context);
|
|
||||||
|
|
||||||
if (options.UseCompression != Lz4CompressionMode.None)
|
// SGen fast path: skip IQueryable/Expression check + WriteValue dispatch chain.
|
||||||
return Lz4.Compress(context.Output.AsSpan(context._buffer, context._position), options.UseCompression);
|
// If root type has a GeneratedWriter it cannot be IQueryable/Expression/primitive/collection.
|
||||||
return context.Output.ToArray(context._buffer, context._position);
|
if (wrapper.GeneratedWriter != null && options.UseGeneratedCode) WriteObject(actualValue, wrapper, context);
|
||||||
}
|
else WriteValue(actualValue, type, context);
|
||||||
}
|
|
||||||
|
|
||||||
var actualValue = ConvertExpressionValue(value, ref runtimeType);
|
return options.UseCompression != Lz4CompressionMode.None
|
||||||
ScanForDuplicates(actualValue, runtimeType, context);
|
? Lz4.Compress(context.Output.AsSpan(context._buffer, context._position), options.UseCompression)
|
||||||
context.WriteHeader();
|
: context.Output.ToArray(context._buffer, context._position);
|
||||||
WriteValue(actualValue, runtimeType, context);
|
|
||||||
|
|
||||||
if (options.UseCompression != Lz4CompressionMode.None)
|
|
||||||
return Lz4.Compress(context.Output.AsSpan(context._buffer, context._position), options.UseCompression);
|
|
||||||
return context.Output.ToArray(context._buffer, context._position);
|
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|
@ -405,8 +359,10 @@ public static partial class AcBinarySerializer
|
||||||
internal static void ScanOnly<T>(T value, AcBinarySerializerOptions options)
|
internal static void ScanOnly<T>(T value, AcBinarySerializerOptions options)
|
||||||
{
|
{
|
||||||
if (value == null) return;
|
if (value == null) return;
|
||||||
var runtimeType = value.GetType();
|
|
||||||
|
var runtimeType = typeof(T);
|
||||||
var context = AcquireArrayOutputContext(options);
|
var context = AcquireArrayOutputContext(options);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ScanForDuplicates(value, runtimeType, context);
|
ScanForDuplicates(value, runtimeType, context);
|
||||||
|
|
@ -432,8 +388,9 @@ public static partial class AcBinarySerializer
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
var runtimeType = value.GetType();
|
var runtimeType = typeof(T);
|
||||||
var context = BinarySerializationContextPool<BufferWriterBinaryOutput>.Get(options);
|
var context = BinarySerializationContextPool<BufferWriterBinaryOutput>.Get(options);
|
||||||
|
|
||||||
context.Output = new BufferWriterBinaryOutput(writer, options.BufferWriterChunkSize);
|
context.Output = new BufferWriterBinaryOutput(writer, options.BufferWriterChunkSize);
|
||||||
context.Output.Initialize(out context._buffer, out context._position, out context._bufferEnd);
|
context.Output.Initialize(out context._buffer, out context._position, out context._bufferEnd);
|
||||||
|
|
||||||
|
|
@ -494,7 +451,7 @@ public static partial class AcBinarySerializer
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
var runtimeType = value.GetType();
|
var runtimeType = type;
|
||||||
var context = BinarySerializationContextPool<BufferWriterBinaryOutput>.Get(options);
|
var context = BinarySerializationContextPool<BufferWriterBinaryOutput>.Get(options);
|
||||||
context.Output = new BufferWriterBinaryOutput(writer, options.BufferWriterChunkSize);
|
context.Output = new BufferWriterBinaryOutput(writer, options.BufferWriterChunkSize);
|
||||||
context.Output.Initialize(out context._buffer, out context._position, out context._bufferEnd);
|
context.Output.Initialize(out context._buffer, out context._position, out context._bufferEnd);
|
||||||
|
|
@ -568,10 +525,12 @@ public static partial class AcBinarySerializer
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <returns>Total serialized bytes written.</returns>
|
/// <returns>Total serialized bytes written.</returns>
|
||||||
public static int SerializeChunked<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] T>(T value, System.IO.Pipelines.Pipe pipe, AcBinarySerializerOptions options, FlushPolicy flushPolicy = FlushPolicy.DoubleBuffered, TimeSpan? flushTimeout = null)
|
public static int SerializeChunked<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] T>(T value, System.IO.Pipelines.Pipe pipe, AcBinarySerializerOptions options, FlushPolicy flushPolicy = FlushPolicy.DoubleBuffered, TimeSpan? flushTimeout = null)
|
||||||
{
|
=> SerializeToPipeWriterCore(value, typeof(T), pipe.Writer, options, flushPolicy, flushTimeout, multiMessage: false);
|
||||||
if (pipe is null) throw new ArgumentNullException(nameof(pipe));
|
|
||||||
return SerializeToPipeWriterCore(value, pipe.Writer, options, flushPolicy, flushTimeout, multiMessage: false);
|
// SerializeChunked non-generic
|
||||||
}
|
public static int SerializeChunked(object? value, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] Type type, System.IO.Pipelines.Pipe pipe, AcBinarySerializerOptions options, FlushPolicy flushPolicy = FlushPolicy.DoubleBuffered, TimeSpan? flushTimeout = null)
|
||||||
|
=> SerializeToPipeWriterCore(value, type, pipe.Writer, options, flushPolicy, flushTimeout, multiMessage: false);
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Serialize to any <see cref="System.IO.Pipelines.PipeWriter"/> as a chunked stream — pure
|
/// Serialize to any <see cref="System.IO.Pipelines.PipeWriter"/> as a chunked stream — pure
|
||||||
|
|
@ -597,7 +556,7 @@ public static partial class AcBinarySerializer
|
||||||
/// <param name="options">Serializer options (type wrappers, reference handling, interning, etc.).</param>
|
/// <param name="options">Serializer options (type wrappers, reference handling, interning, etc.).</param>
|
||||||
/// <returns>Total serialized bytes written.</returns>
|
/// <returns>Total serialized bytes written.</returns>
|
||||||
public static int SerializeChunked<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] T>(T value, System.IO.Pipelines.PipeWriter pipeWriter, AcBinarySerializerOptions options)
|
public static int SerializeChunked<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] T>(T value, System.IO.Pipelines.PipeWriter pipeWriter, AcBinarySerializerOptions options)
|
||||||
=> SerializeToPipeWriterCore(value, pipeWriter, options, FlushPolicy.DoubleBuffered, flushTimeout: null, multiMessage: false);
|
=> SerializeToPipeWriterCore(value, typeof(T), pipeWriter, options, FlushPolicy.DoubleBuffered, flushTimeout: null, multiMessage: false);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Non-generic <c>Type</c>-based counterpart to
|
/// Non-generic <c>Type</c>-based counterpart to
|
||||||
|
|
@ -605,7 +564,7 @@ public static partial class AcBinarySerializer
|
||||||
/// For runtime-typed scenarios (MVC formatters, plugin frameworks).
|
/// For runtime-typed scenarios (MVC formatters, plugin frameworks).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static int SerializeChunked(object? value, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] Type type, System.IO.Pipelines.PipeWriter pipeWriter, AcBinarySerializerOptions options)
|
public static int SerializeChunked(object? value, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] Type type, System.IO.Pipelines.PipeWriter pipeWriter, AcBinarySerializerOptions options)
|
||||||
=> SerializeToPipeWriterCore<object?>(value, pipeWriter, options, FlushPolicy.DoubleBuffered, flushTimeout: null, multiMessage: false);
|
=> SerializeToPipeWriterCore(value,type, pipeWriter, options, FlushPolicy.DoubleBuffered, flushTimeout: null, multiMessage: false);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Serialize a value into a chunked stream where each chunk carries a self-describing
|
/// Serialize a value into a chunked stream where each chunk carries a self-describing
|
||||||
|
|
@ -635,10 +594,8 @@ public static partial class AcBinarySerializer
|
||||||
/// <param name="flushTimeout">See <see cref="SerializeChunked{T}(T, System.IO.Pipelines.Pipe, AcBinarySerializerOptions, FlushPolicy, TimeSpan?)"/>.</param>
|
/// <param name="flushTimeout">See <see cref="SerializeChunked{T}(T, System.IO.Pipelines.Pipe, AcBinarySerializerOptions, FlushPolicy, TimeSpan?)"/>.</param>
|
||||||
/// <returns>Total serialized data bytes (excluding framing overhead).</returns>
|
/// <returns>Total serialized data bytes (excluding framing overhead).</returns>
|
||||||
public static int SerializeChunkedFramed<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] T>(T value, System.IO.Pipelines.Pipe pipe, AcBinarySerializerOptions options, FlushPolicy flushPolicy = FlushPolicy.DoubleBuffered, TimeSpan? flushTimeout = null)
|
public static int SerializeChunkedFramed<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] T>(T value, System.IO.Pipelines.Pipe pipe, AcBinarySerializerOptions options, FlushPolicy flushPolicy = FlushPolicy.DoubleBuffered, TimeSpan? flushTimeout = null)
|
||||||
{
|
=> SerializeToPipeWriterCore(value, typeof(T), pipe.Writer, options, flushPolicy, flushTimeout, multiMessage: true);
|
||||||
if (pipe is null) throw new ArgumentNullException(nameof(pipe));
|
|
||||||
return SerializeToPipeWriterCore(value, pipe.Writer, options, flushPolicy, flushTimeout, multiMessage: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Serialize to any <see cref="System.IO.Pipelines.PipeWriter"/> with per-chunk frame headers
|
/// Serialize to any <see cref="System.IO.Pipelines.PipeWriter"/> with per-chunk frame headers
|
||||||
|
|
@ -650,14 +607,14 @@ public static partial class AcBinarySerializer
|
||||||
/// <see cref="SerializeChunked{T}(T, System.IO.Pipelines.PipeWriter, AcBinarySerializerOptions)"/>.</para>
|
/// <see cref="SerializeChunked{T}(T, System.IO.Pipelines.PipeWriter, AcBinarySerializerOptions)"/>.</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static int SerializeChunkedFramed<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] T>(T value, System.IO.Pipelines.PipeWriter pipeWriter, AcBinarySerializerOptions options)
|
public static int SerializeChunkedFramed<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] T>(T value, System.IO.Pipelines.PipeWriter pipeWriter, AcBinarySerializerOptions options)
|
||||||
=> SerializeToPipeWriterCore(value, pipeWriter, options, FlushPolicy.DoubleBuffered, flushTimeout: null, multiMessage: true);
|
=> SerializeToPipeWriterCore(value, typeof(T), pipeWriter, options, FlushPolicy.DoubleBuffered, flushTimeout: null, multiMessage: true);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Non-generic <c>Type</c>-based counterpart to
|
/// Non-generic <c>Type</c>-based counterpart to
|
||||||
/// <see cref="SerializeChunkedFramed{T}(T, System.IO.Pipelines.PipeWriter, AcBinarySerializerOptions)"/>.
|
/// <see cref="SerializeChunkedFramed{T}(T, System.IO.Pipelines.PipeWriter, AcBinarySerializerOptions)"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static int SerializeChunkedFramed(object? value, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] Type type, System.IO.Pipelines.PipeWriter pipeWriter, AcBinarySerializerOptions options)
|
public static int SerializeChunkedFramed(object? value, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] Type type, System.IO.Pipelines.PipeWriter pipeWriter, AcBinarySerializerOptions options)
|
||||||
=> SerializeToPipeWriterCore<object?>(value, pipeWriter, options, FlushPolicy.DoubleBuffered, flushTimeout: null, multiMessage: true);
|
=> SerializeToPipeWriterCore(value, type, pipeWriter, options, FlushPolicy.DoubleBuffered, flushTimeout: null, multiMessage: true);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Internal flush-tunable framed PipeWriter overload — used by <c>AyCode.Services</c>
|
/// Internal flush-tunable framed PipeWriter overload — used by <c>AyCode.Services</c>
|
||||||
|
|
@ -666,7 +623,7 @@ public static partial class AcBinarySerializer
|
||||||
/// <paramref name="flushPolicy"/> on a guaranteed parallel-capable writer.
|
/// <paramref name="flushPolicy"/> on a guaranteed parallel-capable writer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static int SerializeChunkedFramed<T>(T value, System.IO.Pipelines.PipeWriter pipeWriter, AcBinarySerializerOptions options, FlushPolicy flushPolicy, TimeSpan? flushTimeout)
|
internal static int SerializeChunkedFramed<T>(T value, System.IO.Pipelines.PipeWriter pipeWriter, AcBinarySerializerOptions options, FlushPolicy flushPolicy, TimeSpan? flushTimeout)
|
||||||
=> SerializeToPipeWriterCore(value, pipeWriter, options, flushPolicy, flushTimeout, multiMessage: true);
|
=> SerializeToPipeWriterCore(value, typeof(T), pipeWriter, options, flushPolicy, flushTimeout, multiMessage: true);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Internal legacy alias for <see cref="SerializeChunkedFramed{T}(T, System.IO.Pipelines.PipeWriter, AcBinarySerializerOptions, FlushPolicy, TimeSpan?)"/>
|
/// Internal legacy alias for <see cref="SerializeChunkedFramed{T}(T, System.IO.Pipelines.PipeWriter, AcBinarySerializerOptions, FlushPolicy, TimeSpan?)"/>
|
||||||
|
|
@ -675,14 +632,14 @@ public static partial class AcBinarySerializer
|
||||||
/// (framed wire format with <c>[201][UINT16][data]</c> per chunk + <c>[202]</c> end marker).
|
/// (framed wire format with <c>[201][UINT16][data]</c> per chunk + <c>[202]</c> end marker).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static int Serialize<T>(T value, System.IO.Pipelines.PipeWriter pipeWriter, AcBinarySerializerOptions options, FlushPolicy flushPolicy, TimeSpan? flushTimeout)
|
internal static int Serialize<T>(T value, System.IO.Pipelines.PipeWriter pipeWriter, AcBinarySerializerOptions options, FlushPolicy flushPolicy, TimeSpan? flushTimeout)
|
||||||
=> SerializeToPipeWriterCore(value, pipeWriter, options, flushPolicy, flushTimeout, multiMessage: true);
|
=> SerializeToPipeWriterCore(value, typeof(T), pipeWriter, options, flushPolicy, flushTimeout, multiMessage: true);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Common pipe-output serialization core. Same loop for both raw (<see cref="SerializeChunked{T}"/>)
|
/// Common pipe-output serialization core. Same loop for both raw (<see cref="SerializeChunked{T}"/>)
|
||||||
/// and framed (<see cref="SerializeChunkedFramed{T}"/>) modes — the only difference flows through
|
/// and framed (<see cref="SerializeChunkedFramed{T}"/>) modes — the only difference flows through
|
||||||
/// <paramref name="multiMessage"/> into the <see cref="AsyncPipeWriterOutput"/> ctor.
|
/// <paramref name="multiMessage"/> into the <see cref="AsyncPipeWriterOutput"/> ctor.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static int SerializeToPipeWriterCore<T>(T value, System.IO.Pipelines.PipeWriter pipeWriter, AcBinarySerializerOptions options, FlushPolicy flushPolicy, TimeSpan? flushTimeout, bool multiMessage)
|
private static int SerializeToPipeWriterCore(object? value, Type type, System.IO.Pipelines.PipeWriter pipeWriter, AcBinarySerializerOptions options, FlushPolicy flushPolicy, TimeSpan? flushTimeout, bool multiMessage)
|
||||||
{
|
{
|
||||||
if (value == null)
|
if (value == null)
|
||||||
{
|
{
|
||||||
|
|
@ -707,7 +664,7 @@ public static partial class AcBinarySerializer
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
var runtimeType = value.GetType();
|
var runtimeType = type;
|
||||||
var context = BinarySerializationContextPool<AsyncPipeWriterOutput>.Get(options);
|
var context = BinarySerializationContextPool<AsyncPipeWriterOutput>.Get(options);
|
||||||
|
|
||||||
context.Output = new AsyncPipeWriterOutput(pipeWriter, options.BufferWriterChunkSize, multiMessage, flushPolicy, flushTimeout);
|
context.Output = new AsyncPipeWriterOutput(pipeWriter, options.BufferWriterChunkSize, multiMessage, flushPolicy, flushTimeout);
|
||||||
|
|
@ -760,7 +717,7 @@ public static partial class AcBinarySerializer
|
||||||
{
|
{
|
||||||
if (value == null) return 1;
|
if (value == null) return 1;
|
||||||
|
|
||||||
var runtimeType = value.GetType();
|
var runtimeType = typeof(T);
|
||||||
var context = AcquireArrayOutputContext(options);
|
var context = AcquireArrayOutputContext(options);
|
||||||
|
|
||||||
try
|
try
|
||||||
|
|
@ -785,7 +742,7 @@ public static partial class AcBinarySerializer
|
||||||
{
|
{
|
||||||
if (value == null) return BinarySerializationResult.FromImmutable([BinaryTypeCode.Null]);
|
if (value == null) return BinarySerializationResult.FromImmutable([BinaryTypeCode.Null]);
|
||||||
|
|
||||||
var runtimeType = value.GetType();
|
var runtimeType = typeof(T);
|
||||||
var context = AcquireArrayOutputContext(options);
|
var context = AcquireArrayOutputContext(options);
|
||||||
|
|
||||||
try
|
try
|
||||||
|
|
@ -983,7 +940,7 @@ public static partial class AcBinarySerializer
|
||||||
// Only Nullable<T> can be a value type in the Object accessor path.
|
// Only Nullable<T> can be a value type in the Object accessor path.
|
||||||
if (type.IsValueType)
|
if (type.IsValueType)
|
||||||
{
|
{
|
||||||
if (TryWritePrimitive(value, value.GetType(), context))
|
if (TryWritePrimitive(value, type, context))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue