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 }