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.SymbolMapType; 13 14 import hunt.proton.codec.PrimitiveTypeEncoding; 15 import hunt.proton.codec.AMQPType; 16 import hunt.proton.codec.EncoderImpl; 17 import hunt.proton.codec.DecoderImpl; 18 import hunt.proton.codec.AbstractPrimitiveType; 19 import hunt.collection.Collection; 20 import hunt.collection.Map; 21 import hunt.collection.ArrayList; 22 import hunt.proton.codec.LargeFloatingSizePrimitiveTypeEncoding; 23 import hunt.Exceptions; 24 import hunt.Object; 25 import hunt.collection.Map; 26 import hunt.String; 27 import hunt.proton.codec.TypeEncoding; 28 import hunt.proton.codec.EncodingCodes; 29 import hunt.proton.codec.StringType; 30 import hunt.collection.LinkedHashMap; 31 import hunt.proton.codec.TypeConstructor; 32 import hunt.proton.codec.ReadableBuffer; 33 import hunt.proton.codec.SmallFloatingSizePrimitiveTypeEncoding; 34 import hunt.logging; 35 import std.conv : to; 36 import hunt.proton.amqp.Symbol; 37 import hunt.proton.codec.SymbolType; 38 39 interface MapEncoding : PrimitiveTypeEncoding!(Map!(Symbol,Object)) 40 { 41 void setValue(Map!(Symbol,Object) value, int length); 42 } 43 44 class SymbolMapType : AbstractPrimitiveType!(Map!(Symbol,Object)) 45 { 46 private MapEncoding _mapEncoding; 47 private MapEncoding _shortMapEncoding; 48 private EncoderImpl _encoder; 49 50 //private AMQPType<?> fixedKeyType; 51 52 private IAMQPType fixedKeyType; 53 54 55 this(EncoderImpl encoder, DecoderImpl decoder) 56 { 57 _encoder = encoder; 58 _mapEncoding = new AllMapEncoding(encoder, decoder); 59 _shortMapEncoding = new ShortMapEncoding(encoder, decoder); 60 encoder.register(typeid(LinkedHashMap!(Symbol,Object)), this); 61 decoder.register(this); 62 } 63 64 public TypeInfo getTypeClass() 65 { 66 return typeid(LinkedHashMap!(Symbol,Object)); 67 } 68 69 public void setKeyEncoding(IAMQPType keyType) 70 { 71 this.fixedKeyType = keyType; 72 } 73 74 public ITypeEncoding getEncoding(Object val) 75 { 76 int calculatedSize = calculateSize(cast(Map!(Symbol,Object))val); 77 logInfof("########## %d" , calculatedSize); 78 MapEncoding encoding = ((cast(Map!(Symbol,Object))val).size() > 127 || calculatedSize >= 254) 79 ? _mapEncoding 80 : _shortMapEncoding; 81 82 encoding.setValue(cast(Map!(Symbol,Object))val, calculatedSize); 83 return encoding; 84 } 85 86 private int calculateSize(Map!(Symbol,Object) map) 87 { 88 89 //implementationMissing(false); 90 int len = 0; 91 92 //Iterator<Map.Entry<?, ?>> iter = map.entrySet().iterator(); 93 IAMQPType IfixedKeyType = this.fixedKeyType; 94 95 // Clear existing fixed key type encoding to prevent application to nested Maps 96 setKeyEncoding(null); 97 98 try 99 { 100 foreach (MapEntry!(Symbol, Object) element ; map) 101 { 102 ITypeEncoding elementEncoding; 103 if (IfixedKeyType is null) 104 { 105 IAMQPType tmp = _encoder.getType( element.getKey()); 106 if (tmp is null) 107 { 108 logError( "getType Error"); 109 } 110 111 elementEncoding = tmp.getEncoding( element.getKey()); 112 // elementEncoding = _encoder.getType(element.getKey()).getEncoding(element.getKey()); 113 } 114 else 115 { 116 elementEncoding = IfixedKeyType.getEncoding( element.getKey()); 117 } 118 119 len += elementEncoding.getConstructorSize() + elementEncoding.getValueSize( element.getKey()); 120 121 122 123 124 IAMQPType tmp = (_encoder.getType( element.getValue())); 125 if (tmp is null) 126 { 127 logError( "getType Error"); 128 } 129 ITypeEncoding elementEncodingVal = tmp.getEncoding( element.getValue()); 130 len += elementEncodingVal.getConstructorSize() + elementEncodingVal.getValueSize( element.getValue()); 131 132 133 //if (cast(String)element.getValue() !is null) 134 //{ 135 // StringType tmp = cast(StringType)(_encoder.getType(element.getValue())); 136 // if (tmp is null) 137 // { 138 // logError("getType Error"); 139 // } 140 // 141 // StringEncoding elementEncodingVal = tmp.getEncoding(cast(String)element.getValue()); 142 // len += elementEncodingVal.getConstructorSize() + elementEncodingVal.getValueSize(cast(String)element.getValue()); 143 //}else 144 //{ 145 // logError("unknown type"); 146 //} 147 } 148 } finally { 149 setKeyEncoding(IfixedKeyType); 150 } 151 152 153 //try { 154 // while (iter.hasNext()) 155 // { 156 // Map.Entry<?, ?> element = iter.next(); 157 // TypeEncoding elementEncoding; 158 // 159 // if (fixedKeyType is null) 160 // { 161 // elementEncoding = _encoder.getType(element.getKey()).getEncoding(element.getKey()); 162 // } 163 // else 164 // { 165 // elementEncoding = fixedKeyType.getEncoding(element.getKey()); 166 // } 167 // 168 // len += elementEncoding.getConstructorSize() + elementEncoding.getValueSize(element.getKey()); 169 // elementEncoding = _encoder.getType(element.getValue()).getEncoding(element.getValue()); 170 // len += elementEncoding.getConstructorSize() + elementEncoding.getValueSize(element.getValue()); 171 // } 172 //} finally { 173 // // Reset Existing key type encoding for later encode step or reuse until cleared by caller 174 // setKeyEncoding(fixedKeyType); 175 //} 176 177 //scope(exit) 178 //{ 179 // setKeyEncoding(IfixedKeyType); 180 //} 181 182 return len; 183 } 184 185 186 private static ITypeConstructor findNextDecoder(DecoderImpl decoder, ReadableBuffer buffer, ITypeConstructor previousConstructor) 187 { 188 if (previousConstructor is null) 189 { 190 return decoder.readConstructor(); 191 } 192 else 193 { 194 byte encodingCode = buffer.get(buffer.position()); 195 if (encodingCode == EncodingCodes.DESCRIBED_TYPE_INDICATOR) 196 { 197 return decoder.readConstructor(); 198 } 199 else 200 { 201 IPrimitiveTypeEncoding primitiveConstructor = cast(IPrimitiveTypeEncoding) previousConstructor; 202 if (encodingCode != primitiveConstructor.getEncodingCode()) 203 { 204 return decoder.readConstructor(); 205 } 206 else 207 { 208 // consume the encoding code byte for real 209 encodingCode = buffer.get(); 210 } 211 } 212 } 213 214 return previousConstructor; 215 } 216 217 public MapEncoding getCanonicalEncoding() 218 { 219 return _mapEncoding; 220 } 221 222 223 224 //Collection!(TypeEncoding!(Map!(Symbol,Object))) 225 public Collection!(TypeEncoding!(Map!(Symbol,Object))) getAllEncodings() 226 { 227 ArrayList!(TypeEncoding!(Map!(Symbol,Object))) lst = new ArrayList!(TypeEncoding!(Map!(Symbol,Object)))(); 228 lst.add(_shortMapEncoding); 229 lst.add(_mapEncoding); 230 return lst; 231 // return Arrays.asList(_shortMapEncoding, _mapEncoding); 232 } 233 234 class AllMapEncoding 235 : LargeFloatingSizePrimitiveTypeEncoding!(Map!(Symbol,Object)) 236 , MapEncoding 237 { 238 239 private Map!(Symbol,Object) _value; 240 private int _length; 241 242 this(EncoderImpl encoder, DecoderImpl decoder) 243 { 244 super(encoder, decoder); 245 } 246 247 override 248 protected void writeEncodedValue(Map!(Symbol,Object) map) 249 { 250 getEncoder().getBuffer().ensureRemaining(getSizeBytes() + getEncodedValueSize(map)); 251 getEncoder().writeRaw(2 * map.size()); 252 253 // Iterator<Map.Entry> iter = map.entrySet().iterator(); 254 IAMQPType IfixedKeyType = this.outer.fixedKeyType; 255 256 // Clear existing fixed key type encoding to prevent application to nested Maps 257 setKeyEncoding(null); 258 259 try { 260 foreach (MapEntry!(Symbol, Object) element ; map) 261 { 262 ITypeEncoding elementEncoding; 263 if (IfixedKeyType is null) 264 { 265 SymbolType tmp = cast(SymbolType)(_encoder.getType( element.getKey())); 266 if (tmp is null) 267 { 268 logError( "getType Error"); 269 } 270 271 elementEncoding = tmp.getEncoding( element.getKey()); 272 // elementEncoding = _encoder.getType(element.getKey()).getEncoding(element.getKey()); 273 } 274 else 275 { 276 elementEncoding = IfixedKeyType.getEncoding( element.getKey()); 277 } 278 279 elementEncoding.writeConstructor(); 280 elementEncoding.writeValue( element.getKey()); 281 282 ITypeEncoding elementEncodingVal; 283 elementEncodingVal = _encoder.getType( element.getValue()).getEncoding( element.getValue()); 284 //if (tmp is null) 285 //{ 286 // logError("getType error"); 287 //} 288 // elementEncodingVal = tmp.getEncoding(cast(String)element.getValue()); 289 elementEncodingVal.writeConstructor(); 290 elementEncodingVal.writeValue( element.getValue()); 291 292 //elementEncoding = getEncoder().getType(element.getValue()).getEncoding(element.getValue()); 293 //elementEncoding.writeConstructor(); 294 //elementEncoding.writeValue(element.getValue()); 295 296 } 297 } finally { 298 setKeyEncoding(IfixedKeyType); 299 } 300 301 302 //try { 303 // while (iter.hasNext()) 304 // { 305 // // Map.Entry<?, ?> element = iter.next(); 306 // TypeEncoding elementEncoding; 307 // 308 // if (fixedKeyType is null) 309 // { 310 // elementEncoding = _encoder.getType(element.getKey()).getEncoding(element.getKey()); 311 // } 312 // else 313 // { 314 // elementEncoding = fixedKeyType.getEncoding(element.getKey()); 315 // } 316 // 317 // elementEncoding.writeConstructor(); 318 // elementEncoding.writeValue(element.getKey()); 319 // elementEncoding = getEncoder().getType(element.getValue()).getEncoding(element.getValue()); 320 // elementEncoding.writeConstructor(); 321 // elementEncoding.writeValue(element.getValue()); 322 // } 323 //} finally { 324 // // Reset Existing key type encoding for later encode step or reuse until cleared by caller 325 // setKeyEncoding(fixedKeyType); 326 //} 327 } 328 329 override 330 protected int getEncodedValueSize(Map!(Symbol,Object) val) 331 { 332 return 4 + ((val == _value) ? _length : calculateSize(val)); 333 } 334 335 override 336 public byte getEncodingCode() 337 { 338 return EncodingCodes.MAP32; 339 } 340 341 override 342 public SymbolMapType getType() 343 { 344 return this.outer; 345 } 346 347 override 348 public bool encodesSuperset(TypeEncoding!(Map!(Symbol,Object)) encoding) 349 { 350 return (getType() == encoding.getType()); 351 } 352 353 override 354 public Object readValue() 355 { 356 DecoderImpl decoder = getDecoder(); 357 ReadableBuffer buffer = decoder.getBuffer(); 358 359 int size = decoder.readRawInt(); 360 // todo - limit the decoder with size 361 int count = decoder.readRawInt(); 362 if (count > decoder.getByteBufferRemaining()) { 363 throw new IllegalArgumentException("Map element count " ~ to!string(count) ~" is specified to be greater than the amount of data available ("~ 364 to!string(decoder.getByteBufferRemaining())~ ")"); 365 } 366 367 ITypeConstructor keyConstructor = null; 368 ITypeConstructor valueConstructor = null; 369 370 Map!(Symbol, Object) map = new LinkedHashMap!(Symbol,Object)(count); 371 for(int i = 0; i < count / 2; i++) 372 { 373 keyConstructor = findNextDecoder(decoder, buffer, keyConstructor); 374 if(keyConstructor is null) 375 { 376 // throw new DecodeException("Unknown constructor"); 377 logError("Unknown constructor"); 378 return null; 379 } 380 381 Symbol key = cast(Symbol)keyConstructor.readValue(); 382 383 bool arrayType = false; 384 byte code = buffer.get(buffer.position()); 385 switch (code) 386 { 387 case EncodingCodes.ARRAY8: 388 goto case; 389 case EncodingCodes.ARRAY32: 390 arrayType = true; 391 break; 392 default: 393 break; 394 } 395 396 valueConstructor = findNextDecoder(decoder, buffer, valueConstructor); 397 if (valueConstructor is null) 398 { 399 // throw new DecodeException("Unknown constructor"); 400 logError("Unknown constructor"); 401 return null; 402 } 403 404 Object value; 405 406 //if (arrayType) 407 //{ 408 // value = ((ArrayType.ArrayEncoding) valueConstructor).readValueArray(); 409 //} 410 //else 411 { 412 value = valueConstructor.readValue(); 413 } 414 415 map.put(key, value); 416 } 417 418 return cast(Object)map; 419 } 420 421 override 422 public void skipValue() 423 { 424 DecoderImpl decoder = getDecoder(); 425 ReadableBuffer buffer = decoder.getBuffer(); 426 int size = decoder.readRawInt(); 427 buffer.position(buffer.position() + size); 428 } 429 430 public void setValue(Map!(Symbol,Object) value, int length) 431 { 432 _value = value; 433 _length = length; 434 } 435 436 override 437 void writeConstructor() 438 { 439 super.writeConstructor(); 440 } 441 442 override int getConstructorSize() 443 { 444 return super.getConstructorSize(); 445 } 446 447 448 } 449 450 class ShortMapEncoding 451 : SmallFloatingSizePrimitiveTypeEncoding!(Map!(Symbol,Object)) 452 , MapEncoding 453 { 454 private Map!(Symbol,Object) _value; 455 private int _length; 456 457 this(EncoderImpl encoder, DecoderImpl decoder) 458 { 459 super(encoder, decoder); 460 } 461 462 override 463 protected void writeEncodedValue(Map!(Symbol,Object) map) 464 { 465 getEncoder().getBuffer().ensureRemaining(getSizeBytes() + getEncodedValueSize(map)); 466 getEncoder().writeRaw(cast(byte)(2 * map.size())); 467 468 // Iterator<Map.Entry> iter = map.entrySet().iterator(); 469 470 IAMQPType IfixedKeyType = this.outer.fixedKeyType; 471 472 // Clear existing fixed key type encoding to prevent application to nested Maps 473 setKeyEncoding(null); 474 475 try { 476 foreach (MapEntry!(Symbol, Object) element ; map) 477 { 478 ITypeEncoding elementEncoding; 479 if (IfixedKeyType is null) 480 { 481 IAMQPType tmp = _encoder.getType( element.getKey()); 482 if (tmp is null) 483 { 484 logError( "getType error"); 485 } 486 elementEncoding = tmp.getEncoding( element.getKey()); 487 } 488 else 489 { 490 elementEncoding = IfixedKeyType.getEncoding( element.getKey()); 491 } 492 493 elementEncoding.writeConstructor(); 494 elementEncoding.writeValue( element.getKey()); 495 496 elementEncoding = getEncoder().getType( element.getValue()).getEncoding( element.getValue()); 497 elementEncoding.writeConstructor(); 498 elementEncoding.writeValue( element.getValue()); 499 } 500 }finally { 501 // Reset Existing key type encoding for later encode step or reuse until cleared by caller 502 503 setKeyEncoding(IfixedKeyType); 504 } 505 506 507 //try { 508 // while (iter.hasNext()) 509 // { 510 // Map.Entry<?, ?> element = iter.next(); 511 // TypeEncoding elementEncoding; 512 // 513 // if (fixedKeyType is null) 514 // { 515 // elementEncoding = _encoder.getType(element.getKey()).getEncoding(element.getKey()); 516 // } 517 // else 518 // { 519 // elementEncoding = fixedKeyType.getEncoding(element.getKey()); 520 // } 521 // 522 // elementEncoding.writeConstructor(); 523 // elementEncoding.writeValue(element.getKey()); 524 // elementEncoding = getEncoder().getType(element.getValue()).getEncoding(element.getValue()); 525 // elementEncoding.writeConstructor(); 526 // elementEncoding.writeValue(element.getValue()); 527 // } 528 529 } 530 531 override 532 protected int getEncodedValueSize(Map!(Symbol,Object) val) 533 { 534 return 1 + ((val == _value) ? _length : calculateSize(val)); 535 } 536 537 override 538 public byte getEncodingCode() 539 { 540 return EncodingCodes.MAP8; 541 } 542 543 override 544 public SymbolMapType getType() 545 { 546 return this.outer; 547 } 548 549 override 550 public bool encodesSuperset(TypeEncoding!(Map!(Symbol,Object)) encoder) 551 { 552 return encoder == this; 553 } 554 555 override 556 public Object readValue() 557 { 558 DecoderImpl decoder = getDecoder(); 559 ReadableBuffer buffer = decoder.getBuffer(); 560 561 int size = (decoder.readRawByte()) & 0xff; 562 // todo - limit the decoder with size 563 int count = (decoder.readRawByte()) & 0xff; 564 565 ITypeConstructor keyConstructor = null; 566 ITypeConstructor valueConstructor = null; 567 568 Map!(Symbol, Object) map = new LinkedHashMap!(Symbol, Object)(count); 569 for(int i = 0; i < count / 2; i++) 570 { 571 keyConstructor = findNextDecoder(decoder, buffer, keyConstructor); 572 if(keyConstructor is null) 573 { 574 logError("Unknown constructor"); 575 return null; 576 // throw new DecodeException("Unknown constructor"); 577 } 578 579 Symbol key = cast(Symbol)keyConstructor.readValue(); 580 581 bool arrayType = false; 582 byte code = buffer.get(buffer.position()); 583 switch (code) 584 { 585 case EncodingCodes.ARRAY8: 586 goto case; 587 case EncodingCodes.ARRAY32: 588 arrayType = true; 589 break; 590 default: 591 break; 592 } 593 594 valueConstructor = findNextDecoder(decoder, buffer, valueConstructor); 595 if(valueConstructor is null) 596 { 597 //throw new DecodeException("Unknown constructor"); 598 logError("Unknown constructor"); 599 return null; 600 } 601 602 Object value; 603 604 //if (arrayType) 605 //{ 606 // value = ((ArrayType.ArrayEncoding) valueConstructor).readValueArray(); 607 //} 608 //else 609 { 610 value = valueConstructor.readValue(); 611 } 612 613 map.put(key, value); 614 } 615 616 return cast(Object)map; 617 } 618 619 override 620 public void skipValue() 621 { 622 DecoderImpl decoder = getDecoder(); 623 ReadableBuffer buffer = decoder.getBuffer(); 624 int size = (cast(int)decoder.readRawByte()) & 0xff; 625 buffer.position(buffer.position() + size); 626 } 627 628 public void setValue(Map!(Symbol,Object) value, int length) 629 { 630 _value = value; 631 _length = length; 632 } 633 634 override 635 void writeConstructor() 636 { 637 super.writeConstructor(); 638 } 639 640 override int getConstructorSize() 641 { 642 return super.getConstructorSize(); 643 } 644 } 645 } 646