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