1 module hunt.proton.codec.ObjectMapType; 2 3 import std.stdio; 4 5 /* 6 * hunt-proton: AMQP Protocol library for D programming language. 7 * 8 * Copyright (C) 2018-2019 HuntLabs 9 * 10 * Website: https://www.huntlabs.net/ 11 * 12 * Licensed under the Apache-2.0 License. 13 * 14 */ 15 import hunt.proton.codec.PrimitiveTypeEncoding; 16 import hunt.proton.codec.AMQPType; 17 import hunt.proton.codec.EncoderImpl; 18 import hunt.proton.codec.DecoderImpl; 19 import hunt.proton.codec.AbstractPrimitiveType; 20 import hunt.collection.Collection; 21 import hunt.collection.Map; 22 import hunt.collection.ArrayList; 23 import hunt.proton.codec.LargeFloatingSizePrimitiveTypeEncoding; 24 import hunt.Exceptions; 25 import hunt.Object; 26 import hunt.collection.Map; 27 import hunt.String; 28 import hunt.proton.codec.TypeEncoding; 29 import hunt.proton.codec.EncodingCodes; 30 import hunt.proton.codec.StringType; 31 import hunt.collection.LinkedHashMap; 32 import hunt.proton.codec.TypeConstructor; 33 import hunt.proton.codec.ReadableBuffer; 34 import hunt.proton.codec.SmallFloatingSizePrimitiveTypeEncoding; 35 import hunt.logging; 36 import std.conv : to; 37 38 interface MapEncoding : PrimitiveTypeEncoding!(Map!(Object,Object)) 39 { 40 void setValue(Map!(Object,Object) value, int length); 41 } 42 43 class ObjectMapType : AbstractPrimitiveType!(Map!(Object,Object)) 44 { 45 private MapEncoding _mapEncoding; 46 private MapEncoding _shortMapEncoding; 47 private EncoderImpl _encoder; 48 49 //private AMQPType<?> fixedKeyType; 50 51 private IAMQPType fixedKeyType; 52 53 54 this(EncoderImpl encoder, DecoderImpl decoder) 55 { 56 _encoder = encoder; 57 _mapEncoding = new AllMapEncoding(encoder, decoder); 58 _shortMapEncoding = new ShortMapEncoding(encoder, decoder); 59 encoder.register(typeid(LinkedHashMap!(Object,Object)), this); 60 decoder.register(this); 61 } 62 63 public TypeInfo getTypeClass() 64 { 65 return typeid(LinkedHashMap!(Object,Object)); 66 } 67 68 public void setKeyEncoding(IAMQPType keyType) 69 { 70 this.fixedKeyType = keyType; 71 } 72 73 public ITypeEncoding getEncoding(Object val) 74 { 75 int calculatedSize = calculateSize(cast(Map!(Object,Object))val); 76 MapEncoding encoding = ((cast(Map!(Object,Object))val).size() > 127 || calculatedSize >= 254) 77 ? _mapEncoding 78 : _shortMapEncoding; 79 80 encoding.setValue(cast(Map!(Object,Object))val, calculatedSize); 81 return encoding; 82 } 83 84 private int calculateSize(Map!(Object,Object) map) 85 { 86 87 //implementationMissing(false); 88 int len = 0; 89 90 //Iterator<Map.Entry<?, ?>> iter = map.entrySet().iterator(); 91 IAMQPType IfixedKeyType = this.fixedKeyType; 92 93 // Clear existing fixed key type encoding to prevent application to nested Maps 94 setKeyEncoding(null); 95 96 try 97 { 98 99 foreach (MapEntry!(Object, Object) element ; map) 100 { 101 ITypeEncoding elementEncoding; 102 if (IfixedKeyType is null) 103 { 104 IAMQPType tmp = _encoder.getType( element.getKey()); 105 if (tmp is null) 106 { 107 logError( "getType Error"); 108 } 109 110 elementEncoding = tmp.getEncoding( element.getKey()); 111 // elementEncoding = _encoder.getType(element.getKey()).getEncoding(element.getKey()); 112 } 113 else 114 { 115 elementEncoding = IfixedKeyType.getEncoding( element.getKey()); 116 } 117 118 len += elementEncoding.getConstructorSize() + elementEncoding.getValueSize( element.getKey()); 119 120 121 122 123 IAMQPType tmp = (_encoder.getType( element.getValue())); 124 if (tmp is null) 125 { 126 logError( "getType Error"); 127 } 128 ITypeEncoding elementEncodingVal = tmp.getEncoding( element.getValue()); 129 len += elementEncodingVal.getConstructorSize() + elementEncodingVal.getValueSize( element.getValue()); 130 131 132 //if (cast(String)element.getValue() !is null) 133 //{ 134 // StringType tmp = cast(StringType)(_encoder.getType(element.getValue())); 135 // if (tmp is null) 136 // { 137 // logError("getType Error"); 138 // } 139 // 140 // StringEncoding elementEncodingVal = tmp.getEncoding(cast(String)element.getValue()); 141 // len += elementEncodingVal.getConstructorSize() + elementEncodingVal.getValueSize(cast(String)element.getValue()); 142 //}else 143 //{ 144 // logError("unknown type"); 145 //} 146 } 147 } finally { 148 setKeyEncoding(IfixedKeyType); 149 } 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!(Object,Object))) 225 public Collection!(TypeEncoding!(Map!(Object,Object))) getAllEncodings() 226 { 227 ArrayList!(TypeEncoding!(Map!(Object,Object))) lst = new ArrayList!(TypeEncoding!(Map!(Object,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!(Object,Object)) 236 , MapEncoding 237 { 238 239 private Map!(Object,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!(Object,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 { 261 foreach (MapEntry!(Object, Object) element ; map) 262 { 263 ITypeEncoding elementEncoding; 264 if (IfixedKeyType is null) 265 { 266 elementEncoding = (_encoder.getType( element.getKey())).getEncoding( element.getKey()); 267 if (elementEncoding is null) 268 { 269 logError( "getType Error"); 270 } 271 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 //try { 302 // while (iter.hasNext()) 303 // { 304 // // Map.Entry<?, ?> element = iter.next(); 305 // TypeEncoding elementEncoding; 306 // 307 // if (fixedKeyType is null) 308 // { 309 // elementEncoding = _encoder.getType(element.getKey()).getEncoding(element.getKey()); 310 // } 311 // else 312 // { 313 // elementEncoding = fixedKeyType.getEncoding(element.getKey()); 314 // } 315 // 316 // elementEncoding.writeConstructor(); 317 // elementEncoding.writeValue(element.getKey()); 318 // elementEncoding = getEncoder().getType(element.getValue()).getEncoding(element.getValue()); 319 // elementEncoding.writeConstructor(); 320 // elementEncoding.writeValue(element.getValue()); 321 // } 322 //} finally { 323 // // Reset Existing key type encoding for later encode step or reuse until cleared by caller 324 // setKeyEncoding(fixedKeyType); 325 //} 326 } 327 328 override 329 protected int getEncodedValueSize(Map!(Object,Object) val) 330 { 331 return 4 + ((val == _value) ? _length : calculateSize(val)); 332 } 333 334 override 335 public byte getEncodingCode() 336 { 337 return EncodingCodes.MAP32; 338 } 339 340 override 341 public ObjectMapType getType() 342 { 343 return this.outer; 344 } 345 346 override 347 public bool encodesSuperset(TypeEncoding!(Map!(Object,Object)) encoding) 348 { 349 return (getType() == encoding.getType()); 350 } 351 352 override 353 public Object readValue() 354 { 355 DecoderImpl decoder = getDecoder(); 356 ReadableBuffer buffer = decoder.getBuffer(); 357 358 int size = decoder.readRawInt(); 359 // todo - limit the decoder with size 360 int count = decoder.readRawInt(); 361 if (count > decoder.getByteBufferRemaining()) { 362 throw new IllegalArgumentException("Map element count " ~ to!string(count) ~" is specified to be greater than the amount of data available ("~ 363 to!string(decoder.getByteBufferRemaining())~ ")"); 364 } 365 366 ITypeConstructor keyConstructor = null; 367 ITypeConstructor valueConstructor = null; 368 369 Map!(Object, Object) map = new LinkedHashMap!(Object,Object)(count); 370 for(int i = 0; i < count / 2; i++) 371 { 372 keyConstructor = findNextDecoder(decoder, buffer, keyConstructor); 373 if(keyConstructor is null) 374 { 375 // throw new DecodeException("Unknown constructor"); 376 logError("Unknown constructor"); 377 return null; 378 } 379 380 Object key = keyConstructor.readValue(); 381 382 bool arrayType = false; 383 byte code = buffer.get(buffer.position()); 384 switch (code) 385 { 386 case EncodingCodes.ARRAY8: 387 goto case; 388 case EncodingCodes.ARRAY32: 389 arrayType = true; 390 break; 391 default: 392 break; 393 } 394 395 valueConstructor = findNextDecoder(decoder, buffer, valueConstructor); 396 if (valueConstructor is null) 397 { 398 // throw new DecodeException("Unknown constructor"); 399 logError("Unknown constructor"); 400 return null; 401 } 402 403 Object value; 404 405 //if (arrayType) 406 //{ 407 // value = ((ArrayType.ArrayEncoding) valueConstructor).readValueArray(); 408 //} 409 //else 410 { 411 value = valueConstructor.readValue(); 412 } 413 414 map.put(key, value); 415 } 416 417 return cast(Object)map; 418 } 419 420 override 421 public void skipValue() 422 { 423 DecoderImpl decoder = getDecoder(); 424 ReadableBuffer buffer = decoder.getBuffer(); 425 int size = decoder.readRawInt(); 426 buffer.position(buffer.position() + size); 427 } 428 429 public void setValue(Map!(Object,Object) value, int length) 430 { 431 _value = value; 432 _length = length; 433 } 434 435 override 436 void writeConstructor() 437 { 438 super.writeConstructor(); 439 } 440 441 override int getConstructorSize() 442 { 443 return super.getConstructorSize(); 444 } 445 446 447 } 448 449 class ShortMapEncoding 450 : SmallFloatingSizePrimitiveTypeEncoding!(Map!(Object,Object)) 451 , MapEncoding 452 { 453 private Map!(Object,Object) _value; 454 private int _length; 455 456 this(EncoderImpl encoder, DecoderImpl decoder) 457 { 458 super(encoder, decoder); 459 } 460 461 override 462 protected void writeEncodedValue(Map!(Object,Object) map) 463 { 464 getEncoder().getBuffer().ensureRemaining(getSizeBytes() + getEncodedValueSize(map)); 465 getEncoder().writeRaw(cast(byte)(2 * map.size())); 466 467 // Iterator<Map.Entry> iter = map.entrySet().iterator(); 468 469 IAMQPType IfixedKeyType = this.outer.fixedKeyType; 470 471 // Clear existing fixed key type encoding to prevent application to nested Maps 472 setKeyEncoding(null); 473 474 try 475 { 476 foreach (MapEntry!(Object, 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 501 } finally 502 { 503 setKeyEncoding(IfixedKeyType); 504 } 505 //try { 506 // while (iter.hasNext()) 507 // { 508 // Map.Entry<?, ?> element = iter.next(); 509 // TypeEncoding elementEncoding; 510 // 511 // if (fixedKeyType is null) 512 // { 513 // elementEncoding = _encoder.getType(element.getKey()).getEncoding(element.getKey()); 514 // } 515 // else 516 // { 517 // elementEncoding = fixedKeyType.getEncoding(element.getKey()); 518 // } 519 // 520 // elementEncoding.writeConstructor(); 521 // elementEncoding.writeValue(element.getKey()); 522 // elementEncoding = getEncoder().getType(element.getValue()).getEncoding(element.getValue()); 523 // elementEncoding.writeConstructor(); 524 // elementEncoding.writeValue(element.getValue()); 525 // } 526 //} finally { 527 // // Reset Existing key type encoding for later encode step or reuse until cleared by caller 528 // setKeyEncoding(fixedKeyType); 529 //} 530 } 531 532 override 533 protected int getEncodedValueSize(Map!(Object,Object) val) 534 { 535 return 1 + ((val == _value) ? _length : calculateSize(val)); 536 } 537 538 override 539 public byte getEncodingCode() 540 { 541 return EncodingCodes.MAP8; 542 } 543 544 override 545 public ObjectMapType getType() 546 { 547 return this.outer; 548 } 549 550 override 551 public bool encodesSuperset(TypeEncoding!(Map!(Object,Object)) encoder) 552 { 553 return encoder == this; 554 } 555 556 override 557 public Object readValue() 558 { 559 DecoderImpl decoder = getDecoder(); 560 ReadableBuffer buffer = decoder.getBuffer(); 561 562 int size = (decoder.readRawByte()) & 0xff; 563 // todo - limit the decoder with size 564 int count = (decoder.readRawByte()) & 0xff; 565 566 ITypeConstructor keyConstructor = null; 567 ITypeConstructor valueConstructor = null; 568 569 Map!(Object, Object) map = new LinkedHashMap!(Object, Object)(count); 570 for(int i = 0; i < count / 2; i++) 571 { 572 keyConstructor = findNextDecoder(decoder, buffer, keyConstructor); 573 if(keyConstructor is null) 574 { 575 logError("Unknown constructor"); 576 return null; 577 // throw new DecodeException("Unknown constructor"); 578 } 579 580 Object key = keyConstructor.readValue(); 581 582 bool arrayType = false; 583 byte code = buffer.get(buffer.position()); 584 switch (code) 585 { 586 case EncodingCodes.ARRAY8: 587 goto case; 588 case EncodingCodes.ARRAY32: 589 arrayType = true; 590 break; 591 default: 592 break; 593 } 594 595 valueConstructor = findNextDecoder(decoder, buffer, valueConstructor); 596 if(valueConstructor is null) 597 { 598 //throw new DecodeException("Unknown constructor"); 599 logError("Unknown constructor"); 600 return null; 601 } 602 603 Object value; 604 605 //if (arrayType) 606 //{ 607 // value = ((ArrayType.ArrayEncoding) valueConstructor).readValueArray(); 608 //} 609 //else 610 { 611 value = valueConstructor.readValue(); 612 } 613 614 map.put(key, value); 615 } 616 617 return cast(Object)map; 618 } 619 620 override 621 public void skipValue() 622 { 623 DecoderImpl decoder = getDecoder(); 624 ReadableBuffer buffer = decoder.getBuffer(); 625 int size = (cast(int)decoder.readRawByte()) & 0xff; 626 buffer.position(buffer.position() + size); 627 } 628 629 public void setValue(Map!(Object,Object) value, int length) 630 { 631 _value = value; 632 _length = length; 633 } 634 635 override 636 void writeConstructor() 637 { 638 super.writeConstructor(); 639 } 640 641 override int getConstructorSize() 642 { 643 return super.getConstructorSize(); 644 } 645 } 646 }