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.SymbolType;
13 
14 import hunt.proton.codec.SmallFloatingSizePrimitiveTypeEncoding;
15 import hunt.proton.codec.LargeFloatingSizePrimitiveTypeEncoding;
16 import hunt.proton.codec.EncodingCodes;
17 import hunt.proton.codec.EncoderImpl;
18 import hunt.proton.codec.PrimitiveTypeEncoding;
19 import hunt.proton.codec.DecoderImpl;
20 import hunt.proton.codec.ReadableBuffer;
21 import hunt.proton.codec.AbstractPrimitiveType;
22 import hunt.collection.Collection;
23 import hunt.collection.HashMap;
24 import hunt.collection.Map;
25 import hunt.collection.ArrayList;
26 import hunt.proton.codec.TypeEncoding;
27 
28 import hunt.proton.amqp.Symbol;
29 import hunt.String;
30 import hunt.collection.List;
31 
32 class SymbolType : AbstractPrimitiveType!(Symbol)
33 {
34     //private static Charset ASCII_CHARSET = Charset.forName("US-ASCII");
35     private SymbolEncoding _symbolEncoding;
36     private SymbolEncoding _shortSymbolEncoding;
37 
38     private Map!(ReadableBuffer, Symbol) _symbolCache;
39     private DecoderImpl.TypeDecoder!(Symbol) _symbolCreator ;
40 
41     interface SymbolEncoding : PrimitiveTypeEncoding!(Symbol)
42     {
43 
44     }
45 
46     this(EncoderImpl encoder, DecoderImpl decoder)
47     {
48         _symbolCreator = new class DecoderImpl.TypeDecoder!(Symbol)
49         {
50             override
51             public Symbol decode(DecoderImpl decoder, ReadableBuffer buffer)
52             {
53                 Symbol symbol = _symbolCache.get(buffer);
54                 if (symbol is null)
55                 {
56                     byte[] bytes = new byte[buffer.limit()];
57                     buffer.get(bytes);
58 
59                     // String str = new String(cast(string)bytes);
60                     symbol = Symbol.getSymbol(cast(string)bytes);
61 
62                     _symbolCache.put(ByteBufferReader.wrap(bytes), symbol);
63                 }
64                 return symbol;
65             }
66         };
67         _symbolCache  =  new HashMap!(ReadableBuffer, Symbol);
68         _symbolEncoding =  new LongSymbolEncoding(encoder, decoder);
69         _shortSymbolEncoding = new ShortSymbolEncoding(encoder, decoder);
70         encoder.register(typeid(Symbol), this);
71         decoder.register(this);
72     }
73 
74     public TypeInfo getTypeClass()
75     {
76         return typeid(Symbol);
77     }
78 
79     public void fastWrite(EncoderImpl encoder, Symbol symbol)
80     {
81         if (symbol.length() <= 255)
82         {
83             // Reserve size of body + type encoding and single byte size
84             encoder.getBuffer().ensureRemaining(2 + symbol.length());
85             encoder.writeRaw(EncodingCodes.SYM8);
86             encoder.writeRaw(cast(byte) symbol.length());
87             symbol.writeTo(encoder.getBuffer());
88         }
89         else
90         {
91             // Reserve size of body + type encoding and four byte size
92             encoder.getBuffer().ensureRemaining(5 + symbol.length());
93             encoder.writeRaw(EncodingCodes.SYM32);
94             encoder.writeRaw(symbol.length());
95             symbol.writeTo(encoder.getBuffer());
96         }
97     }
98 
99     public ITypeEncoding getEncoding(Object val)
100     {
101         return (cast(Symbol)val).length() <= 255 ? _shortSymbolEncoding : _symbolEncoding;
102     }
103 
104     public SymbolEncoding getCanonicalEncoding()
105     {
106         return _symbolEncoding;
107     }
108 
109     public Collection!(TypeEncoding!(Symbol)) getAllEncodings()
110     {
111         List!(TypeEncoding!(Symbol)) lst = new ArrayList!(TypeEncoding!(Symbol));
112         lst.add(_shortSymbolEncoding);
113         lst.add(_symbolEncoding);
114         return lst;
115         //return Arrays.asList(_shortSymbolEncoding, _symbolEncoding);
116     }
117 
118 
119     //Collection!(PrimitiveTypeEncoding!(Symbol)) getAllEncodings()
120     //{
121     //    return super.getAllEncodings();
122     //}
123 
124     class LongSymbolEncoding
125             : LargeFloatingSizePrimitiveTypeEncoding!(Symbol)
126             , SymbolEncoding
127     {
128 
129         this(EncoderImpl encoder, DecoderImpl decoder)
130         {
131             super(encoder, decoder);
132         }
133 
134         override
135         protected void writeEncodedValue(Symbol val)
136         {
137             getEncoder().getBuffer().ensureRemaining(getEncodedValueSize(val));
138             val.writeTo(getEncoder().getBuffer());
139         }
140 
141         override
142         protected int getEncodedValueSize(Symbol val)
143         {
144             return val.length();
145         }
146 
147         override
148         public byte getEncodingCode()
149         {
150             return EncodingCodes.SYM32;
151         }
152 
153         override
154         public SymbolType getType()
155         {
156             return this.outer;
157         }
158 
159         override
160         public bool encodesSuperset(TypeEncoding!(Symbol) encoding)
161         {
162             return (getType() == encoding.getType());
163         }
164 
165         override
166         public Object readValue()
167         {
168             DecoderImpl decoder = getDecoder();
169             int size = decoder.readRawInt();
170             return decoder.readRaw(_symbolCreator, size);
171         }
172 
173         override
174         public void skipValue()
175         {
176             DecoderImpl decoder = getDecoder();
177             ReadableBuffer buffer = decoder.getBuffer();
178             int size = decoder.readRawInt();
179             buffer.position(buffer.position() + size);
180         }
181 
182         override  bool encodesJavaPrimitive()
183         {
184             return super.encodesJavaPrimitive();
185         }
186 
187         override TypeInfo getTypeClass()
188         {
189             return super.getTypeClass();
190         }
191 
192         override void writeConstructor()
193         {
194             return super.writeConstructor();
195         }
196 
197         override  int getConstructorSize()
198         {
199             return super.getConstructorSize();
200         }
201     }
202 
203     class ShortSymbolEncoding
204             : SmallFloatingSizePrimitiveTypeEncoding!(Symbol)
205             , SymbolEncoding
206     {
207 
208         this(EncoderImpl encoder, DecoderImpl decoder)
209         {
210             super(encoder, decoder);
211         }
212 
213         override
214         protected void writeEncodedValue(Symbol val)
215         {
216             getEncoder().getBuffer().ensureRemaining(getEncodedValueSize(val));
217             val.writeTo(getEncoder().getBuffer());
218         }
219 
220         override
221         protected int getEncodedValueSize(Symbol val)
222         {
223             return val.length();
224         }
225 
226         override
227         public byte getEncodingCode()
228         {
229             return EncodingCodes.SYM8;
230         }
231 
232         override
233         public SymbolType getType()
234         {
235             return this.outer;
236         }
237 
238         override
239         public bool encodesSuperset(TypeEncoding!(Symbol) encoder)
240         {
241             return encoder == this;
242         }
243 
244         override
245         public Symbol readValue()
246         {
247             DecoderImpl decoder = getDecoder();
248             int size = (cast(int)decoder.readRawByte()) & 0xff;
249             return decoder.readRaw(_symbolCreator, size);
250         }
251 
252         override
253         public void skipValue()
254         {
255             DecoderImpl decoder = getDecoder();
256             ReadableBuffer buffer = decoder.getBuffer();
257             int size = (cast(int)decoder.readRawByte()) & 0xff;
258             buffer.position(buffer.position() + size);
259         }
260 
261         override bool encodesJavaPrimitive()
262         {
263             return super.encodesJavaPrimitive();
264         }
265 
266         override TypeInfo getTypeClass()
267         {
268             return super.getTypeClass();
269         }
270 
271         override void writeConstructor()
272         {
273             return super.writeConstructor();
274         }
275 
276         override  int getConstructorSize()
277         {
278             return super.getConstructorSize();
279         }
280     }
281 }