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.DynamicDescribedType;
13 
14 import hunt.proton.amqp.DescribedType;
15 
16 import hunt.collection.Collection;
17 import hunt.collection.Collections;
18 import hunt.collection.HashMap;
19 import hunt.collection.Map;
20 import hunt.proton.codec.AMQPType;
21 
22 import hunt.proton.codec.TypeEncoding;
23 import hunt.proton.codec.EncoderImpl;
24 import hunt.collection.List;
25 import hunt.collection.ArrayList;
26 import hunt.proton.codec.EncodingCodes;
27 
28 class DynamicDescribedType : AMQPType!(DescribedType)
29 {
30 
31     private EncoderImpl _encoder;
32     private Map!(ITypeEncoding, ITypeEncoding) _encodings ;//= new HashMap!(ITypeEncoding, ITypeEncoding)();
33     private Object _descriptor;
34 
35     this(EncoderImpl encoder, Object descriptor)
36     {
37         _encoder = encoder;
38         _descriptor = descriptor;
39         _encodings = new HashMap!(ITypeEncoding, ITypeEncoding);
40     }
41 
42 
43     public TypeInfo getTypeClass()
44     {
45         return typeid(DescribedType);
46     }
47 
48     public ITypeEncoding getEncoding(Object v)
49     {
50         DescribedType val = cast(DescribedType)v;
51         ITypeEncoding underlyingEncoding = _encoder.getType(val.getDescribed()).getEncoding(val.getDescribed());
52         ITypeEncoding encoding = _encodings.get(underlyingEncoding);
53         if(encoding is null)
54         {
55             encoding = new DynamicDescribedTypeEncoding(underlyingEncoding);
56             _encodings.put(underlyingEncoding, encoding);
57         }
58 
59         return encoding;
60     }
61 
62     public TypeEncoding!(DescribedType) getCanonicalEncoding()
63     {
64         return null;
65     }
66 
67     public Collection!(TypeEncoding!(DescribedType)) getAllEncodings()
68     {
69         //Collection values = _encodings.values();
70         List!(TypeEncoding!(DescribedType)) lst = new ArrayList!(TypeEncoding!(DescribedType));
71         foreach(ITypeEncoding v ;  _encodings.values() )
72         {
73             lst.add(cast(TypeEncoding!(DescribedType))v);
74         }
75         //Collection unmodifiable = Collections.unmodifiableCollection(values);
76         return lst;
77     }
78 
79     public void write(Object val)
80     {
81         ITypeEncoding encoding = getEncoding(val);
82         encoding.writeConstructor();
83         encoding.writeValue(val);
84     }
85 
86     class DynamicDescribedTypeEncoding : ITypeEncoding
87     {
88         private ITypeEncoding _underlyingEncoding;
89         private ITypeEncoding _descriptorType;
90         private int _constructorSize;
91 
92 
93         this(ITypeEncoding underlyingEncoding)
94         {
95             _underlyingEncoding = underlyingEncoding;
96             _descriptorType = _encoder.getType(_descriptor).getEncoding(_descriptor);
97             _constructorSize = 1 + _descriptorType.getConstructorSize()
98                                + _descriptorType.getValueSize(_descriptor)
99                                + _underlyingEncoding.getConstructorSize();
100         }
101 
102         public AMQPType!(DescribedType) getType()
103         {
104             return this.outer;
105         }
106 
107         public void writeConstructor()
108         {
109             _encoder.writeRaw(EncodingCodes.DESCRIBED_TYPE_INDICATOR);
110             _descriptorType.writeConstructor();
111             _descriptorType.writeValue(_descriptor);
112             _underlyingEncoding.writeConstructor();
113         }
114 
115         public int getConstructorSize()
116         {
117             return _constructorSize;
118         }
119 
120         public void writeValue(Object val)
121         {
122             _underlyingEncoding.writeValue((cast(DescribedType)val).getDescribed());
123         }
124 
125         public int getValueSize(Object val)
126         {
127             return _underlyingEncoding.getValueSize((cast(DescribedType) val).getDescribed());
128         }
129 
130         public bool isFixedSizeVal()
131         {
132             return _underlyingEncoding.isFixedSizeVal();
133         }
134 
135         public bool encodesSuperset(TypeEncoding!DescribedType encoding)
136         {
137             return (getType() == encoding.getType());
138         }
139 
140         override
141         public bool encodesJavaPrimitive()
142         {
143             return false;
144         }
145 
146         int opCmp(ITypeEncoding o)
147         {
148             return this.getConstructorSize - o.getConstructorSize;
149         }
150 
151     }
152 }