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 module hunt.proton.codec.messaging.FastPathDataType;
12 
13 import hunt.Exceptions;
14 import hunt.collection.Collection;
15 import hunt.proton.amqp.Binary;
16 import hunt.proton.amqp.Symbol;
17 import hunt.proton.amqp.UnsignedLong;
18 import hunt.proton.amqp.messaging.Data;
19 import hunt.proton.codec.AMQPType;
20 import hunt.proton.codec.Decoder;
21 import hunt.proton.codec.DecoderImpl;
22 import hunt.proton.codec.EncoderImpl;
23 import hunt.proton.codec.EncodingCodes;
24 import hunt.proton.codec.FastPathDescribedTypeConstructor;
25 import hunt.proton.codec.ReadableBuffer;
26 import hunt.proton.codec.TypeEncoding;
27 import hunt.proton.codec.WritableBuffer;
28 import hunt.proton.codec.messaging.DataType;
29 import std.concurrency : initOnce;
30 import hunt.logging;
31 import std.conv : to;
32 
33 class FastPathDataType : AMQPType!(Data), FastPathDescribedTypeConstructor!(Data) {
34 
35     private static byte DESCRIPTOR_CODE = 0x75;
36 
37     //private static Object[] DESCRIPTORS =
38     //{
39     //    UnsignedLong.valueOf(DESCRIPTOR_CODE), Symbol.valueOf("amqp:data:binary"),
40     //};
41 
42     static Object[]  DESCRIPTORS() {
43         __gshared Object[]  inst;
44         return initOnce!inst([UnsignedLong.valueOf(DESCRIPTOR_CODE), Symbol.valueOf("amqp:data:binary")]);
45     }
46 
47     private DataType dataType;
48 
49     this(EncoderImpl encoder) {
50         this.dataType = new DataType(encoder);
51     }
52 
53     public EncoderImpl getEncoder() {
54         return dataType.getEncoder();
55     }
56 
57     public DecoderImpl getDecoder() {
58         return dataType.getDecoder();
59     }
60 
61     override
62     public bool encodesJavaPrimitive() {
63         return false;
64     }
65 
66     override
67     public TypeInfo getTypeClass() {
68         return dataType.getTypeClass();
69     }
70 
71     override
72     public ITypeEncoding getEncoding(Object val) {
73         return dataType.getEncoding(cast(Data)val);
74     }
75 
76     override
77     public TypeEncoding!(Data) getCanonicalEncoding() {
78         return dataType.getCanonicalEncoding();
79     }
80 
81     override
82     public  Collection!(TypeEncoding!(Data)) getAllEncodings() {
83         return dataType.getAllEncodings();
84     }
85 
86     override
87     public Data readValue() {
88         ReadableBuffer buffer = getDecoder().getBuffer();
89         byte encodingCode = buffer.get();
90 
91         int size = 0;
92 
93         switch (encodingCode) {
94             case EncodingCodes.VBIN8:
95                 size = buffer.get() & 0xFF;
96                 break;
97             case EncodingCodes.VBIN32:
98                 size = buffer.getInt();
99                 break;
100             case EncodingCodes.NULL:
101                 return new Data(null);
102             default:
103             {
104                 logError("Expected Binary type but found encoding: %d",encodingCode);
105                 break;
106             }
107                 //throw new ProtonException("Expected Binary type but found encoding: " ~ encodingCode);
108         }
109 
110         if (size > buffer.remaining()) {
111             throw new IllegalArgumentException("Binary data size " ~ to!string(size) ~ " is specified to be greater than the " ~
112                                                "amount of data available ("~ to!string(buffer.remaining())~")");
113         }
114 
115         byte[] data = new byte[size];
116         buffer.get(data, 0, size);
117 
118         return new Data(new Binary(data));
119     }
120 
121     override
122     public void skipValue() {
123         implementationMissing(false);
124       //  getDecoder().readConstructor().skipValue();
125     }
126 
127     override
128     public void write(Object v) {
129         Data data = cast(Data)v;
130         WritableBuffer buffer = getEncoder().getBuffer();
131         buffer.put(EncodingCodes.DESCRIBED_TYPE_INDICATOR);
132         buffer.put(EncodingCodes.SMALLULONG);
133         buffer.put(DESCRIPTOR_CODE);
134         getEncoder().writeBinary(data.getValue());
135     }
136 
137     public static void register(Decoder decoder, EncoderImpl encoder) {
138         FastPathDataType type = new FastPathDataType(encoder);
139         //implementationMissing(false);
140         foreach(Object descriptor ; DESCRIPTORS) {
141            // decoder.register(descriptor, (FastPathDescribedTypeConstructor<?>) type);
142              decoder.registerFastPath(descriptor,  type);
143         }
144         encoder.register(type);
145     }
146 }