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.ArrayElement;
13 
14 import hunt.proton.codec.impl.LongElement;
15 import hunt.proton.codec.impl.ShortElement;
16 import hunt.proton.codec.impl.IntegerElement;
17 import hunt.proton.codec.impl.ByteElement;
18 import hunt.proton.codec.impl.AbstractElement;
19 import hunt.proton.codec.impl.Element;
20 import hunt.proton.codec.impl.ArrayElement;
21 import hunt.proton.codec.Data;
22 import hunt.proton.codec.impl.DescribedTypeImpl;
23 import hunt.proton.codec.impl.SymbolElement;
24 import hunt.collection.Map;
25 import hunt.io.ByteBuffer;
26 import std.conv;
27 
28 import hunt.proton.amqp.DescribedType;
29 import hunt.proton.amqp.Symbol;
30 import hunt.proton.codec.Data;
31 import hunt.Exceptions;
32 import hunt.Integer;
33 import hunt.Long;
34 import hunt.collection.List;
35 import hunt.collection.ArrayList;
36 import hunt.Byte;
37 import hunt.Long;
38 import hunt.Short;
39 import hunt.Integer;
40 
41 class ArrayElement : AbstractElement!(List!Object)
42 {
43 
44     private bool _described;
45     private Data.DataType _arrayType;
46     private ConstructorType _constructorType;
47     private IElement _first;
48 
49 
50     enum ConstructorType { TINY, SMALL, LARGE }
51 
52 
53     enum ConstructorType TINY = ConstructorType.TINY;
54     enum ConstructorType SMALL = ConstructorType.SMALL;
55     enum ConstructorType LARGE = ConstructorType.LARGE;
56 
57     this(IElement parent, IElement prev, bool described, Data.DataType type)
58     {
59         super(parent, prev);
60         _described = described;
61         _arrayType = type;
62         if(_arrayType == Data.DataType.NULL)
63         {
64             throw new NullPointerException("Array type cannot be null");
65         }
66         else if(_arrayType == Data.DataType.DESCRIBED)
67         {
68             throw new IllegalArgumentException("Array type cannot be DESCRIBED");
69         }
70         switch(_arrayType)
71         {
72             case Data.DataType.UINT:
73                  goto case;
74             case Data.DataType.ULONG:
75                  goto case;
76             case Data.DataType.LIST:
77                 setConstructorType(TINY);
78                 break;
79             default:
80                 setConstructorType(SMALL);
81                 break;
82         }
83     }
84 
85     ConstructorType constructorType()
86     {
87         return _constructorType;
88     }
89 
90     void setConstructorType(ConstructorType type)
91     {
92         _constructorType = type;
93     }
94 
95     public int size()
96     {
97         ConstructorType oldConstructorType;
98         int bodySize;
99         int count = 0;
100         do
101         {
102             bodySize = 1; // data type constructor
103             oldConstructorType = _constructorType;
104             IElement element = _first;
105             while(element !is null)
106             {
107                 count++;
108                 bodySize += element.size();
109                 element = element.next();
110             }
111         }
112         while (oldConstructorType != constructorType());
113 
114         if(isDescribed())
115         {
116             bodySize++; // 00 instruction
117             if(count != 0)
118             {
119                 count--;
120             }
121         }
122 
123         if(isElementOfArray())
124         {
125             ArrayElement parent = cast(ArrayElement)parent();
126             if(parent.constructorType()==SMALL)
127             {
128                 if(count<=255 && bodySize<=254)
129                 {
130                     bodySize+=2;
131                 }
132                 else
133                 {
134                     parent.setConstructorType(LARGE);
135                     bodySize+=8;
136                 }
137             }
138             else
139             {
140                 bodySize+=8;
141             }
142         }
143         else
144         {
145 
146             if(count<=255 && bodySize<=254)
147             {
148                 bodySize+=3;
149             }
150             else
151             {
152                 bodySize+=9;
153             }
154 
155         }
156 
157 
158         return bodySize;
159     }
160 
161     public Object getValue()
162     {
163         //implementationMissing(false);
164         //return null;
165         if(isDescribed())
166         {
167            // DescribedType[] rVal = new DescribedType[cast(int) count()];
168             List!Object rVal = new ArrayList!Object;
169             Object descriptor = _first is null ? null : _first.getValue();
170             IElement element = _first is null ? null : _first.next();
171             int i = 0;
172             while(element !is null)
173             {
174                 rVal.add(new DescribedTypeImpl(descriptor, element.getValue()));
175                 element = element.next();
176             }
177             return cast(Object)rVal;
178         }
179         else if(_arrayType == Data.DataType.SYMBOL)
180         {
181             List!Object rVal = new ArrayList!Object;
182             SymbolElement element = cast(SymbolElement) _first;
183             int i = 0;
184             while (element !is null)
185             {
186                 rVal.add (element.getValue());
187                 element = cast(SymbolElement) element.next();
188             }
189             return cast(Object)rVal;
190         }
191         else
192         {
193             List!Object rVal = new ArrayList!Object;
194             IElement element = _first;
195             int i = 0;
196             while (element !is null)
197             {
198                 rVal.add(element.getValue());
199                 element = element.next();
200             }
201             return cast(Object)rVal;
202         }
203     }
204 
205     public Data.DataType getDataType()
206     {
207         return Data.DataType.ARRAY;
208     }
209 
210     public int encode(ByteBuffer b)
211     {
212         int size = size();
213 
214         int count = cast(int) count();
215 
216         if(b.remaining()>=size)
217         {
218             if(!isElementOfArray())
219             {
220                 if(size>257 || count >255)
221                 {
222                     b.put(cast(byte)0xf0);
223                     b.putInt(size-5);
224                     b.putInt(count);
225                 }
226                 else
227                 {
228                     b.put(cast(byte)0xe0);
229                     b.put(cast(byte)(size-2));
230                     b.put(cast(byte)count);
231                 }
232             }
233             else
234             {
235                 ArrayElement parent = cast(ArrayElement)parent();
236                 if(parent.constructorType()==SMALL)
237                 {
238                     b.put(cast(byte)(size-1));
239                     b.put(cast(byte)count);
240                 }
241                 else
242                 {
243                     b.putInt(size-4);
244                     b.putInt(count);
245                 }
246             }
247             IElement element = _first;
248             if(isDescribed())
249             {
250                 b.put(cast(byte)0);
251                 if(element is null)
252                 {
253                     b.put(cast(byte)0x40);
254                 }
255                 else
256                 {
257                     element.encode(b);
258                     element = element.next();
259                 }
260             }
261             switch(_arrayType)
262             {
263                 case Data.DataType.NULL:
264                     b.put(cast(byte)0x40);
265                     break;
266                 case Data.DataType.BOOL:
267                     b.put(cast(byte)0x56);
268                     break;
269                 case Data.DataType.UBYTE:
270                     b.put(cast(byte)0x50);
271                     break;
272                 case Data.DataType.BYTE:
273                     b.put(cast(byte)0x51);
274                     break;
275                 case Data.DataType.USHORT:
276                     b.put(cast(byte)0x60);
277                     break;
278                 case Data.DataType.SHORT:
279                     b.put(cast(byte)0x61);
280                     break;
281                 case Data.DataType.UINT:
282                     switch (constructorType())
283                     {
284                         case TINY:
285                             b.put(cast(byte)0x43);
286                             break;
287                         case SMALL:
288                             b.put(cast(byte)0x52);
289                             break;
290                         case LARGE:
291                             b.put(cast(byte)0x70);
292                             break;
293                         default:
294                             break;
295                     }
296                     break;
297                 case Data.DataType.INT:
298                     b.put(_constructorType == SMALL ? cast(byte)0x54 : cast(byte)0x71);
299                     break;
300                 case Data.DataType.CHAR:
301                     b.put(cast(byte)0x73);
302                     break;
303                 case Data.DataType.ULONG:
304                     switch (constructorType())
305                     {
306                         case TINY:
307                             b.put(cast(byte)0x44);
308                             break;
309                         case SMALL:
310                             b.put(cast(byte)0x53);
311                             break;
312                         case LARGE:
313                             b.put(cast(byte)0x80);
314                             break;
315                         default:
316                             break;
317                     }
318                     break;
319                 case Data.DataType.LONG:
320                     b.put(_constructorType == SMALL ? cast(byte)0x55 : cast(byte)0x81);
321                     break;
322                 case Data.DataType.TIMESTAMP:
323                     b.put(cast(byte)0x83);
324                     break;
325                 case Data.DataType.FLOAT:
326                     b.put(cast(byte)0x72);
327                     break;
328                 case Data.DataType.DOUBLE:
329                     b.put(cast(byte)0x82);
330                     break;
331                 case Data.DataType.DECIMAL32:
332                     b.put(cast(byte)0x74);
333                     break;
334                 case Data.DataType.DECIMAL64:
335                     b.put(cast(byte)0x84);
336                     break;
337                 case Data.DataType.DECIMAL128:
338                     b.put(cast(byte)0x94);
339                     break;
340                 case Data.DataType.UUID:
341                     b.put(cast(byte)0x98);
342                     break;
343                 case Data.DataType.BINARY:
344                     b.put(_constructorType == SMALL ? cast(byte)0xa0 : cast(byte)0xb0);
345                     break;
346                 case Data.DataType.STRING:
347                     b.put(_constructorType == SMALL ? cast(byte)0xa1 : cast(byte)0xb1);
348                     break;
349                 case Data.DataType.SYMBOL:
350                     b.put(_constructorType == SMALL ? cast(byte)0xa3 : cast(byte)0xb3);
351                     break;
352                 case Data.DataType.ARRAY:
353                     b.put(_constructorType == SMALL ? cast(byte)0xe0 : cast(byte)0xf0);
354                     break;
355                 case Data.DataType.LIST:
356                     b.put(_constructorType == TINY ? cast(byte)0x45 :_constructorType == SMALL ? cast(byte)0xc0 : cast(byte)0xd0);
357                     break;
358                 case Data.DataType.MAP:
359                     b.put(_constructorType == SMALL ? cast(byte)0xc1 : cast(byte)0xd1);
360                     break;
361                 default:
362                     break;
363             }
364             while(element !is null)
365             {
366                 element.encode(b);
367                 element = element.next();
368             }
369             return size;
370         }
371         else
372         {
373             return 0;
374         }
375     }
376 
377     public bool canEnter()
378     {
379         return true;
380     }
381 
382     public IElement child()
383     {
384         return _first;
385     }
386 
387     public void setChild(IElement elt)
388     {
389         _first = elt;
390     }
391 
392     public IElement  addChild(IElement  element)
393     {
394         if(isDescribed() || element.getDataType() == _arrayType)
395         {
396             _first =  element;
397             return element;
398         }
399         else
400         {
401             IElement replacement = coerce(element);
402             if(replacement !is null)
403             {
404                 _first = replacement;
405                 return replacement;
406             }
407             throw new IllegalArgumentException("Attempting to add instance of " ~ to!string(element.getDataType()) ~ " to array of " ~ to!string(_arrayType));
408         }
409     }
410 
411     private IElement coerce(IElement element)
412     {
413         //implementationMissing(false);
414         //return null;
415         switch (_arrayType)
416         {
417         case Data.DataType.INT:
418             int i;
419             switch (element.getDataType())
420             {
421             case Data.DataType.BYTE:
422                 i = (cast(Byte)(element.getValue())).intValue();
423                 break;
424             case Data.DataType.SHORT:
425                 i = (cast(Short)element.getValue()).intValue();
426                 break;
427             case Data.DataType.LONG:
428                 i = (cast(Long)element.getValue()).intValue();
429                 break;
430             default:
431                 return null;
432             }
433             return new IntegerElement(cast(Element!Integer)element.parent(),cast(Element!Integer)element.prev(),i);
434 
435         case Data.DataType.LONG:
436             long l;
437             switch (element.getDataType())
438             {
439             case Data.DataType.BYTE:
440                 l = (cast(Byte)element.getValue()).longValue();
441                 break;
442             case Data.DataType.SHORT:
443                 l = (cast(Short)element.getValue()).longValue();
444                 break;
445             case Data.DataType.INT:
446                 l = (cast(Integer)element.getValue()).longValue();
447                 break;
448             default:
449                 return null;
450             }
451            // return new LongElement(element.parent(),element.prev(),l);
452             return new LongElement(element.parent(),element.prev(),l);
453         default:
454             return null;
455         }
456     }
457 
458     public IElement checkChild(IElement element)
459     {
460         //implementationMissing(false);
461         //return null;
462         if(element.getDataType() != _arrayType)
463         {
464             IElement replacement = coerce(element);
465             if(replacement !is null)
466             {
467                 return replacement;
468             }
469             throw new IllegalArgumentException("Attempting to add instance of " ~ to!string(element.getDataType()) ~ " to array of " ~ to!string(_arrayType));
470         }
471         return element;
472     }
473 
474 
475     public long count()
476     {
477         int count = 0;
478         IElement elt = _first;
479         while(elt !is null)
480         {
481             count++;
482             elt = elt.next();
483         }
484         if(isDescribed() && count != 0)
485         {
486             count--;
487         }
488         return count;
489         //implementationMissing(false);
490         //return 0;
491     }
492 
493     public bool isDescribed()
494     {
495         return _described;
496     }
497 
498 
499     public Data.DataType getArrayDataType()
500     {
501         return _arrayType;
502     }
503 
504     override
505     string startSymbol() {
506         //return String.format("%s%s[", isDescribed() ? "D" : "", getArrayDataType());
507         return "";
508     }
509 
510     override
511     string stopSymbol() {
512         return "]";
513     }
514 
515 }