src/Proton.TestPeer/Codec/Impl/MapElement.cs (183 lines of code) (raw):

/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System.Collections; using System.IO; namespace Apache.Qpid.Proton.Test.Driver.Codec.Impl { public class MapElement : AbstractElement { private IElement first; internal MapElement(IElement parent, IElement prev) : base(parent, prev) { } public override uint GetSize() { return ComputeSize(); } public uint Count { get { uint count = 0; IElement elt = first; while (elt != null) { count++; elt = elt.Next; } return count; } } public override object Value => MapValue; public IDictionary MapValue { get { IDictionary map = new Hashtable(); IElement elt = first; while (elt != null) { object key = elt.Value; object value; elt = elt.Next; if (elt != null) { value = elt.Value; elt = elt.Next; } else { value = null; } map.Add(key, value); } return map; } } public override DataType DataType => DataType.Map; public override IElement Child { get => first; set => first = value; } public override bool CanEnter => true; public override IElement AddChild(IElement element) { return first = element; } public override IElement CheckChild(IElement element) { return element; } public override uint Encode(Stream stream) { uint encodedSize = ComputeSize(); uint count = 0; uint size = 0; IElement elt = first; while (elt != null) { count++; size += elt.GetSize(); elt = elt.Next; } if (!stream.IsWritable()) { return 0; } else { if (IsElementOfArray()) { switch (((ArrayElement)Parent).ConstructorType) { case ConstructorType.Small: stream.WriteByte((byte)(size + 1)); stream.WriteByte((byte)count); break; case ConstructorType.Large: stream.WriteUnsignedInt(size + 4); stream.WriteUnsignedInt(count); break; case ConstructorType.Tiny: break; default: break; } } else { if (size <= 254 && count <= 255) { stream.WriteByte(0xc1); stream.WriteByte((byte)(size + 1)); stream.WriteByte((byte)count); } else { stream.WriteByte(0xd1); stream.WriteUnsignedInt(size + 4); stream.WriteUnsignedInt(count); } } elt = first; while (elt != null) { elt.Encode(stream); elt = elt.Next; } return encodedSize; } } internal override string StartSymbol() { return "{"; } internal override string StopSymbol() { return "}"; } private uint ComputeSize() { uint count = 0; uint size = 0; IElement elt = first; while (elt != null) { count++; size += elt.GetSize(); elt = elt.Next; } if (IsElementOfArray()) { ArrayElement parent = (ArrayElement)Parent; if (parent.ConstructorType == ConstructorType.Small) { if (count > 255 || size > 254) { parent.ConstructorType = ConstructorType.Large; size += 8; } else { size += 2; } } else { size += 8; } } else { if (count <= 255 && size <= 254) { size += 3; } else { size += 9; } } return size; } } }