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, "uint8_t"); 051 public static final CxxTypeMeta DOUBLE = new CxxTypeMeta(ThriftProtocolType.TYPE_DOUBLE, "double"); 052 public static final CxxTypeMeta I16 = new CxxTypeMeta(ThriftProtocolType.TYPE_I16, "uint16_t"); 053 public static final CxxTypeMeta I32 = new CxxTypeMeta(ThriftProtocolType.TYPE_I32, "uint32_t"); 054 public static final CxxTypeMeta I64 = new CxxTypeMeta(ThriftProtocolType.TYPE_I64, "uint64_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 checkState(keyType != null, "%s does not have a key", protocolType); 229 return keyType; 230 } 231 public CxxTypeMeta getValueType() { 232 checkState(valueType != null, "%s does not have a value", protocolType); 233 return valueType; 234 } 235 236 public ThriftProtocolType getProtocolType() { 237 return protocolType; 238 } 239 public boolean isBool(){ 240 return ThriftProtocolType.TYPE_BOOL.equals(getProtocolType()); 241 } 242 public boolean isVoid(){ 243 return ThriftProtocolType.TYPE_VOID.equals(getProtocolType()); 244 } 245 public boolean isString(){ 246 return ThriftProtocolType.TYPE_STRING.equals(getProtocolType()); 247 } 248 public boolean isBinary(){ 249 return ThriftProtocolType.TYPE_BINARY.equals(getProtocolType()); 250 } 251 public boolean isMap() { 252 return ThriftProtocolType.TYPE_MAP.equals(getProtocolType()); 253 } 254 public boolean isSet() { 255 return ThriftProtocolType.TYPE_SET.equals(getProtocolType()); 256 } 257 public boolean isList() { 258 return ThriftProtocolType.TYPE_LIST.equals(getProtocolType()); 259 } 260 public boolean isEnum() { 261 return ThriftProtocolType.TYPE_ENUM.equals(getProtocolType()); 262 } 263 public boolean isStruct() { 264 return ThriftProtocolType.TYPE_STRUCT.equals(getProtocolType()); 265 } 266 public boolean isContainer(){ 267 return this.getProtocolType().isContainer; 268 } 269 public boolean isBaseType(){ 270 return this.getProtocolType().isBaseType; 271 } 272 273 public boolean isNumber(){ 274 return getProtocolType().isNumber; 275 } 276 public boolean isArray() { 277 return isArray; 278 } 279 280 public boolean isByValue(){ 281 return isBool() || isNumber() || isEnum(); 282 } 283 public boolean isByReference(){ 284 return !isByValue(); 285 } 286 public boolean isCanMove(){ 287 return isBinary() || isString() || isContainer() || isStruct(); 288 } 289 public boolean isRaii(){ 290 return isBinary() || isString() || isContainer(); 291 } 292 /** 293 * 类型namespace转换 294 * @param ns 新的名字空间 295 * @return 296 */ 297 public CxxTypeMeta castNamespace(String ns){ 298 checkArgument(null !=ns, "ns is null"); 299 if(!ns.isEmpty() && !ns.endsWith("::")){ 300 ns = ns+"::"; 301 } 302 if(isContainer()){ 303 CxxTypeMeta k = (null != keyType)?keyType.castNamespace(ns) : null; 304 CxxTypeMeta v = (null != valueType)?valueType.castNamespace(ns) : null; 305 return cast(k,v,isArray); 306 }else{ 307 if(isEnum() || isStruct()){ 308 String name = CxxHelper.simpleName(getType()); 309 return new CxxTypeMeta(protocolType,ns + name); 310 }else{ 311 return this; 312 } 313 } 314 } 315 /** 316 * 类名转换,不含namespace 317 * @param name 318 * @return 319 */ 320 public CxxTypeMeta castName(String name){ 321 checkArgument(null !=name, "ns is null"); 322 checkArgument(isEnum() || isStruct(),"only ENUM or STRUCT can be cast namespace"); 323 return new CxxTypeMeta(protocolType,getNamespace() + "::" + name); 324 } 325 /** 326 * 类型转换 327 * @param cxxType 328 * @return 329 */ 330 public CxxTypeMeta cast(String cxxType){ 331 checkArgument(null !=cxxType, "cxxType is null"); 332 return new CxxTypeMeta(protocolType,cxxType); 333 } 334 /** 335 * 类型转换 336 * @param keyType 337 * @param valueType 338 * @param isArray 339 * @return 340 */ 341 public CxxTypeMeta cast(CxxTypeMeta keyType, CxxTypeMeta valueType, boolean isArray){ 342 return new CxxTypeMeta(protocolType,keyType,valueType,isArray); 343 } 344@Override 345 public String toString() { 346 StringBuilder builder = new StringBuilder(); 347 builder.append("CxxTypeMeta [protocolType="); 348 builder.append(protocolType); 349 builder.append(", type="); 350 builder.append(type.get()); 351 builder.append(", isArray="); 352 builder.append(isArray); 353 builder.append("]"); 354 return builder.toString(); 355 } 356 @Override 357 public int hashCode() { 358 final int prime = 31; 359 int result = 1; 360 result = prime * result + ((protocolType == null) ? 0 : protocolType.hashCode()); 361 result = prime * result + ((type == null) ? 0 : type.get().hashCode()); 362 return result; 363 } 364 @Override 365 public boolean equals(Object obj) { 366 if (this == obj) 367 return true; 368 if (obj == null) 369 return false; 370 if (getClass() != obj.getClass()) 371 return false; 372 CxxTypeMeta other = (CxxTypeMeta) obj; 373 if (protocolType != other.protocolType) 374 return false; 375 if (type == null) { 376 if (other.type != null) 377 return false; 378 } else if (!type.get().equals(other.type.get())) 379 return false; 380 return true; 381 } 382 383}