// Copyright (c) All contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; using System.Buffers; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Linq; using System.Runtime.InteropServices; #pragma warning disable SA1649 // File name should match first type name namespace MessagePack.Formatters { public sealed class ArrayFormatter : IMessagePackFormatter { public void Serialize(ref MessagePackWriter writer, T[] value, MessagePackSerializerOptions options) { if (value == null) { writer.WriteNil(); } else { IMessagePackFormatter formatter = options.Resolver.GetFormatterWithVerify(); writer.WriteArrayHeader(value.Length); for (int i = 0; i < value.Length; i++) { writer.CancellationToken.ThrowIfCancellationRequested(); formatter.Serialize(ref writer, value[i], options); } } } public T[] Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) { if (reader.TryReadNil()) { return default; } var len = reader.ReadArrayHeader(); if (len == 0) { return Array.Empty(); } IMessagePackFormatter formatter = options.Resolver.GetFormatterWithVerify(); var array = new T[len]; options.Security.DepthStep(ref reader); try { for (int i = 0; i < array.Length; i++) { reader.CancellationToken.ThrowIfCancellationRequested(); array[i] = formatter.Deserialize(ref reader, options); } } finally { reader.Depth--; } return array; } } public sealed class ByteMemoryFormatter : IMessagePackFormatter> { public static readonly ByteMemoryFormatter Instance = new ByteMemoryFormatter(); private ByteMemoryFormatter() { } public void Serialize(ref MessagePackWriter writer, Memory value, MessagePackSerializerOptions options) { writer.Write(value.Span); } public Memory Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) { return reader.ReadBytes() is ReadOnlySequence bytes ? new Memory(bytes.ToArray()) : default; } } public sealed class ByteReadOnlyMemoryFormatter : IMessagePackFormatter> { public static readonly ByteReadOnlyMemoryFormatter Instance = new ByteReadOnlyMemoryFormatter(); private ByteReadOnlyMemoryFormatter() { } public void Serialize(ref MessagePackWriter writer, ReadOnlyMemory value, MessagePackSerializerOptions options) { writer.Write(value.Span); } public ReadOnlyMemory Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) { return reader.ReadBytes() is ReadOnlySequence bytes ? new ReadOnlyMemory(bytes.ToArray()) : default; } } public sealed class ByteReadOnlySequenceFormatter : IMessagePackFormatter> { public static readonly ByteReadOnlySequenceFormatter Instance = new ByteReadOnlySequenceFormatter(); private ByteReadOnlySequenceFormatter() { } public void Serialize(ref MessagePackWriter writer, ReadOnlySequence value, MessagePackSerializerOptions options) { writer.WriteBinHeader(checked((int)value.Length)); foreach (ReadOnlyMemory segment in value) { writer.WriteRaw(segment.Span); } } public ReadOnlySequence Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) { return reader.ReadBytes() is ReadOnlySequence bytes ? new ReadOnlySequence(bytes.ToArray()) : default; } } public sealed class ByteArraySegmentFormatter : IMessagePackFormatter> { public static readonly ByteArraySegmentFormatter Instance = new ByteArraySegmentFormatter(); private ByteArraySegmentFormatter() { } public void Serialize(ref MessagePackWriter writer, ArraySegment value, MessagePackSerializerOptions options) { if (value.Array == null) { writer.WriteNil(); } else { writer.Write(value); } } public ArraySegment Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) { return reader.ReadBytes() is ReadOnlySequence bytes ? new ArraySegment(bytes.ToArray()) : default; } } public sealed class MemoryFormatter : IMessagePackFormatter> { public void Serialize(ref MessagePackWriter writer, Memory value, MessagePackSerializerOptions options) { var formatter = options.Resolver.GetFormatterWithVerify>(); formatter.Serialize(ref writer, value, options); } public Memory Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) { return options.Resolver.GetFormatterWithVerify().Deserialize(ref reader, options); } } public sealed class ReadOnlyMemoryFormatter : IMessagePackFormatter> { public void Serialize(ref MessagePackWriter writer, ReadOnlyMemory value, MessagePackSerializerOptions options) { IMessagePackFormatter formatter = options.Resolver.GetFormatterWithVerify(); var span = value.Span; writer.WriteArrayHeader(span.Length); for (int i = 0; i < span.Length; i++) { writer.CancellationToken.ThrowIfCancellationRequested(); formatter.Serialize(ref writer, span[i], options); } } public ReadOnlyMemory Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) { return options.Resolver.GetFormatterWithVerify().Deserialize(ref reader, options); } } public sealed class ReadOnlySequenceFormatter : IMessagePackFormatter> { public void Serialize(ref MessagePackWriter writer, ReadOnlySequence value, MessagePackSerializerOptions options) { IMessagePackFormatter formatter = options.Resolver.GetFormatterWithVerify(); writer.WriteArrayHeader(checked((int)value.Length)); foreach (ReadOnlyMemory segment in value) { ReadOnlySpan span = segment.Span; for (int i = 0; i < span.Length; i++) { writer.CancellationToken.ThrowIfCancellationRequested(); formatter.Serialize(ref writer, span[i], options); } } } public ReadOnlySequence Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) { return new ReadOnlySequence(options.Resolver.GetFormatterWithVerify().Deserialize(ref reader, options)); } } public sealed class ArraySegmentFormatter : IMessagePackFormatter> { public void Serialize(ref MessagePackWriter writer, ArraySegment value, MessagePackSerializerOptions options) { if (value.Array == null) { writer.WriteNil(); } else { var formatter = options.Resolver.GetFormatterWithVerify>(); formatter.Serialize(ref writer, value, options); } } public ArraySegment Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) { if (reader.TryReadNil()) { return default; } else { T[] array = options.Resolver.GetFormatterWithVerify().Deserialize(ref reader, options); return new ArraySegment(array); } } } // List is popular format, should avoid abstraction. public sealed class ListFormatter : IMessagePackFormatter> { public void Serialize(ref MessagePackWriter writer, List value, MessagePackSerializerOptions options) { if (value == null) { writer.WriteNil(); } else { IMessagePackFormatter formatter = options.Resolver.GetFormatterWithVerify(); var c = value.Count; writer.WriteArrayHeader(c); for (int i = 0; i < c; i++) { writer.CancellationToken.ThrowIfCancellationRequested(); formatter.Serialize(ref writer, value[i], options); } } } public List Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) { if (reader.TryReadNil()) { return default; } else { IMessagePackFormatter formatter = options.Resolver.GetFormatterWithVerify(); var len = reader.ReadArrayHeader(); var list = new List((int)len); options.Security.DepthStep(ref reader); try { for (int i = 0; i < len; i++) { reader.CancellationToken.ThrowIfCancellationRequested(); list.Add(formatter.Deserialize(ref reader, options)); } } finally { reader.Depth--; } return list; } } } public abstract class CollectionFormatterBase : IMessagePackFormatter where TCollection : IEnumerable where TEnumerator : IEnumerator { public void Serialize(ref MessagePackWriter writer, TCollection value, MessagePackSerializerOptions options) { if (value == null) { writer.WriteNil(); } else { IMessagePackFormatter formatter = options.Resolver.GetFormatterWithVerify(); // Optimize iteration(array is fastest) if (value is TElement[] array) { writer.WriteArrayHeader(array.Length); foreach (TElement item in array) { writer.CancellationToken.ThrowIfCancellationRequested(); formatter.Serialize(ref writer, item, options); } } else { // knows count or not. var seqCount = this.GetCount(value); if (seqCount != null) { writer.WriteArrayHeader(seqCount.Value); // Unity's foreach struct enumerator causes boxing so iterate manually. using (var e = this.GetSourceEnumerator(value)) { while (e.MoveNext()) { writer.CancellationToken.ThrowIfCancellationRequested(); formatter.Serialize(ref writer, e.Current, options); } } } else { using (var scratchRental = options.SequencePool.Rent()) { var scratch = scratchRental.Value; MessagePackWriter scratchWriter = writer.Clone(scratch); var count = 0; using (var e = this.GetSourceEnumerator(value)) { while (e.MoveNext()) { writer.CancellationToken.ThrowIfCancellationRequested(); count++; formatter.Serialize(ref scratchWriter, e.Current, options); } } scratchWriter.Flush(); writer.WriteArrayHeader(count); writer.WriteRaw(scratch.AsReadOnlySequence); } } } } } public TCollection Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) { if (reader.TryReadNil()) { return default(TCollection); } else { IMessagePackFormatter formatter = options.Resolver.GetFormatterWithVerify(); var len = reader.ReadArrayHeader(); TIntermediate list = this.Create(len, options); options.Security.DepthStep(ref reader); try { for (int i = 0; i < len; i++) { reader.CancellationToken.ThrowIfCancellationRequested(); this.Add(list, i, formatter.Deserialize(ref reader, options), options); } } finally { reader.Depth--; } return this.Complete(list); } } // abstraction for serialize protected virtual int? GetCount(TCollection sequence) { var collection = sequence as ICollection; if (collection != null) { return collection.Count; } else { var c2 = sequence as IReadOnlyCollection; if (c2 != null) { return c2.Count; } } return null; } // Some collections can use struct iterator, this is optimization path protected abstract TEnumerator GetSourceEnumerator(TCollection source); // abstraction for deserialize protected abstract TIntermediate Create(int count, MessagePackSerializerOptions options); protected abstract void Add(TIntermediate collection, int index, TElement value, MessagePackSerializerOptions options); protected abstract TCollection Complete(TIntermediate intermediateCollection); } public abstract class CollectionFormatterBase : CollectionFormatterBase, TCollection> where TCollection : IEnumerable { protected override IEnumerator GetSourceEnumerator(TCollection source) { return source.GetEnumerator(); } } public abstract class CollectionFormatterBase : CollectionFormatterBase where TCollection : IEnumerable { protected sealed override TCollection Complete(TCollection intermediateCollection) { return intermediateCollection; } } public sealed class GenericCollectionFormatter : CollectionFormatterBase where TCollection : ICollection, new() { protected override TCollection Create(int count, MessagePackSerializerOptions options) { return new TCollection(); } protected override void Add(TCollection collection, int index, TElement value, MessagePackSerializerOptions options) { collection.Add(value); } } public sealed class GenericEnumerableFormatter : CollectionFormatterBase where TCollection : IEnumerable { protected override TElement[] Create(int count, MessagePackSerializerOptions options) { return new TElement[count]; } protected override void Add(TElement[] collection, int index, TElement value, MessagePackSerializerOptions options) { collection[index] = value; } protected override TCollection Complete(TElement[] intermediateCollection) { return (TCollection)Activator.CreateInstance(typeof(TCollection), intermediateCollection); } } public sealed class LinkedListFormatter : CollectionFormatterBase, LinkedList.Enumerator, LinkedList> { protected override void Add(LinkedList collection, int index, T value, MessagePackSerializerOptions options) { collection.AddLast(value); } protected override LinkedList Complete(LinkedList intermediateCollection) { return intermediateCollection; } protected override LinkedList Create(int count, MessagePackSerializerOptions options) { return new LinkedList(); } protected override LinkedList.Enumerator GetSourceEnumerator(LinkedList source) { return source.GetEnumerator(); } } public sealed class QueueFormatter : CollectionFormatterBase, Queue.Enumerator, Queue> { protected override int? GetCount(Queue sequence) { return sequence.Count; } protected override void Add(Queue collection, int index, T value, MessagePackSerializerOptions options) { collection.Enqueue(value); } protected override Queue Create(int count, MessagePackSerializerOptions options) { return new Queue(count); } protected override Queue.Enumerator GetSourceEnumerator(Queue source) { return source.GetEnumerator(); } protected override Queue Complete(Queue intermediateCollection) { return intermediateCollection; } } // should deserialize reverse order. public sealed class StackFormatter : CollectionFormatterBase.Enumerator, Stack> { protected override int? GetCount(Stack sequence) { return sequence.Count; } protected override void Add(T[] collection, int index, T value, MessagePackSerializerOptions options) { // add reverse collection[collection.Length - 1 - index] = value; } protected override T[] Create(int count, MessagePackSerializerOptions options) { return count == 0 ? Array.Empty() : new T[count]; } protected override Stack.Enumerator GetSourceEnumerator(Stack source) { return source.GetEnumerator(); } protected override Stack Complete(T[] intermediateCollection) { return new Stack(intermediateCollection); } } public sealed class HashSetFormatter : CollectionFormatterBase, HashSet.Enumerator, HashSet> { protected override int? GetCount(HashSet sequence) { return sequence.Count; } protected override void Add(HashSet collection, int index, T value, MessagePackSerializerOptions options) { collection.Add(value); } protected override HashSet Complete(HashSet intermediateCollection) { return intermediateCollection; } protected override HashSet Create(int count, MessagePackSerializerOptions options) { return new HashSet(options.Security.GetEqualityComparer()); } protected override HashSet.Enumerator GetSourceEnumerator(HashSet source) { return source.GetEnumerator(); } } public sealed class ReadOnlyCollectionFormatter : CollectionFormatterBase> { protected override void Add(T[] collection, int index, T value, MessagePackSerializerOptions options) { collection[index] = value; } protected override ReadOnlyCollection Complete(T[] intermediateCollection) { return new ReadOnlyCollection(intermediateCollection); } protected override T[] Create(int count, MessagePackSerializerOptions options) { return count == 0 ? Array.Empty() : new T[count]; } } [Obsolete("Use " + nameof(InterfaceListFormatter2) + " instead.")] public sealed class InterfaceListFormatter : CollectionFormatterBase> { protected override void Add(T[] collection, int index, T value, MessagePackSerializerOptions options) { collection[index] = value; } protected override T[] Create(int count, MessagePackSerializerOptions options) { return count == 0 ? Array.Empty() : new T[count]; } protected override IList Complete(T[] intermediateCollection) { return intermediateCollection; } } [Obsolete("Use " + nameof(InterfaceCollectionFormatter2) + " instead.")] public sealed class InterfaceCollectionFormatter : CollectionFormatterBase> { protected override void Add(T[] collection, int index, T value, MessagePackSerializerOptions options) { collection[index] = value; } protected override T[] Create(int count, MessagePackSerializerOptions options) { return count == 0 ? Array.Empty() : new T[count]; } protected override ICollection Complete(T[] intermediateCollection) { return intermediateCollection; } } public sealed class InterfaceListFormatter2 : CollectionFormatterBase, IList> { protected override void Add(List collection, int index, T value, MessagePackSerializerOptions options) { collection.Add(value); } protected override List Create(int count, MessagePackSerializerOptions options) { return new List(count); } protected override IList Complete(List intermediateCollection) { return intermediateCollection; } } public sealed class InterfaceCollectionFormatter2 : CollectionFormatterBase, ICollection> { protected override void Add(List collection, int index, T value, MessagePackSerializerOptions options) { collection.Add(value); } protected override List Create(int count, MessagePackSerializerOptions options) { return new List(count); } protected override ICollection Complete(List intermediateCollection) { return intermediateCollection; } } public sealed class InterfaceEnumerableFormatter : CollectionFormatterBase> { protected override void Add(T[] collection, int index, T value, MessagePackSerializerOptions options) { collection[index] = value; } protected override T[] Create(int count, MessagePackSerializerOptions options) { return count == 0 ? Array.Empty() : new T[count]; } protected override IEnumerable Complete(T[] intermediateCollection) { return intermediateCollection; } } // [Key, [Array]] public sealed class InterfaceGroupingFormatter : IMessagePackFormatter> { public void Serialize(ref MessagePackWriter writer, IGrouping value, MessagePackSerializerOptions options) { if (value == null) { writer.WriteNil(); } else { writer.WriteArrayHeader(2); options.Resolver.GetFormatterWithVerify().Serialize(ref writer, value.Key, options); options.Resolver.GetFormatterWithVerify>().Serialize(ref writer, value, options); } } public IGrouping Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) { if (reader.TryReadNil()) { return null; } else { var count = reader.ReadArrayHeader(); if (count != 2) { throw new MessagePackSerializationException("Invalid Grouping format."); } options.Security.DepthStep(ref reader); try { TKey key = options.Resolver.GetFormatterWithVerify().Deserialize(ref reader, options); IEnumerable value = options.Resolver.GetFormatterWithVerify>().Deserialize(ref reader, options); return new Grouping(key, value); } finally { reader.Depth--; } } } } public sealed class InterfaceLookupFormatter : CollectionFormatterBase, Dictionary>, ILookup> { protected override void Add(Dictionary> collection, int index, IGrouping value, MessagePackSerializerOptions options) { collection.Add(value.Key, value); } protected override ILookup Complete(Dictionary> intermediateCollection) { return new Lookup(intermediateCollection); } protected override Dictionary> Create(int count, MessagePackSerializerOptions options) { return new Dictionary>(count); } } internal class Grouping : IGrouping { private readonly TKey key; private readonly IEnumerable elements; public Grouping(TKey key, IEnumerable elements) { this.key = key; this.elements = elements; } public TKey Key { get { return this.key; } } public IEnumerator GetEnumerator() { return this.elements.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return this.elements.GetEnumerator(); } } internal class Lookup : ILookup { private readonly Dictionary> groupings; public Lookup(Dictionary> groupings) { this.groupings = groupings; } public IEnumerable this[TKey key] { get { return this.groupings[key]; } } public int Count { get { return this.groupings.Count; } } public bool Contains(TKey key) { return this.groupings.ContainsKey(key); } public IEnumerator> GetEnumerator() { return this.groupings.Values.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return this.groupings.Values.GetEnumerator(); } } /* NonGenerics */ public sealed class NonGenericListFormatter : IMessagePackFormatter where T : class, IList, new() { public void Serialize(ref MessagePackWriter writer, T value, MessagePackSerializerOptions options) { if (value == null) { writer.WriteNil(); return; } IMessagePackFormatter formatter = options.Resolver.GetFormatterWithVerify(); writer.WriteArrayHeader(value.Count); foreach (var item in value) { writer.CancellationToken.ThrowIfCancellationRequested(); formatter.Serialize(ref writer, item, options); } } public T Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) { if (reader.TryReadNil()) { return default(T); } IMessagePackFormatter formatter = options.Resolver.GetFormatterWithVerify(); var count = reader.ReadArrayHeader(); var list = new T(); options.Security.DepthStep(ref reader); try { for (int i = 0; i < count; i++) { reader.CancellationToken.ThrowIfCancellationRequested(); list.Add(formatter.Deserialize(ref reader, options)); } } finally { reader.Depth--; } return list; } } public sealed class NonGenericInterfaceCollectionFormatter : IMessagePackFormatter { public static readonly IMessagePackFormatter Instance = new NonGenericInterfaceCollectionFormatter(); private NonGenericInterfaceCollectionFormatter() { } public void Serialize(ref MessagePackWriter writer, ICollection value, MessagePackSerializerOptions options) { if (value == null) { writer.WriteNil(); return; } IMessagePackFormatter formatter = options.Resolver.GetFormatterWithVerify(); writer.WriteArrayHeader(value.Count); foreach (var item in value) { writer.CancellationToken.ThrowIfCancellationRequested(); formatter.Serialize(ref writer, item, options); } } public ICollection Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) { if (reader.TryReadNil()) { return default(ICollection); } var count = reader.ReadArrayHeader(); if (count == 0) { return Array.Empty(); } IMessagePackFormatter formatter = options.Resolver.GetFormatterWithVerify(); var list = new object[count]; options.Security.DepthStep(ref reader); try { for (int i = 0; i < count; i++) { reader.CancellationToken.ThrowIfCancellationRequested(); list[i] = formatter.Deserialize(ref reader, options); } } finally { reader.Depth--; } return list; } } public sealed class NonGenericInterfaceEnumerableFormatter : IMessagePackFormatter { public static readonly IMessagePackFormatter Instance = new NonGenericInterfaceEnumerableFormatter(); private NonGenericInterfaceEnumerableFormatter() { } public void Serialize(ref MessagePackWriter writer, IEnumerable value, MessagePackSerializerOptions options) { if (value == null) { writer.WriteNil(); return; } IMessagePackFormatter formatter = options.Resolver.GetFormatterWithVerify(); using (var scratchRental = options.SequencePool.Rent()) { var scratch = scratchRental.Value; MessagePackWriter scratchWriter = writer.Clone(scratch); var count = 0; var e = value.GetEnumerator(); try { while (e.MoveNext()) { writer.CancellationToken.ThrowIfCancellationRequested(); count++; formatter.Serialize(ref scratchWriter, e.Current, options); } } finally { if (e is IDisposable d) { d.Dispose(); } } scratchWriter.Flush(); writer.WriteArrayHeader(count); writer.WriteRaw(scratch.AsReadOnlySequence); } } public IEnumerable Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) { if (reader.TryReadNil()) { return default(IEnumerable); } var count = reader.ReadArrayHeader(); if (count == 0) { return Array.Empty(); } IMessagePackFormatter formatter = options.Resolver.GetFormatterWithVerify(); var list = new object[count]; options.Security.DepthStep(ref reader); try { for (int i = 0; i < count; i++) { reader.CancellationToken.ThrowIfCancellationRequested(); list[i] = formatter.Deserialize(ref reader, options); } } finally { reader.Depth--; } return list; } } public sealed class NonGenericInterfaceListFormatter : IMessagePackFormatter { public static readonly IMessagePackFormatter Instance = new NonGenericInterfaceListFormatter(); private NonGenericInterfaceListFormatter() { } public void Serialize(ref MessagePackWriter writer, IList value, MessagePackSerializerOptions options) { if (value == null) { writer.WriteNil(); return; } IMessagePackFormatter formatter = options.Resolver.GetFormatterWithVerify(); writer.WriteArrayHeader(value.Count); foreach (var item in value) { writer.CancellationToken.ThrowIfCancellationRequested(); formatter.Serialize(ref writer, item, options); } } public IList Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) { if (reader.TryReadNil()) { return default(IList); } var count = reader.ReadArrayHeader(); if (count == 0) { return Array.Empty(); } IMessagePackFormatter formatter = options.Resolver.GetFormatterWithVerify(); var list = new object[count]; options.Security.DepthStep(ref reader); try { for (int i = 0; i < count; i++) { reader.CancellationToken.ThrowIfCancellationRequested(); list[i] = formatter.Deserialize(ref reader, options); } } finally { reader.Depth--; } return list; } } public sealed class NonGenericDictionaryFormatter : IMessagePackFormatter where T : class, IDictionary, new() { public void Serialize(ref MessagePackWriter writer, T value, MessagePackSerializerOptions options) { if (value == null) { writer.WriteNil(); return; } IMessagePackFormatter formatter = options.Resolver.GetFormatterWithVerify(); writer.WriteMapHeader(value.Count); foreach (DictionaryEntry item in value) { writer.CancellationToken.ThrowIfCancellationRequested(); formatter.Serialize(ref writer, item.Key, options); formatter.Serialize(ref writer, item.Value, options); } } public T Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) { if (reader.TryReadNil()) { return null; } IMessagePackFormatter formatter = options.Resolver.GetFormatterWithVerify(); var count = reader.ReadMapHeader(); var dict = CollectionHelpers.CreateHashCollection(count, options.Security.GetEqualityComparer()); options.Security.DepthStep(ref reader); try { for (int i = 0; i < count; i++) { reader.CancellationToken.ThrowIfCancellationRequested(); var key = formatter.Deserialize(ref reader, options); var value = formatter.Deserialize(ref reader, options); dict.Add(key, value); } } finally { reader.Depth--; } return dict; } } public sealed class NonGenericInterfaceDictionaryFormatter : IMessagePackFormatter { public static readonly IMessagePackFormatter Instance = new NonGenericInterfaceDictionaryFormatter(); private NonGenericInterfaceDictionaryFormatter() { } public void Serialize(ref MessagePackWriter writer, IDictionary value, MessagePackSerializerOptions options) { if (value == null) { writer.WriteNil(); return; } IMessagePackFormatter formatter = options.Resolver.GetFormatterWithVerify(); writer.WriteMapHeader(value.Count); foreach (DictionaryEntry item in value) { writer.CancellationToken.ThrowIfCancellationRequested(); formatter.Serialize(ref writer, item.Key, options); formatter.Serialize(ref writer, item.Value, options); } } public IDictionary Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) { if (reader.TryReadNil()) { return null; } IMessagePackFormatter formatter = options.Resolver.GetFormatterWithVerify(); var count = reader.ReadMapHeader(); var dict = new Dictionary(count, options.Security.GetEqualityComparer()); options.Security.DepthStep(ref reader); try { for (int i = 0; i < count; i++) { reader.CancellationToken.ThrowIfCancellationRequested(); var key = formatter.Deserialize(ref reader, options); var value = formatter.Deserialize(ref reader, options); dict.Add(key, value); } } finally { reader.Depth--; } return dict; } } public sealed class ObservableCollectionFormatter : CollectionFormatterBase> { protected override void Add(ObservableCollection collection, int index, T value, MessagePackSerializerOptions options) { collection.Add(value); } protected override ObservableCollection Create(int count, MessagePackSerializerOptions options) { return new ObservableCollection(); } } public sealed class ReadOnlyObservableCollectionFormatter : CollectionFormatterBase, ReadOnlyObservableCollection> { protected override void Add(ObservableCollection collection, int index, T value, MessagePackSerializerOptions options) { collection.Add(value); } protected override ObservableCollection Create(int count, MessagePackSerializerOptions options) { return new ObservableCollection(); } protected override ReadOnlyObservableCollection Complete(ObservableCollection intermediateCollection) { return new ReadOnlyObservableCollection(intermediateCollection); } } public sealed class InterfaceReadOnlyListFormatter : CollectionFormatterBase> { protected override void Add(T[] collection, int index, T value, MessagePackSerializerOptions options) { collection[index] = value; } protected override T[] Create(int count, MessagePackSerializerOptions options) { return count == 0 ? Array.Empty() : new T[count]; } protected override IReadOnlyList Complete(T[] intermediateCollection) { return intermediateCollection; } } public sealed class InterfaceReadOnlyCollectionFormatter : CollectionFormatterBase> { protected override void Add(T[] collection, int index, T value, MessagePackSerializerOptions options) { collection[index] = value; } protected override T[] Create(int count, MessagePackSerializerOptions options) { return count == 0 ? Array.Empty() : new T[count]; } protected override IReadOnlyCollection Complete(T[] intermediateCollection) { return intermediateCollection; } } public sealed class InterfaceSetFormatter : CollectionFormatterBase, ISet> { protected override void Add(HashSet collection, int index, T value, MessagePackSerializerOptions options) { collection.Add(value); } protected override ISet Complete(HashSet intermediateCollection) { return intermediateCollection; } protected override HashSet Create(int count, MessagePackSerializerOptions options) { return new HashSet(options.Security.GetEqualityComparer()); } } #if NET5_0_OR_GREATER public sealed class InterfaceReadOnlySetFormatter : CollectionFormatterBase, IReadOnlySet> { protected override void Add(HashSet collection, int index, T value, MessagePackSerializerOptions options) { collection.Add(value); } protected override IReadOnlySet Complete(HashSet intermediateCollection) { return intermediateCollection; } protected override HashSet Create(int count, MessagePackSerializerOptions options) { return new HashSet(options.Security.GetEqualityComparer()); } } #endif public sealed class ConcurrentBagFormatter : CollectionFormatterBase> { protected override int? GetCount(ConcurrentBag sequence) { return sequence.Count; } protected override void Add(ConcurrentBag collection, int index, T value, MessagePackSerializerOptions options) { collection.Add(value); } protected override ConcurrentBag Create(int count, MessagePackSerializerOptions options) { return new ConcurrentBag(); } } public sealed class ConcurrentQueueFormatter : CollectionFormatterBase> { protected override int? GetCount(ConcurrentQueue sequence) { return sequence.Count; } protected override void Add(ConcurrentQueue collection, int index, T value, MessagePackSerializerOptions options) { collection.Enqueue(value); } protected override ConcurrentQueue Create(int count, MessagePackSerializerOptions options) { return new ConcurrentQueue(); } } public sealed class ConcurrentStackFormatter : CollectionFormatterBase> { protected override int? GetCount(ConcurrentStack sequence) { return sequence.Count; } protected override void Add(T[] collection, int index, T value, MessagePackSerializerOptions options) { // add reverse collection[collection.Length - 1 - index] = value; } protected override T[] Create(int count, MessagePackSerializerOptions options) { return count == 0 ? Array.Empty() : new T[count]; } protected override ConcurrentStack Complete(T[] intermediateCollection) { return new ConcurrentStack(intermediateCollection); } } }