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.ReadableBuffer; 13 14 import hunt.proton.codec.WritableBuffer; 15 import hunt.Exceptions; 16 import hunt.io.BufferUtils; 17 import hunt.io.ByteBuffer; 18 import hunt.String; 19 /** 20 * Interface to abstract a buffer, similar to {@link WritableBuffer} 21 */ 22 interface ReadableBuffer { 23 24 /** 25 * Returns the capacity of the backing buffer of this ReadableBuffer 26 * @return the capacity of the backing buffer of this ReadableBuffer 27 */ 28 int capacity(); 29 30 /** 31 * Returns true if this ReadableBuffer is backed by an array which can be 32 * accessed by the {@link #array()} and {@link #arrayOffset()} methods. 33 * 34 * @return true if the buffer is backed by a primitive array. 35 */ 36 bool hasArray(); 37 38 /** 39 * Returns the primitive array that backs this buffer if one exists and the 40 * buffer is not read-only. The caller should have checked the {@link #hasArray()} 41 * method before calling this method. 42 * 43 * @return the array that backs this buffer is available. 44 * 45 * @throws UnsupportedOperationException if this {@link ReadableBuffer} doesn't support array access. 46 * @throws ReadOnlyBufferException if the ReadableBuffer is read-only. 47 */ 48 byte[] array(); 49 50 /** 51 * Returns the offset into the backing array of the first element in the buffer. The caller 52 * should have checked the {@link #hasArray()} method before calling this method. 53 * 54 * @return the offset into the backing array of the first element in the buffer. 55 * 56 * @throws UnsupportedOperationException if this {@link ReadableBuffer} doesn't support array access. 57 * @throws ReadOnlyBufferException if the ReadableBuffer is read-only. 58 */ 59 int arrayOffset(); 60 61 /** 62 * Compact the backing storage of this ReadableBuffer, possibly freeing previously-read 63 * portions of pooled data or reducing the number of backing arrays if present. 64 * <p> 65 * This is an optional operation and care should be taken in its implementation. 66 * 67 * @return a reference to this buffer 68 */ 69 ReadableBuffer reclaimRead(); 70 71 /** 72 * Reads the byte at the current position and advances the position by 1. 73 * 74 * @return the byte at the current position. 75 * 76 * @throws BufferUnderflowException if the buffer position has reached the limit. 77 */ 78 byte get(); 79 80 /** 81 * Reads the byte at the given index, the buffer position is not affected. 82 * 83 * @param index 84 * The index in the buffer from which to read the byte. 85 * 86 * @return the byte value stored at the target index. 87 * 88 * @throws IndexOutOfBoundsException if the index is not in range for this buffer. 89 */ 90 byte get(int index); 91 92 /** 93 * Reads four bytes from the buffer and returns them as an integer value. The 94 * buffer position is advanced by four byes. 95 * 96 * @return and integer value composed of bytes read from the buffer. 97 * 98 * @throws BufferUnderflowException if the buffer position has reached the limit. 99 */ 100 int getInt(); 101 102 /** 103 * Reads eight bytes from the buffer and returns them as an long value. The 104 * buffer position is advanced by eight byes. 105 * 106 * @return and long value composed of bytes read from the buffer. 107 * 108 * @throws BufferUnderflowException if the buffer position has reached the limit. 109 */ 110 long getLong(); 111 112 /** 113 * Reads two bytes from the buffer and returns them as an short value. The 114 * buffer position is advanced by two byes. 115 * 116 * @return and short value composed of bytes read from the buffer. 117 * 118 * @throws BufferUnderflowException if the buffer position has reached the limit. 119 */ 120 short getShort(); 121 122 /** 123 * Reads four bytes from the buffer and returns them as an float value. The 124 * buffer position is advanced by four byes. 125 * 126 * @return and float value composed of bytes read from the buffer. 127 * 128 * @throws BufferUnderflowException if the buffer position has reached the limit. 129 */ 130 float getFloat(); 131 132 /** 133 * Reads eight bytes from the buffer and returns them as an double value. The 134 * buffer position is advanced by eight byes. 135 * 136 * @return and double value composed of bytes read from the buffer. 137 * 138 * @throws BufferUnderflowException if the buffer position has reached the limit. 139 */ 140 double getDouble(); 141 142 /** 143 * A bulk read method that copies bytes from this buffer into the target byte array. 144 * 145 * @param target 146 * The byte array to copy bytes read from this buffer. 147 * @param offset 148 * The offset into the given array where the copy starts. 149 * @param length 150 * The number of bytes to copy into the target array. 151 * 152 * @return a reference to this ReadableBuffer instance. 153 * 154 * @throws BufferUnderflowException if the are less readable bytes than the array length. 155 * @throws IndexOutOfBoundsException if the offset or length values are invalid. 156 */ 157 ReadableBuffer get(byte[] target, int offset, int length); 158 159 /** 160 * A bulk read method that copies bytes from this buffer into the target byte array. 161 * 162 * @param target 163 * The byte array to copy bytes read from this buffer. 164 * 165 * @return a reference to this ReadableBuffer instance. 166 * 167 * @throws BufferUnderflowException if the are less readable bytes than the array length. 168 */ 169 ReadableBuffer get(byte[] target); 170 171 /** 172 * Copy data from this buffer to the target buffer starting from the current 173 * position and continuing until either this buffer's remaining bytes are 174 * consumed or the target is full. 175 * 176 * @param target 177 * The WritableBuffer to transfer this buffer's data to. 178 * 179 * @return a reference to this ReadableBuffer instance. 180 */ 181 ReadableBuffer get(WritableBuffer target); 182 183 /** 184 * Creates a new ReadableBuffer instance that is a view of the readable portion of 185 * this buffer. The position will be set to zero and the limit and the reported capacity 186 * will match the value returned by this buffer's {@link #remaining()} method, the mark 187 * will be undefined. 188 * 189 * @return a new ReadableBuffer that is a view of the readable portion of this buffer. 190 */ 191 ReadableBuffer slice(); 192 193 /** 194 * Sets the buffer limit to the current position and the position is set to zero, the 195 * mark value reset to undefined. 196 * 197 * @return a reference to this {@link ReadableBuffer}. 198 */ 199 ReadableBuffer flip(); 200 201 /** 202 * Sets the current read limit of this buffer to the given value. If the buffer mark 203 * value is defined and is larger than the limit the mark will be discarded. If the 204 * position is larger than the new limit it will be reset to the new limit. 205 * 206 * @param limit 207 * The new read limit to set for this buffer. 208 * 209 * @return a reference to this {@link ReadableBuffer}. 210 * 211 * @throws IllegalArgumentException if the limit value is negative or greater than the capacity. 212 */ 213 ReadableBuffer limit(int limit); 214 215 /** 216 * @return the current value of this buffer's limit. 217 */ 218 int limit(); 219 220 /** 221 * Sets the current position of this buffer to the given value. If the buffer mark 222 * value is defined and is larger than the newly set position is must be discarded. 223 * 224 * @param position 225 * The new position to set for this buffer. 226 * 227 * @return a reference to this {@link ReadableBuffer}. 228 * 229 * @throws IllegalArgumentException if the position value is negative or greater than the limit. 230 */ 231 ReadableBuffer position(int position); 232 233 /** 234 * @return the current position from which the next read operation will start. 235 */ 236 int position(); 237 238 /** 239 * Mark the current position of this buffer which can be returned to after a 240 * read operation by calling {@link #reset()}. 241 * 242 * @return a reference to this {@link ReadableBuffer}. 243 */ 244 ReadableBuffer mark(); 245 246 /** 247 * Reset the buffer's position to a previously marked value, the mark should remain 248 * set after calling this method. 249 * 250 * @return a reference to this {@link ReadableBuffer}. 251 * 252 * @throws InvalidMarkException if the mark value is undefined. 253 */ 254 ReadableBuffer reset(); 255 256 /** 257 * Resets the buffer position to zero and clears and previously set mark. 258 * 259 * @return a reference to this {@link ReadableBuffer}. 260 */ 261 ReadableBuffer rewind(); 262 263 /** 264 * Resets the buffer position to zero and sets the limit to the buffer capacity, 265 * the mark value is discarded if set. 266 * 267 * @return a reference to this {@link ReadableBuffer}. 268 */ 269 ReadableBuffer clear(); 270 271 /** 272 * @return the remaining number of readable bytes in this buffer. 273 */ 274 int remaining(); 275 276 /** 277 * @return true if there are readable bytes still remaining in this buffer. 278 */ 279 bool hasRemaining(); 280 281 /** 282 * Creates a duplicate {@link ReadableBuffer} to this instance. 283 * <p> 284 * The duplicated buffer will have the same position, limit and mark as this 285 * buffer. The two buffers share the same backing data. 286 * 287 * @return a duplicate of this {@link ReadableBuffer}. 288 */ 289 ReadableBuffer duplicate(); 290 291 /** 292 * @return a ByteBuffer view of the current readable portion of this buffer. 293 */ 294 ByteBuffer byteBuffer(); 295 296 /** 297 * Reads a UTF-8 encoded String from the buffer starting the decode at the 298 * current position and reading until the limit is reached. The position 299 * is advanced to the limit once this method returns. If there is no bytes 300 * remaining in the buffer when this method is called a null is returned. 301 * 302 * @return a string decoded from the remaining bytes in this buffer. 303 * 304 * @throws CharacterCodingException if the encoding is invalid for any reason. 305 */ 306 string readUTF8() ; 307 308 /** 309 * Decodes a String from the buffer using the provided {@link CharsetDecoder} 310 * starting the decode at the current position and reading until the limit is 311 * reached. The position is advanced to the limit once this method returns. 312 * If there is no bytes remaining in the buffer when this method is called a 313 * null is returned. 314 * 315 * @return a string decoded from the remaining bytes in this buffer. 316 * 317 * @throws CharacterCodingException if the encoding is invalid for any reason. 318 */ 319 //string readString() ; 320 321 int opCmp(ReadableBuffer o); 322 323 } 324 325 326 327 class ByteBufferReader : ReadableBuffer { 328 329 private ByteBuffer buffer; 330 331 public static ByteBufferReader allocate(int size) { 332 ByteBuffer allocated = BufferUtils.allocate(size); 333 return new ByteBufferReader(allocated); 334 } 335 336 public static ByteBufferReader wrap(ByteBuffer buffer) { 337 return new ByteBufferReader(buffer); 338 } 339 340 public static ByteBufferReader wrap(byte[] array) { 341 return new ByteBufferReader(BufferUtils.toBuffer(array)); 342 } 343 344 this(ByteBuffer buffer) { 345 this.buffer = buffer; 346 } 347 348 override 349 public int capacity() { 350 return buffer.capacity(); 351 } 352 353 override 354 public byte get() { 355 return buffer.get(); 356 } 357 358 override 359 public byte get(int index) { 360 return buffer.get(index); 361 } 362 363 override 364 public int getInt() { 365 return buffer.getInt(); 366 } 367 368 override 369 public long getLong() { 370 return buffer.getLong(); 371 } 372 373 override 374 public short getShort() { 375 return buffer.getShort(); 376 } 377 378 override 379 public float getFloat() { 380 return cast(float)buffer.getInt(); 381 } 382 383 override 384 public double getDouble() { 385 return cast(double)buffer.getLong(); 386 } 387 388 override 389 public int limit() { 390 return buffer.limit(); 391 } 392 393 override 394 public ReadableBuffer get(byte[] data, int offset, int length) { 395 buffer.get(data, offset, length); 396 return this; 397 } 398 399 override 400 public ReadableBuffer get(byte[] data) { 401 buffer.get(data); 402 return this; 403 } 404 405 override 406 public ReadableBuffer flip() { 407 buffer.flip(); 408 return this; 409 } 410 411 override 412 public ReadableBuffer position(int position) { 413 buffer.position(position); 414 return this; 415 } 416 417 override 418 public ReadableBuffer slice() { 419 return new ByteBufferReader(buffer.slice()); 420 } 421 422 override 423 public ReadableBuffer limit(int limit) { 424 buffer.limit(limit); 425 return this; 426 } 427 428 override 429 public int remaining() { 430 return buffer.remaining(); 431 } 432 433 override 434 public int position() { 435 return buffer.position(); 436 } 437 438 override 439 public bool hasRemaining() { 440 return buffer.hasRemaining(); 441 } 442 443 override 444 public ReadableBuffer duplicate() { 445 return new ByteBufferReader(buffer.duplicate()); 446 } 447 448 override 449 public ByteBuffer byteBuffer() { 450 return buffer; 451 } 452 453 override 454 public string readUTF8() { 455 // return StandardCharsets.UTF_8.decode(buffer).toString(); 456 return(cast(string)(buffer.getRemaining())); 457 } 458 459 //override 460 //public String readString(CharsetDecoder decoder) throws CharacterCodingException { 461 // return decoder.decode(buffer).toString(); 462 //} 463 464 override 465 public bool hasArray() { 466 return buffer.hasArray(); 467 } 468 469 override 470 public byte[] array() { 471 return buffer.array(); 472 } 473 474 override 475 public int arrayOffset() { 476 return buffer.arrayOffset(); 477 } 478 479 override 480 public ReadableBuffer reclaimRead() { 481 // Don't compact ByteBuffer due to the expense of the copy 482 return this; 483 } 484 485 override 486 public ReadableBuffer mark() { 487 buffer.mark(); 488 return this; 489 } 490 491 override 492 public ReadableBuffer reset() { 493 buffer.reset(); 494 return this; 495 } 496 497 override 498 public ReadableBuffer rewind() { 499 buffer.rewind(); 500 return this; 501 } 502 503 override 504 public ReadableBuffer clear() { 505 buffer.clear(); 506 return this; 507 } 508 509 override 510 public ReadableBuffer get(WritableBuffer target) { 511 target.put(buffer); 512 return this; 513 } 514 515 override 516 public string toString() { 517 return buffer.toString(); 518 } 519 520 //override 521 //public int hashCode() { 522 // return buffer.hashCode(); 523 //} 524 525 int opCmp(ReadableBuffer o) 526 { 527 return this.remaining() - o.remaining(); 528 } 529 530 override bool opEquals(Object other) 531 { 532 if (this is other) { 533 return true; 534 } 535 536 if ((typeof(this).stringof != typeof(other).stringof )) { 537 return false; 538 } 539 540 ReadableBuffer readable = cast(ReadableBuffer) other; 541 if (this.remaining() != readable.remaining()) { 542 return false; 543 } 544 545 //if (other instanceof CompositeReadableBuffer) { 546 // return other.equals(this); 547 //} 548 549 return buffer.getRemaining() == (readable.byteBuffer().getRemaining()); 550 } 551 }