src/Encoding/EncodingBase.cs (105 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.Encoding { using System; using System.Diagnostics; /// <summary> /// Implements the AMQP type system. /// </summary> /// /// Notes for encoding design and implementation. /// * Each AMQP type implements EncodingBase of T. /// * The encoding methods should be in static methods so that they /// can be called directly when the type is known and probably inlined. /// * Encoding implementations do not deal with null values, except /// for those struct types (e.g. AmqpSymbol) which cannot be null /// checked when the value is an object. Null check is handed in /// AmqpCodec. AmqpCodec should be used always except when the type /// is known and the value is not null. /// * Encoding methods should allow custom type to encode any types /// (e.g. IList in Multiple) as arrays. The array specific methods /// allow fast encoding of large arrays. /// * When a type is not known, AmqpEncoding can lookup the encoding by /// Type or FormatCode. The IEncoding implementations handle encoding /// of an object efficiently because they know the concrete type. /// * GetEncodeSize does not have to be exact but it must be greater /// than the actual size and be as close as possible. /// interface IEncoding { FormatCode FormatCode { get; } // if arrayIndex >= 0, it is encoding an item in the array int GetSize(object obj, int arrayIndex = -1); void Write(object obj, ByteBuffer buffer, int arrayIndex = -1); object Read(ByteBuffer buffer, FormatCode formatCode); int GetArraySize(Array array); void WriteArray(Array array, ByteBuffer buffer); Array ReadArray(ByteBuffer buffer, FormatCode formatCode, int count); } /// <summary> /// Encodes and decodes amqp types. /// </summary> /// <remarks>This should be used by AmqpCodec only, where null values are handled.</remarks> abstract class EncodingBase<T> : IEncoding { readonly FormatCode formatCode; readonly int width; // -1 for variable and compact-enabled types protected EncodingBase(FormatCode formatCode, int width = -1) { this.formatCode = formatCode; this.width = width; } public FormatCode FormatCode { get { return this.formatCode; } } public int GetSize(T value, int arrayIndex = -1) { return this.width > 0 ? FixedWidth.FormatCode + this.width : this.OnGetSize(value, arrayIndex); } public void Write(T value, ByteBuffer buffer, int arrayIndex = -1) { this.OnWrite(value, buffer, arrayIndex); } public T Read(ByteBuffer buffer, FormatCode formatCode) { return this.OnRead(buffer, formatCode); } // Provide default implementations. Override them if possible for better performance. public virtual int GetArrayValueSize(T[] array) { if (this.width > 0) { return this.width * array.Length; } int size = 0; for (int i = 0; i < array.Length; i++) { size += this.GetSize(array[i], i); } return size; } public virtual void WriteArrayValue(T[] array, ByteBuffer buffer) { for (int i = 0; i < array.Length; i++) { this.Write(array[i], buffer, i); } } public virtual T[] ReadArrayValue(ByteBuffer buffer, FormatCode formatCode, T[] array) { for (int i = 0; i < array.Length; i++) { array[i] = this.Read(buffer, formatCode); } return array; } protected abstract int OnGetSize(T value, int arrayIndex); protected abstract void OnWrite(T value, ByteBuffer buffer, int arrayIndex); protected abstract T OnRead(ByteBuffer buffer, FormatCode formatCode); int IEncoding.GetSize(object obj, int arrayIndex) { Debug.Assert(obj != null); return this.GetSize((T)obj, arrayIndex); } void IEncoding.Write(object obj, ByteBuffer buffer, int arrayIndex) { Debug.Assert(obj != null); this.Write((T)obj, buffer, arrayIndex); } object IEncoding.Read(ByteBuffer buffer, FormatCode formatCode) { Debug.Assert(formatCode != FormatCode.Null); return this.Read(buffer, formatCode); } int IEncoding.GetArraySize(Array array) { return ArrayEncoding.GetEncodeSize((T[])array, this); } void IEncoding.WriteArray(Array array, ByteBuffer buffer) { ArrayEncoding.Encode(buffer, (T[])array, this); } Array IEncoding.ReadArray(ByteBuffer buffer, FormatCode formatCode, int count) { T[] array = new T[count]; if (count > 0) { array = this.ReadArrayValue(buffer, formatCode, array); } return array; } } }