using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; #if NETSTANDARD using System.Collections.Concurrent; #endif namespace MessagePack.Formatters { public sealed class ArrayFormatter : IMessagePackFormatter { public int Serialize(ref byte[] bytes, int offset, T[] value, IFormatterResolver formatterResolver) { if (value == null) { return MessagePackBinary.WriteNil(ref bytes, offset); } else { var startOffset = offset; var formatter = formatterResolver.GetFormatterWithVerify(); offset += MessagePackBinary.WriteArrayHeader(ref bytes, offset, value.Length); for (int i = 0; i < value.Length; i++) { offset += formatter.Serialize(ref bytes, offset, value[i], formatterResolver); } return offset - startOffset; } } public T[] Deserialize(byte[] bytes, int offset, IFormatterResolver formatterResolver, out int readSize) { if (MessagePackBinary.IsNil(bytes, offset)) { readSize = 1; return null; } else { var startOffset = offset; var formatter = formatterResolver.GetFormatterWithVerify(); var len = MessagePackBinary.ReadArrayHeader(bytes, offset, out readSize); offset += readSize; var array = new T[len]; for (int i = 0; i < array.Length; i++) { array[i] = formatter.Deserialize(bytes, offset, formatterResolver, out readSize); offset += readSize; } readSize = offset - startOffset; return array; } } } public sealed class ByteArraySegmentFormatter : IMessagePackFormatter> { public static readonly ByteArraySegmentFormatter Instance = new ByteArraySegmentFormatter(); ByteArraySegmentFormatter() { } public int Serialize(ref byte[] bytes, int offset, ArraySegment value, IFormatterResolver formatterResolver) { if (value.Array == null) { return MessagePackBinary.WriteNil(ref bytes, offset); } else { return MessagePackBinary.WriteBytes(ref bytes, offset, value.Array, value.Offset, value.Count); } } public ArraySegment Deserialize(byte[] bytes, int offset, IFormatterResolver formatterResolver, out int readSize) { if (MessagePackBinary.IsNil(bytes, offset)) { readSize = 1; return default(ArraySegment); } else { // use ReadBytesSegment? But currently straem api uses memory pool so can't save arraysegment... var binary = MessagePackBinary.ReadBytes(bytes, offset, out readSize); return new ArraySegment(binary, 0, binary.Length); } } } public sealed class ArraySegmentFormatter : IMessagePackFormatter> { public int Serialize(ref byte[] bytes, int offset, ArraySegment value, IFormatterResolver formatterResolver) { if (value.Array == null) { return MessagePackBinary.WriteNil(ref bytes, offset); } else { var startOffset = offset; var formatter = formatterResolver.GetFormatterWithVerify(); offset += MessagePackBinary.WriteArrayHeader(ref bytes, offset, value.Count); var array = value.Array; for (int i = 0; i < value.Count; i++) { var item = array[value.Offset + i]; offset += formatter.Serialize(ref bytes, offset, item, formatterResolver); } return offset - startOffset; } } public ArraySegment Deserialize(byte[] bytes, int offset, IFormatterResolver formatterResolver, out int readSize) { if (MessagePackBinary.IsNil(bytes, offset)) { readSize = 1; return default(ArraySegment); } else { var array = formatterResolver.GetFormatterWithVerify().Deserialize(bytes, offset, formatterResolver, out readSize); return new ArraySegment(array, 0, array.Length); } } } // List is popular format, should avoid abstraction. public sealed class ListFormatter : IMessagePackFormatter> { public int Serialize(ref byte[] bytes, int offset, List value, IFormatterResolver formatterResolver) { if (value == null) { return MessagePackBinary.WriteNil(ref bytes, offset); } else { var startOffset = offset; var formatter = formatterResolver.GetFormatterWithVerify(); var c = value.Count; offset += MessagePackBinary.WriteArrayHeader(ref bytes, offset, c); for (int i = 0; i < c; i++) { offset += formatter.Serialize(ref bytes, offset, value[i], formatterResolver); } return offset - startOffset; } } public List Deserialize(byte[] bytes, int offset, IFormatterResolver formatterResolver, out int readSize) { if (MessagePackBinary.IsNil(bytes, offset)) { readSize = 1; return null; } else { var startOffset = offset; var formatter = formatterResolver.GetFormatterWithVerify(); var len = MessagePackBinary.ReadArrayHeader(bytes, offset, out readSize); offset += readSize; var list = new List(len); for (int i = 0; i < len; i++) { list.Add(formatter.Deserialize(bytes, offset, formatterResolver, out readSize)); offset += readSize; } readSize = offset - startOffset; return list; } } } public abstract class CollectionFormatterBase : IMessagePackFormatter where TCollection : IEnumerable where TEnumerator : IEnumerator { public int Serialize(ref byte[] bytes, int offset, TCollection value, IFormatterResolver formatterResolver) { if (value == null) { return MessagePackBinary.WriteNil(ref bytes, offset); } else { // Optimize iteration(array is fastest) var array = value as TElement[]; if (array != null) { var startOffset = offset; var formatter = formatterResolver.GetFormatterWithVerify(); offset += MessagePackBinary.WriteArrayHeader(ref bytes, offset, array.Length); foreach (var item in array) { offset += formatter.Serialize(ref bytes, offset, item, formatterResolver); } return offset - startOffset; } else { var startOffset = offset; var formatter = formatterResolver.GetFormatterWithVerify(); // knows count or not. var seqCount = GetCount(value); if (seqCount != null) { offset += MessagePackBinary.WriteArrayHeader(ref bytes, offset, seqCount.Value); // Unity's foreach struct enumerator causes boxing so iterate manually. var e = GetSourceEnumerator(value); try { while (e.MoveNext()) { #if NETSTANDARD offset += formatter.Serialize(ref bytes, offset, e.Current, formatterResolver); #else offset += formatter.Serialize(ref bytes, (int)offset, (TElement)e.Current, (IFormatterResolver)formatterResolver); #endif } } finally { e.Dispose(); } return offset - startOffset; } else { // write message first -> open header space -> write header var writeStarOffset = offset; var count = 0; var moveCount = 0; // count = 16 <= 65535, header len is "3" so choose default space. offset += 3; var e = GetSourceEnumerator(value); try { while (e.MoveNext()) { count++; #if NETSTANDARD var writeSize = formatter.Serialize(ref bytes, offset, e.Current, formatterResolver); #else var writeSize = formatter.Serialize(ref bytes, (int)offset, (TElement)e.Current, (IFormatterResolver)formatterResolver); #endif moveCount += writeSize; offset += writeSize; } } finally { e.Dispose(); } var headerLength = MessagePackBinary.GetArrayHeaderLength(count); if (headerLength != 3) { if (headerLength == 1) offset -= 2; // 1 else offset += 2; // 5 MessagePackBinary.EnsureCapacity(ref bytes, offset, headerLength); Buffer.BlockCopy(bytes, writeStarOffset + 3, bytes, writeStarOffset + headerLength, moveCount); } MessagePackBinary.WriteArrayHeader(ref bytes, writeStarOffset, count); return offset - startOffset; } } } } public TCollection Deserialize(byte[] bytes, int offset, IFormatterResolver formatterResolver, out int readSize) { if (MessagePackBinary.IsNil(bytes, offset)) { readSize = 1; return default(TCollection); } else { var startOffset = offset; var formatter = formatterResolver.GetFormatterWithVerify(); var len = MessagePackBinary.ReadArrayHeader(bytes, offset, out readSize); offset += readSize; var list = Create(len); for (int i = 0; i < len; i++) { Add(list, i, formatter.Deserialize(bytes, offset, formatterResolver, out readSize)); offset += readSize; } readSize = offset - startOffset; return Complete(list); } } // abstraction for serialize protected virtual int? GetCount(TCollection sequence) { var collection = sequence as ICollection; if (collection != null) { return collection.Count; } #if NETSTANDARD else { var c2 = sequence as IReadOnlyCollection; if (c2 != null) { return c2.Count; } } #endif 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); protected abstract void Add(TIntermediate collection, int index, TElement value); 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) { return new TCollection(); } protected override void Add(TCollection collection, int index, TElement value) { collection.Add(value); } } public sealed class LinkedListFormatter : CollectionFormatterBase, LinkedList.Enumerator, LinkedList> { protected override void Add(LinkedList collection, int index, T value) { collection.AddLast(value); } protected override LinkedList Complete(LinkedList intermediateCollection) { return intermediateCollection; } protected override LinkedList Create(int count) { return new LinkedList(); } protected override LinkedList.Enumerator GetSourceEnumerator(LinkedList source) { return source.GetEnumerator(); } } public sealed class QeueueFormatter : CollectionFormatterBase, Queue.Enumerator, Queue> { protected override int? GetCount(Queue sequence) { return sequence.Count; } protected override void Add(Queue collection, int index, T value) { collection.Enqueue(value); } protected override Queue Create(int count) { 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) { // add reverse collection[collection.Length - 1 - index] = value; } protected override T[] Create(int count) { return 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) { collection.Add(value); } protected override HashSet Complete(HashSet intermediateCollection) { return intermediateCollection; } protected override HashSet Create(int count) { return new HashSet(); } 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) { collection[index] = value; } protected override ReadOnlyCollection Complete(T[] intermediateCollection) { return new ReadOnlyCollection(intermediateCollection); } protected override T[] Create(int count) { return new T[count]; } } public sealed class InterfaceListFormatter : CollectionFormatterBase> { protected override void Add(T[] collection, int index, T value) { collection[index] = value; } protected override T[] Create(int count) { return new T[count]; } protected override IList Complete(T[] intermediateCollection) { return intermediateCollection; } } public sealed class InterfaceCollectionFormatter : CollectionFormatterBase> { protected override void Add(T[] collection, int index, T value) { collection[index] = value; } protected override T[] Create(int count) { return new T[count]; } protected override ICollection Complete(T[] intermediateCollection) { return intermediateCollection; } } public sealed class InterfaceEnumerableFormatter : CollectionFormatterBase> { protected override void Add(T[] collection, int index, T value) { collection[index] = value; } protected override T[] Create(int count) { return new T[count]; } protected override IEnumerable Complete(T[] intermediateCollection) { return intermediateCollection; } } // [Key, [Array]] public sealed class InterfaceGroupingFormatter : IMessagePackFormatter> { public int Serialize(ref byte[] bytes, int offset, IGrouping value, IFormatterResolver formatterResolver) { if (value == null) { return MessagePackBinary.WriteNil(ref bytes, offset); } else { var startOffset = offset; offset += MessagePackBinary.WriteArrayHeader(ref bytes, offset, 2); offset += formatterResolver.GetFormatterWithVerify().Serialize(ref bytes, offset, value.Key, formatterResolver); offset += formatterResolver.GetFormatterWithVerify>().Serialize(ref bytes, offset, value, formatterResolver); return offset - startOffset; } } public IGrouping Deserialize(byte[] bytes, int offset, IFormatterResolver formatterResolver, out int readSize) { if (MessagePackBinary.IsNil(bytes, offset)) { readSize = 1; return null; } else { var startOffset = offset; var count = MessagePackBinary.ReadArrayHeader(bytes, offset, out readSize); offset += readSize; if (count != 2) throw new InvalidOperationException("Invalid Grouping format."); var key = formatterResolver.GetFormatterWithVerify().Deserialize(bytes, offset, formatterResolver, out readSize); offset += readSize; var value = formatterResolver.GetFormatterWithVerify>().Deserialize(bytes, offset, formatterResolver, out readSize); offset += readSize; readSize = offset - startOffset; return new Grouping(key, value); } } } public sealed class InterfaceLookupFormatter : CollectionFormatterBase, Dictionary>, ILookup> { protected override void Add(Dictionary> collection, int index, IGrouping value) { collection.Add(value.Key, value); } protected override ILookup Complete(Dictionary> intermediateCollection) { return new Lookup(intermediateCollection); } protected override Dictionary> Create(int count) { return new Dictionary>(count); } } class Grouping : IGrouping { readonly TKey key; readonly IEnumerable elements; public Grouping(TKey key, IEnumerable elements) { this.key = key; this.elements = elements; } public TKey Key { get { return key; } } public IEnumerator GetEnumerator() { return elements.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return elements.GetEnumerator(); } } class Lookup : ILookup { readonly Dictionary> groupings; public Lookup(Dictionary> groupings) { this.groupings = groupings; } public IEnumerable this[TKey key] { get { return groupings[key]; } } public int Count { get { return groupings.Count; } } public bool Contains(TKey key) { return groupings.ContainsKey(key); } public IEnumerator> GetEnumerator() { return groupings.Values.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return groupings.Values.GetEnumerator(); } } // NonGenerics public sealed class NonGenericListFormatter : IMessagePackFormatter where T : class, IList, new() { public int Serialize(ref byte[] bytes, int offset, T value, IFormatterResolver formatterResolver) { if (value == null) { MessagePackBinary.WriteNil(ref bytes, offset); return 1; } var formatter = formatterResolver.GetFormatterWithVerify(); var startOffset = offset; offset += MessagePackBinary.WriteArrayHeader(ref bytes, offset, value.Count); foreach (var item in value) { offset += formatter.Serialize(ref bytes, offset, item, formatterResolver); } return offset - startOffset; } public T Deserialize(byte[] bytes, int offset, IFormatterResolver formatterResolver, out int readSize) { if (MessagePackBinary.IsNil(bytes, offset)) { readSize = 1; return default(T); } var formatter = formatterResolver.GetFormatterWithVerify(); var startOffset = offset; var count = MessagePackBinary.ReadArrayHeader(bytes, offset, out readSize); offset += readSize; var list = new T(); for (int i = 0; i < count; i++) { list.Add(formatter.Deserialize(bytes, offset, formatterResolver, out readSize)); offset += readSize; } readSize = offset - startOffset; return list; } } public sealed class NonGenericInterfaceListFormatter : IMessagePackFormatter { public static readonly IMessagePackFormatter Instance = new NonGenericInterfaceListFormatter(); NonGenericInterfaceListFormatter() { } public int Serialize(ref byte[] bytes, int offset, IList value, IFormatterResolver formatterResolver) { if (value == null) { MessagePackBinary.WriteNil(ref bytes, offset); return 1; } var formatter = formatterResolver.GetFormatterWithVerify(); var startOffset = offset; offset += MessagePackBinary.WriteArrayHeader(ref bytes, offset, value.Count); foreach (var item in value) { offset += formatter.Serialize(ref bytes, offset, item, formatterResolver); } return offset - startOffset; } public IList Deserialize(byte[] bytes, int offset, IFormatterResolver formatterResolver, out int readSize) { if (MessagePackBinary.IsNil(bytes, offset)) { readSize = 1; return default(IList); } var formatter = formatterResolver.GetFormatterWithVerify(); var startOffset = offset; var count = MessagePackBinary.ReadArrayHeader(bytes, offset, out readSize); offset += readSize; var list = new object[count]; for (int i = 0; i < count; i++) { list[i] = formatter.Deserialize(bytes, offset, formatterResolver, out readSize); offset += readSize; } readSize = offset - startOffset; return list; } } public sealed class NonGenericDictionaryFormatter : IMessagePackFormatter where T : class, IDictionary, new() { public int Serialize(ref byte[] bytes, int offset, T value, IFormatterResolver formatterResolver) { if (value == null) { MessagePackBinary.WriteNil(ref bytes, offset); return 1; } var formatter = formatterResolver.GetFormatterWithVerify(); var startOffset = offset; offset += MessagePackBinary.WriteMapHeader(ref bytes, offset, value.Count); foreach (DictionaryEntry item in value) { offset += formatter.Serialize(ref bytes, offset, item.Key, formatterResolver); offset += formatter.Serialize(ref bytes, offset, item.Value, formatterResolver); } return offset - startOffset; } public T Deserialize(byte[] bytes, int offset, IFormatterResolver formatterResolver, out int readSize) { if (MessagePackBinary.IsNil(bytes, offset)) { readSize = 1; return null; } var formatter = formatterResolver.GetFormatterWithVerify(); var startOffset = offset; var count = MessagePackBinary.ReadMapHeader(bytes, offset, out readSize); offset += readSize; var dict = new T(); for (int i = 0; i < count; i++) { var key = formatter.Deserialize(bytes, offset, formatterResolver, out readSize); offset += readSize; var value = formatter.Deserialize(bytes, offset, formatterResolver, out readSize); offset += readSize; dict.Add(key, value); } readSize = offset - startOffset; return dict; } } public sealed class NonGenericInterfaceDictionaryFormatter : IMessagePackFormatter { public static readonly IMessagePackFormatter Instance = new NonGenericInterfaceDictionaryFormatter(); NonGenericInterfaceDictionaryFormatter() { } public int Serialize(ref byte[] bytes, int offset, IDictionary value, IFormatterResolver formatterResolver) { if (value == null) { MessagePackBinary.WriteNil(ref bytes, offset); return 1; } var formatter = formatterResolver.GetFormatterWithVerify(); var startOffset = offset; offset += MessagePackBinary.WriteMapHeader(ref bytes, offset, value.Count); foreach (DictionaryEntry item in value) { offset += formatter.Serialize(ref bytes, offset, item.Key, formatterResolver); offset += formatter.Serialize(ref bytes, offset, item.Value, formatterResolver); } return offset - startOffset; } public IDictionary Deserialize(byte[] bytes, int offset, IFormatterResolver formatterResolver, out int readSize) { if (MessagePackBinary.IsNil(bytes, offset)) { readSize = 1; return null; } var formatter = formatterResolver.GetFormatterWithVerify(); var startOffset = offset; var count = MessagePackBinary.ReadMapHeader(bytes, offset, out readSize); offset += readSize; var dict = new Dictionary(count); for (int i = 0; i < count; i++) { var key = formatter.Deserialize(bytes, offset, formatterResolver, out readSize); offset += readSize; var value = formatter.Deserialize(bytes, offset, formatterResolver, out readSize); offset += readSize; dict.Add(key, value); } readSize = offset - startOffset; return dict; } } #if NETSTANDARD public sealed class ObservableCollectionFormatter : CollectionFormatterBase> { protected override void Add(ObservableCollection collection, int index, T value) { collection.Add(value); } protected override ObservableCollection Create(int count) { return new ObservableCollection(); } } public sealed class ReadOnlyObservableCollectionFormatter : CollectionFormatterBase, ReadOnlyObservableCollection> { protected override void Add(ObservableCollection collection, int index, T value) { collection.Add(value); } protected override ObservableCollection Create(int count) { 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) { collection[index] = value; } protected override T[] Create(int count) { return 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) { collection[index] = value; } protected override T[] Create(int count) { return 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) { collection.Add(value); } protected override ISet Complete(HashSet intermediateCollection) { return intermediateCollection; } protected override HashSet Create(int count) { return new HashSet(); } } public sealed class ConcurrentBagFormatter : CollectionFormatterBase> { protected override int? GetCount(ConcurrentBag sequence) { return sequence.Count; } protected override void Add(ConcurrentBag collection, int index, T value) { collection.Add(value); } protected override ConcurrentBag Create(int count) { 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) { collection.Enqueue(value); } protected override ConcurrentQueue Create(int count) { 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) { // add reverse collection[collection.Length - 1 - index] = value; } protected override T[] Create(int count) { return new T[count]; } protected override ConcurrentStack Complete(T[] intermediateCollection) { return new ConcurrentStack(intermediateCollection); } } #endif }