src/Framing/Multiple.cs (121 lines of code) (raw):

// Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. namespace Microsoft.Azure.Amqp.Framing { using System.Collections.Generic; using System.Text; using Microsoft.Azure.Amqp.Encoding; /// <summary> /// Represents one or multiple object of T. /// </summary> /// <remarks>Multiple is not an AMQP data type. It is an encoding property. /// When there is only one T object, it is encoded as a single T object. /// When there are multiple T objects, it is encoded as an array of T. /// Examples are <see cref="Open.OfferedCapabilities"/> and <see cref="Source.Capabilities"/></remarks> public sealed class Multiple<T> : List<T> { static readonly EncodingBase<T> encoding = AmqpEncoding.GetEncoding<T>(); /// <summary> /// Initializes a Multiple object. /// </summary> public Multiple() { } /// <summary> /// Initializes a Multiple object with a list of objects. /// </summary> /// <param name="value">The list of objects to add to the Multiple object.</param> public Multiple(IList<T> value) : base(value.Count) { for (int i = 0; i < value.Count; i++) { this.Add(value[i]); } } Multiple(int capacity) : base(capacity) { } internal static int GetEncodeSize(Multiple<T> multiple) { if (multiple == null) { return FixedWidth.NullEncoded; } if (multiple.Count == 1) { return encoding.GetSize(multiple[0]); } // encoded as array32 int size = ArrayEncoding.PrefixSize; for (int i = 0; i < multiple.Count; i++) { size += encoding.GetSize(multiple[i], i); } return size; } internal static void Encode(Multiple<T> multiple, ByteBuffer buffer) { if (multiple == null) { AmqpEncoding.EncodeNull(buffer); } else if (multiple.Count == 1) { encoding.Write(multiple[0], buffer); } else { AmqpBitConverter.WriteUByte(buffer, FormatCode.Array32); var tracker = SizeTracker.Track(buffer); AmqpBitConverter.WriteUInt(buffer, FixedWidth.Int); // size AmqpBitConverter.WriteInt(buffer, multiple.Count); // count AmqpBitConverter.WriteUByte(buffer, encoding.FormatCode); for (int i = 0; i < multiple.Count; i++) { encoding.Write(multiple[i], buffer, i); } tracker.CommitExclusive(0); } } internal static Multiple<T> Decode(ByteBuffer buffer) { FormatCode formatCode = AmqpEncoding.ReadFormatCode(buffer); if (formatCode == FormatCode.Null) { return null; } if (formatCode != FormatCode.Array8 && formatCode != FormatCode.Array32) { T item = encoding.Read(buffer, formatCode); return new Multiple<T>(1) { item }; } AmqpEncoding.ReadSizeAndCount(buffer, formatCode, FormatCode.Array8, FormatCode.Array32, out int size, out int count); Multiple<T> multiple = new Multiple<T>(count); formatCode = AmqpEncoding.ReadFormatCode(buffer); for (int i = 0; i < count; i++) { T item = encoding.Read(buffer, formatCode); multiple.Add(item); } return multiple; } /// <summary> /// Returns a new Multiple object that contains items in both Multiple objects. /// </summary> /// <param name="multiple1">The first Multiple object.</param> /// <param name="multiple2">The second Multiple object.</param> /// <returns>A Multiple object that contains items in both Multiple objects.</returns> public static IList<T> Intersect(Multiple<T> multiple1, Multiple<T> multiple2) { List<T> list = new List<T>(); if (multiple1 == null || multiple2 == null) { return list; } for (var index = 0; index < multiple1.Count; index++) { T t1 = multiple1[index]; if (multiple2.Contains(t1)) { list.Add(t1); } } return list; } /// <summary> /// Returns a string that represents the object. /// </summary> /// <returns>The string representation.</returns> public override string ToString() { StringBuilder sb = new StringBuilder("["); bool firstItem = true; foreach (var item in this) { if (!firstItem) { sb.Append(','); } sb.Append(item); firstItem = false; } sb.Append(']'); return sb.ToString(); } } }