1 /*
2  * hunt-proton: AMQP Protocol library for D programming language.
3  *
4  * Copyright (C) 2018-2019 HuntLabs
5  *
6  * Website: https://www.huntlabs.net/
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11 
12 module hunt.proton.codec.impl.ListElement;
13 
14 import hunt.proton.codec.impl.AbstractElement;
15 import hunt.proton.codec.impl.Element;
16 import hunt.proton.codec.impl.ArrayElement;
17 import hunt.proton.codec.Data;
18 import hunt.collection.List;
19 import hunt.io.ByteBuffer;
20 import hunt.collection.ArrayList;
21 import std.conv;
22 
23 import hunt.proton.codec.Data;
24 
25 class ListElement : AbstractElement!(List!Object)
26 {
27     private IElement _first;
28 
29     this(IElement parent, IElement prev)
30     {
31         super(parent, prev);
32     }
33 
34     public int count()
35     {
36         int count = 0;
37         IElement elt = _first;
38         while(elt !is null)
39         {
40             count++;
41             elt = elt.next();
42         }
43         return count;
44     }
45 
46 
47     public int size()
48     {
49         int count = 0;
50         int size = 0;
51         IElement elt = _first;
52         while(elt !is null)
53         {
54             count++;
55             size += elt.size();
56             elt = elt.next();
57         }
58         if(isElementOfArray())
59         {
60             ArrayElement parent = cast(ArrayElement) parent();
61             if(parent.constructorType() == ArrayElement.TINY)
62             {
63                 if(count != 0)
64                 {
65                     parent.setConstructorType(ArrayElement.ConstructorType.SMALL);
66                     size += 2;
67                 }
68             }
69             else if(parent.constructorType() == ArrayElement.SMALL)
70             {
71                 if(count > 255 || size > 254)
72                 {
73                     parent.setConstructorType(ArrayElement.ConstructorType.LARGE);
74                     size += 8;
75                 }
76                 else
77                 {
78                     size += 2;
79                 }
80             }
81             else
82             {
83                 size += 8;
84             }
85 
86         }
87         else
88         {
89             if(count == 0)
90             {
91                 size = 1;
92             }
93             else if(count <= 255 && size <= 254)
94             {
95                 size += 3;
96             }
97             else
98             {
99                 size+=9;
100             }
101         }
102 
103         return size;
104     }
105 
106     public Object getValue()
107     {
108         List!Object list = new ArrayList!Object();
109         IElement elt = _first;
110 
111 
112         while(elt !is null)
113         {
114             list.add(elt.getValue());
115             elt = elt.next();
116         }
117 
118         return cast(Object)list;
119     }
120 
121     public Data.DataType getDataType()
122     {
123         return Data.DataType.LIST;
124     }
125 
126     public int encode(ByteBuffer b)
127     {
128         int encodedSize = size();
129 
130         int count = 0;
131         int size = 0;
132         IElement elt = _first;
133         while(elt !is null)
134         {
135             count++;
136             size += elt.size();
137             elt = elt.next();
138         }
139 
140         if(encodedSize > b.remaining())
141         {
142             return 0;
143         }
144         else
145         {
146             if(isElementOfArray())
147             {
148                 switch((cast(ArrayElement)parent()).constructorType())
149                 {
150                     case ArrayElement.ConstructorType.TINY:
151                         break;
152                     case ArrayElement.ConstructorType.SMALL:
153                     {
154                         b.put(cast(byte)(size+1));
155                         b.put(cast(byte)count);
156                         break;
157                     }
158 
159                     case ArrayElement.ConstructorType.LARGE:
160                     {
161                         b.putInt((size+4));
162                         b.putInt(count);
163                         break;
164                     }
165                     default:
166                         break;
167                 }
168             }
169             else
170             {
171                 if(count == 0)
172                 {
173                     b.put(cast(byte)0x45);
174                 }
175                 else if(size <= 254 && count <=255)
176                 {
177                     b.put(cast(byte)0xc0);
178                     b.put(cast(byte)(size+1));
179                     b.put(cast(byte)count);
180                 }
181                 else
182                 {
183                     b.put(cast(byte)0xd0);
184                     b.putInt((size+4));
185                     b.putInt(count);
186                 }
187 
188             }
189 
190             elt = _first;
191             while(elt !is null)
192             {
193                 elt.encode(b);
194                 elt = elt.next();
195             }
196 
197             return encodedSize;
198         }
199     }
200 
201     public bool canEnter()
202     {
203         return true;
204     }
205 
206     public IElement child()
207     {
208         return _first;
209     }
210 
211     public void setChild(IElement elt)
212     {
213         _first = elt;
214     }
215 
216     public IElement checkChild(IElement element)
217     {
218         return element;
219     }
220 
221     public IElement addChild(IElement element)
222     {
223         _first = element;
224         return element;
225     }
226 
227     override
228     string startSymbol() {
229         return "[";
230     }
231 
232     override
233     string stopSymbol() {
234         return "]";
235     }
236 
237 }