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 }