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.AbstractDescribedType;
13
14 import hunt.proton.codec.DecoderImpl;
15 import hunt.proton.codec.EncoderImpl;
16 import hunt.proton.codec.TypeEncoding;
17 import hunt.proton.codec.AMQPType;
18 import hunt.proton.codec.EncodingCodes;
19 import hunt.proton.amqp.UnsignedLong;
20
21 import hunt.collection.Map;
22 import hunt.collection.HashMap;
23 import hunt.collection.Collection;
24 import hunt.collection.ArrayList;
25 import hunt.Exceptions;
26 import hunt.logging.ConsoleLogger;
27
28 abstract class AbstractDescribedType(T,M) : AMQPType!(T) //!(AmqpValue,Object)
29 {
30 private DecoderImpl _decoder;
31 private EncoderImpl _encoder;
32 private Map!(TypeEncoding!(M), TypeEncoding!(T)) _encodings ;
33
34 this(EncoderImpl encoder)
35 {
36 _encoder = encoder;
37 _decoder = encoder.getDecoder();
38 _encodings = new HashMap!(TypeEncoding!(M), TypeEncoding!(T));
39 }
40
41 abstract protected UnsignedLong getDescriptor();
42
43 public EncoderImpl getEncoder()
44 {
45 return _encoder;
46 }
47
48 public DecoderImpl getDecoder()
49 {
50 return _decoder;
51 }
52
53 public ITypeEncoding getEncoding(Object v)
54 {
55 version(HUNT_AMQP_DEBUG) {
56 if(v is null) {
57 warning("v is null");
58 } else {
59 infof("wrapping %s", typeid(v));
60 }
61 }
62
63 T val = cast(T)v;
64
65 if(val is null) {
66 warningf("Wrong casting from '%s' to '%s'", typeid(v), T.stringof);
67 }
68 //M asUnderlying = wrap(val);
69 //TypeEncoding<M> underlyingEncoding = _encoder.getType(asUnderlying).getEncoding(asUnderlying);
70 //TypeEncoding<T> encoding = _encodings.get(underlyingEncoding);
71 //if(encoding == null)
72 //{
73 // encoding = new DynamicDescribedTypeEncoding(underlyingEncoding);
74 // _encodings.put(underlyingEncoding, encoding);
75 //}
76
77 //protected List!Object wrap(Header val)
78 //{
79 // return new HeaderWrapper(val);
80 //}
81 //String
82 M asUnderlying = wrap(val); //ArrayList!Object
83
84 if(asUnderlying is null) {
85 warningf("asUnderlying is null for %s", typeid(val));
86 } else {
87 version(HUNT_AMQP_DEBUG) trace(typeid(cast(Object)asUnderlying));
88 }
89
90 IAMQPType tt = _encoder.getType(cast(Object)asUnderlying);
91 version(HUNT_AMQP_DEBUG) trace(typeid(cast(Object)tt));
92
93 // IAMQPType tt = _encoder.getType(cast(Object)asUnderlying,typeid(M));
94 ITypeEncoding typeEncoding = tt.getEncoding(cast(Object)asUnderlying);
95 TypeEncoding!(M) underlyingEncoding = cast(TypeEncoding!(M))typeEncoding;
96
97 if(underlyingEncoding is null) {
98 warningf("Wrong casting from '%s' to '%s'", typeid(typeEncoding), typeid(TypeEncoding!(M)));
99 return null;
100 }
101
102 // TypeEncoding!(M) underlyingEncoding = (cast(AMQPType!M)(_encoder.getType(cast(Object)asUnderlying,this.getTypeClass()))).getEncoding(asUnderlying);
103 TypeEncoding!(T) encoding = _encodings.get(underlyingEncoding);
104 if(encoding is null)
105 {
106 encoding = new DynamicDescribedTypeEncoding(underlyingEncoding);
107 _encodings.put(underlyingEncoding, encoding);
108 }
109 return cast(ITypeEncoding)encoding;
110 //implementationMissing(false);
111 //return null;
112 }
113
114 abstract protected M wrap(T val);
115
116 public TypeEncoding!(T) getCanonicalEncoding()
117 {
118 return null;
119 }
120
121 public Collection!(TypeEncoding!(T)) getAllEncodings()
122 {
123 // auto lst = new ArrayList!(TypeEncoding!(T));
124
125 return new ArrayList!(TypeEncoding!(T)) (_encodings.values());
126 // Collection unmodifiable = Collections.unmodifiableCollection(values);
127 // return (Collection!(TypeEncoding!(T))) unmodifiable;
128 }
129
130 public void write(Object val)
131 {
132 //T t = cast(T)val;
133 //assert(t !is null);
134 ITypeEncoding encoding = getEncoding(val);
135 if(encoding is null) {
136 warning("encoding is null");
137 } else {
138 encoding.writeConstructor();
139 encoding.writeValue(val);
140 }
141 }
142
143 class DynamicDescribedTypeEncoding : TypeEncoding!(T)
144 {
145 private TypeEncoding!(M) _underlyingEncoding;
146 private TypeEncoding!(UnsignedLong) _descriptorType;
147 private int _constructorSize;
148
149
150 this(TypeEncoding!(M) underlyingEncoding)
151 {
152 _underlyingEncoding = underlyingEncoding;
153 _descriptorType = cast(TypeEncoding!(UnsignedLong))(_encoder.getType(getDescriptor()).getEncoding(getDescriptor()));
154 _constructorSize = 1 + _descriptorType.getConstructorSize()
155 + _descriptorType.getValueSize(getDescriptor())
156 + _underlyingEncoding.getConstructorSize();
157 }
158
159 public AMQPType!(T) getType()
160 {
161 // return AbstractDescribedType.this;
162 return this.outer;
163 }
164
165
166 int opCmp(ITypeEncoding o)
167 {
168 return this.getConstructorSize - o.getConstructorSize;
169 }
170
171 // alias opCmp = Object.opCmp;
172
173 public void writeConstructor()
174 {
175 _encoder.writeRaw(EncodingCodes.DESCRIBED_TYPE_INDICATOR);
176 _descriptorType.writeConstructor();
177 _descriptorType.writeValue(getDescriptor());
178 _underlyingEncoding.writeConstructor();
179 }
180
181 public int getConstructorSize()
182 {
183 return _constructorSize;
184 }
185
186 public void writeValue(Object val)
187 {
188 _underlyingEncoding.writeValue(cast(Object)wrap(cast(T)val));
189 }
190
191 public int getValueSize(Object val)
192 {
193 return _underlyingEncoding.getValueSize(cast(Object)wrap(cast(T)val));
194 }
195
196 public bool isFixedSizeVal()
197 {
198 return _underlyingEncoding.isFixedSizeVal();
199 }
200
201 public bool encodesSuperset(TypeEncoding!(T) encoding)
202 {
203 return (getType() == encoding.getType())
204 && (_underlyingEncoding.encodesSuperset((cast(DynamicDescribedTypeEncoding)encoding)
205 ._underlyingEncoding));
206 }
207
208 override
209 public bool encodesJavaPrimitive()
210 {
211 return false;
212 }
213
214 }
215 }