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 }