001package net.gdface.codegen.thrift;
002
003import static com.google.common.base.Preconditions.*;
004
005import com.google.common.base.Supplier;
006import com.google.common.base.Suppliers;
007
008/**
009 * 定义thrift协议cxx类型
010 * @author guyadong
011 *
012 */
013public class CxxTypeMeta {
014
015        enum ThriftProtocolType {
016            TYPE_VOID(true,false,false),
017            TYPE_STRING(true,false,false),
018            TYPE_BOOL(true,false,false),
019            TYPE_I8(true,false,true),
020            TYPE_I16(true,false,true),
021            TYPE_I32(true,false,true),
022            TYPE_I64(true,false,true),
023            TYPE_DOUBLE(true,false,true),
024            TYPE_BINARY(true,false,false),
025            TYPE_STRUCT(false,false,false),
026            TYPE_MAP(false,true,false),
027            TYPE_SET(false,true,false),
028            TYPE_LIST(false,true,false),
029            TYPE_ENUM(false,false,false);
030            public final boolean isBaseType,isContainer,isNumber;
031                private ThriftProtocolType(boolean isBaseType, boolean isContainer,boolean isNumber) {
032                        this.isBaseType = isBaseType;
033                        this.isContainer = isContainer;
034                        this.isNumber = isNumber;
035                }
036                private Supplier<String> getTypeSupplier(CxxTypeMeta meta){
037                        switch(this){
038                    case TYPE_MAP:
039                        return meta.mapSupplier;
040                    case TYPE_SET:
041                        return meta.setSupplier;
042                    case TYPE_LIST:
043                        return meta.listSupplier;
044                    default:
045                        return meta.type;
046                        }
047                }
048        };
049    public static final CxxTypeMeta BOOL = new CxxTypeMeta(ThriftProtocolType.TYPE_BOOL, "bool");
050    public static final CxxTypeMeta BYTE = new CxxTypeMeta(ThriftProtocolType.TYPE_I8, "int8_t");
051    public static final CxxTypeMeta DOUBLE = new CxxTypeMeta(ThriftProtocolType.TYPE_DOUBLE, "double");
052    public static final CxxTypeMeta I16 = new CxxTypeMeta(ThriftProtocolType.TYPE_I16, "int16_t");
053    public static final CxxTypeMeta I32 = new CxxTypeMeta(ThriftProtocolType.TYPE_I32, "int32_t");
054    public static final CxxTypeMeta I64 = new CxxTypeMeta(ThriftProtocolType.TYPE_I64, "int64_t");
055    public static final CxxTypeMeta STRING = new CxxTypeMeta(ThriftProtocolType.TYPE_STRING, "std::string");
056    public static final CxxTypeMeta BINARY = new CxxTypeMeta(ThriftProtocolType.TYPE_BINARY, "std::string");
057    public static final CxxTypeMeta VOID = new CxxTypeMeta(ThriftProtocolType.TYPE_VOID, "void");
058        private Supplier<String> arraySupplier=new Supplier<String>(){  
059        @Override
060        public String get() {
061                StringBuilder sb = new StringBuilder();
062                sb.append("std::vector<")
063                        .append(valueType.getType()).append(">");
064                return  sb.toString();
065        }};
066        private Supplier<String> listSupplier=new Supplier<String>(){
067
068                @Override
069                public String get() {
070                        StringBuilder sb = new StringBuilder();
071                        sb.append("std::vector<")
072                                .append(valueType.getType()).append(">");
073                        return  sb.toString();  
074                }};
075        private Supplier<String> setSupplier=new Supplier<String>(){
076
077                @Override
078                public String get() {
079                        StringBuilder sb = new StringBuilder();
080                        sb.append("std::set<")
081                                .append(valueType.getType()).append(">");
082                        return  sb.toString();  
083                }};
084        private Supplier<String> mapSupplier = new Supplier<String>(){
085
086                @Override
087                public String get() {
088                StringBuilder sb = new StringBuilder();
089                        sb.append("std::map<")
090                                .append(keyType.getType()).append(",")
091                                .append(valueType.getType()).append(">");
092                        return sb.toString();
093                }};
094        private final ThriftProtocolType protocolType;
095        private final CxxTypeMeta keyType;
096        private final CxxTypeMeta valueType;
097        private final Supplier<String> type;
098        private final boolean isArray;
099        private static class NameSupplier implements Supplier<String>{
100                private String cxxType;
101
102                public NameSupplier(String cxxType) {
103                        super();
104                        checkArgument(null !=cxxType, "cxxType is null");
105                        this.cxxType = cxxType;
106                }
107
108                @Override
109                public String get() {
110                        return CxxHelper.getTypeName(cxxType);
111                }
112        }
113        static CxxTypeMeta struct(final String cxxType)
114    {           
115        Supplier<String> supplier = new NameSupplier(cxxType);
116        return new CxxTypeMeta(ThriftProtocolType.TYPE_STRUCT,supplier);
117    }
118
119    static CxxTypeMeta enumType(final String cxxType)
120        {
121        Supplier<String> supplier = new NameSupplier(cxxType);
122            return new CxxTypeMeta(ThriftProtocolType.TYPE_ENUM,supplier);
123        }
124
125        static <K, V> CxxTypeMeta map(CxxTypeMeta keyType, CxxTypeMeta valueType)
126    {
127        if(null == valueType || null == valueType){
128                return null;
129        }
130
131        return new CxxTypeMeta(ThriftProtocolType.TYPE_MAP, keyType, valueType, false);
132    }
133        static <E> CxxTypeMeta set(CxxTypeMeta valueType)
134    {
135                 if(null == valueType){
136                        return null;
137             }
138
139        return new CxxTypeMeta(ThriftProtocolType.TYPE_SET, null, valueType, false);
140    }
141
142    static <E> CxxTypeMeta list(CxxTypeMeta valueType)
143    {
144         if(null == valueType){
145                return null;
146         }
147
148        return new CxxTypeMeta(ThriftProtocolType.TYPE_LIST, null, valueType, false);
149    }
150    static CxxTypeMeta array(CxxTypeMeta valueType)
151    {
152        if(null == valueType){
153                return null;
154        }
155        return new CxxTypeMeta(ThriftProtocolType.TYPE_LIST, null, valueType, true);
156    }
157    /**
158     * 容器类型构造方法<br>
159     * {@code isAray}为{@code true}且{@code valueType}为BYTE时,也允许{@code protocolType}为BINARY
160     * @param protocolType
161     * @param keyType
162     * @param valueType
163     * @param isArray 
164     */
165    private CxxTypeMeta(ThriftProtocolType protocolType, CxxTypeMeta keyType, CxxTypeMeta valueType, boolean isArray)
166    {
167        checkArgument(null !=protocolType, "protocolType is null");        
168        checkArgument(protocolType.equals(ThriftProtocolType.TYPE_BINARY) || protocolType.isContainer, "protocolType must be SET,MAP,LIST,BINARY");
169        if(isArray){
170                checkArgument(protocolType.equals(ThriftProtocolType.TYPE_LIST) || protocolType.equals(ThriftProtocolType.TYPE_BINARY),"protocolType must be LIST or BINARY,if isArray");
171                if(protocolType.equals(ThriftProtocolType.TYPE_BINARY)){
172                        checkArgument(BYTE.equals(valueType),"valueType must be BYTE,if isArray is true and protocolType is TYPE_LIST");
173                }
174        }
175        this.protocolType = protocolType;
176        this.isArray=isArray;
177        this.type = isArray? arraySupplier : protocolType.getTypeSupplier(this);
178        this.keyType = keyType;
179        this.valueType = checkNotNull(valueType,"valueType is null");
180    }
181    /**
182     * 简单类型构造方法
183     * @param protocolType
184     * @param cxxType
185     */
186    private CxxTypeMeta(ThriftProtocolType protocolType, String cxxType){
187        this(protocolType,Suppliers.ofInstance(checkNotNull(cxxType, "cxxType is null")));
188        }
189    /**
190     * 非容器类型构造方法
191     * @param protocolType
192     * @param cxxType
193     */
194    private CxxTypeMeta(ThriftProtocolType protocolType, Supplier<String> cxxType){
195        checkNotNull(protocolType, "protocolType is null"); 
196        checkArgument(!protocolType.isContainer, "protocolType must not be SET,MAP,LIST");        
197        checkNotNull(cxxType, "cxxType is null");        
198        this.protocolType = protocolType;
199        this.isArray = false;
200        this.type = cxxType;
201        this.keyType = null;
202        this.valueType = null;
203        }
204        public String getType(){
205                return type.get();
206        }
207        public String getSampleType(){
208                if(protocolType==ThriftProtocolType.TYPE_STRUCT || protocolType==ThriftProtocolType.TYPE_ENUM){
209                        return CxxHelper.simpleName(type.get());
210                }
211                return type.get();
212        }
213        public String getFullType(){
214                if(type instanceof NameSupplier){
215                        return ((NameSupplier)type).cxxType;
216                }else{
217                        return type.get();
218                }
219        }
220        public String getNamespace(){
221                if(type instanceof NameSupplier){
222                        return CxxHelper.getCxxNamespace(((NameSupplier)type).cxxType);
223                }else{
224                        return CxxHelper.getCxxNamespace(type.get());
225                }
226        }
227        public CxxTypeMeta getKeyType() {
228                return keyType;
229        }
230        public CxxTypeMeta getValueType() {
231                return valueType;
232        }
233
234        public ThriftProtocolType getProtocolType() {
235                return protocolType;
236        }
237        public boolean isBool(){
238                return ThriftProtocolType.TYPE_BOOL.equals(getProtocolType());
239        }
240        public boolean isVoid(){
241                return ThriftProtocolType.TYPE_VOID.equals(getProtocolType());
242        }
243        public boolean isString(){
244                return ThriftProtocolType.TYPE_STRING.equals(getProtocolType());
245        }
246        public boolean isBinary(){
247                return ThriftProtocolType.TYPE_BINARY.equals(getProtocolType());
248        }
249        public boolean isMap() {
250                return ThriftProtocolType.TYPE_MAP.equals(getProtocolType());
251        }
252        public boolean isSet() {
253                return ThriftProtocolType.TYPE_SET.equals(getProtocolType());
254        }
255        public boolean isList() {
256                return ThriftProtocolType.TYPE_LIST.equals(getProtocolType());
257        }
258        public boolean isEnum() {
259                return ThriftProtocolType.TYPE_ENUM.equals(getProtocolType());
260        }
261        public boolean isStruct() {
262                return ThriftProtocolType.TYPE_STRUCT.equals(getProtocolType());
263        }
264        public boolean isContainer(){
265                return this.getProtocolType().isContainer;
266        }
267        public boolean isBaseType(){
268                return this.getProtocolType().isBaseType;
269        }
270        
271        public boolean isNumber(){
272                return getProtocolType().isNumber;
273        }
274        public boolean isArray() {
275                return isArray;
276        }
277
278        public boolean isByValue(){
279                return isBool() || isNumber() || isEnum();
280        }
281        public boolean isByReference(){
282                return !isByValue() && !isVoid();
283        }
284        public boolean isCanMove(){
285                return isBinary() || isString() || isContainer() || isStruct();
286        }
287        /**
288         * 类名转换,不含namespace
289         * @param name
290         * @return
291         */
292        public CxxTypeMeta castName(String name){
293                checkArgument(null !=name, "ns is null");
294                checkArgument(isEnum() || isStruct(),"only ENUM or STRUCT can be cast namespace");
295        return new CxxTypeMeta(protocolType,getNamespace() + "::" + name);
296        }
297        /**
298         * 类型转换
299         * @param cxxType
300         * @return
301         */
302        public CxxTypeMeta cast(String cxxType){
303                checkArgument(null !=cxxType, "cxxType is null");
304        return new CxxTypeMeta(protocolType,cxxType);
305        }
306        /**
307         * 类型转换
308         * @param keyType
309         * @param valueType
310         * @param isArray
311         * @return
312         */
313        public CxxTypeMeta cast(CxxTypeMeta keyType, CxxTypeMeta valueType, boolean isArray){
314                return new CxxTypeMeta(protocolType,keyType,valueType,isArray);
315        }
316@Override
317        public String toString() {
318                StringBuilder builder = new StringBuilder();
319                builder.append("CxxTypeMeta [protocolType=");
320                builder.append(protocolType);
321                builder.append(", type=");
322                builder.append(type.get());
323                builder.append(", isArray=");
324                builder.append(isArray);
325                builder.append("]");
326                return builder.toString();
327        }
328        @Override
329        public int hashCode() {
330                final int prime = 31;
331                int result = 1;
332                result = prime * result + ((protocolType == null) ? 0 : protocolType.hashCode());
333                result = prime * result + ((type == null) ? 0 : type.get().hashCode());
334                return result;
335        }
336        @Override
337        public boolean equals(Object obj) {
338                if (this == obj)
339                        return true;
340                if (obj == null)
341                        return false;
342                if (getClass() != obj.getClass())
343                        return false;
344                CxxTypeMeta other = (CxxTypeMeta) obj;
345                if (protocolType != other.protocolType)
346                        return false;
347                if (type == null) {
348                        if (other.type != null)
349                                return false;
350                } else if (!type.get().equals(other.type.get()))
351                        return false;
352                return true;
353        }
354
355}