|  | import time | 
|  | import os | 
|  | import os.path | 
|  | from string import Template | 
|  | from parser import * | 
|  | from generator import * | 
|  |  | 
|  | HEADER_COMMENT = """/** | 
|  | * Autogenerated by Thrift | 
|  | * ${date} | 
|  | * | 
|  | * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING | 
|  | */ | 
|  | """ | 
|  |  | 
|  | CPP_TYPES_HEADER = Template(HEADER_COMMENT+""" | 
|  | #if !defined(${source}_types_h_) | 
|  | #define ${source}_types_h_ 1 | 
|  |  | 
|  | #include <Thrift.h> | 
|  | ${namespacePrefix} | 
|  | """) | 
|  |  | 
|  | CPP_TYPES_FOOTER = Template(""" | 
|  | ${namespaceSuffix} | 
|  | #endif // !defined(${source}_types_h_) | 
|  | """) | 
|  |  | 
|  | CPP_SERVICES_HEADER = Template(HEADER_COMMENT+""" | 
|  | #if !defined(${source}_h_) | 
|  | #define ${source}_h_ 1 | 
|  |  | 
|  | #include <Thrift.h> | 
|  | #include <TProcessor.h> | 
|  | #include <protocol/TProtocol.h> | 
|  | #include <transport/TTransport.h> | 
|  | #include \"${source}_types.h\" | 
|  |  | 
|  | ${namespacePrefix} | 
|  | """) | 
|  |  | 
|  | CPP_SERVICES_FOOTER = Template(""" | 
|  | ${namespaceSuffix} | 
|  | #endif // !defined(${source}_h_)""") | 
|  |  | 
|  | CPP_IMPL_HEADER = Template(HEADER_COMMENT+""" | 
|  | #include \"${source}.h\" | 
|  |  | 
|  | ${namespacePrefix} | 
|  | """) | 
|  |  | 
|  | CPP_IMPL_FOOTER = Template(""" | 
|  | ${namespaceSuffix} | 
|  | """) | 
|  |  | 
|  | def cpp_debug(arg): | 
|  | print(arg) | 
|  |  | 
|  | class Indenter(object): | 
|  | def __init__(self, level=0, step=4): | 
|  | self.level = level | 
|  | self.step = step | 
|  | self.chunk = "" | 
|  | for i in range(step): | 
|  | self.chunk+= " " | 
|  | self.prefix="" | 
|  |  | 
|  | def inc(self): | 
|  | self.level+= self.step | 
|  | self.prefix += self.chunk | 
|  |  | 
|  | def dec(self): | 
|  | self.level-= self.step | 
|  | if(self.level < 0): | 
|  | raise Exception, "Illegal indent level" | 
|  | self.prefix = self.prefix[:self.level] | 
|  |  | 
|  | def __call__(self): | 
|  | return  self.prefix | 
|  |  | 
|  | class CFile(file): | 
|  |  | 
|  | def __init__(self, name, flags): | 
|  | file.__init__(self, name, flags) | 
|  | self.indent = Indenter() | 
|  | self.newline = True | 
|  |  | 
|  | def rwrite(self, value): | 
|  | file.write(self, value) | 
|  |  | 
|  | def write(self, value=""): | 
|  | if self.newline: | 
|  | self.rwrite(self.indent()) | 
|  | self.newline = False | 
|  | self.rwrite(value) | 
|  |  | 
|  | def writeln(self, value=""): | 
|  | self.write(value+"\n") | 
|  | self.newline = True | 
|  |  | 
|  | def beginBlock(self): | 
|  | self.writeln("{") | 
|  | self.indent.inc(); | 
|  |  | 
|  | def endBlock(self, suffix=""): | 
|  | self.indent.dec(); | 
|  | self.writeln("}"+suffix) | 
|  |  | 
|  | CPP_PRIMITIVE_MAP = { | 
|  | "void" : "void", | 
|  | "bool" : "bool", | 
|  | "string": "std::string", | 
|  | "utf7": "std::string", | 
|  | "utf8": "std::wstring", | 
|  | "utf16": "std::utf16", | 
|  | "byte" : "uint8_t", | 
|  | "i08": "int8_t", | 
|  | "i16": "int16_t", | 
|  | "i32": "int32_t", | 
|  | "i64": "int64_t", | 
|  | "u08": "uint8_t", | 
|  | "u16": "uint16_t", | 
|  | "u32": "uint32_t", | 
|  | "u64": "uint64_t", | 
|  | "float": "float", | 
|  | "double": "double" | 
|  | } | 
|  |  | 
|  | CPP_CONTAINER_MAP = { | 
|  | MapType : "std::map", | 
|  | ListType: "std::list", | 
|  | SetType : "std::set", | 
|  | } | 
|  |  | 
|  | def toCNamespacePrefix(namespace): | 
|  | if not namespace: | 
|  | return "" | 
|  | else: | 
|  | return string.join(["namespace "+token + " {" for token in string.split(namespace, ".")], " ") | 
|  |  | 
|  | def toCNamespaceSuffix(namespace): | 
|  | if not namespace: | 
|  | return "" | 
|  | else: | 
|  | return string.join(["}" for token in string.split(namespace, ".")], "") | 
|  |  | 
|  | def toCTypeDeclaration(ttype): | 
|  | """ Converts the thrift IDL type to the corresponding C/C++ type.  Note that if ttype is FieldType, this function c | 
|  | converts to type declaration followed by field name, i.e. \"string string_thing\"""" | 
|  |  | 
|  | if isinstance(ttype, PrimitiveType): | 
|  | return CPP_PRIMITIVE_MAP[ttype.name] | 
|  |  | 
|  | elif isinstance(ttype, CollectionType): | 
|  |  | 
|  | result = CPP_CONTAINER_MAP[type(ttype)]+"<" | 
|  |  | 
|  | if isinstance(ttype, MapType): | 
|  | result+= toCTypeDeclaration(ttype.keyType)+", "+ toCTypeDeclaration(ttype.valueType) | 
|  |  | 
|  | elif isinstance(ttype, SetType) or isinstance(ttype, ListType): | 
|  | result+= toCTypeDeclaration(ttype.valueType) | 
|  |  | 
|  | else: | 
|  | raise Exception, "Unknown Collection Type "+str(ttype) | 
|  |  | 
|  | result+= "> " | 
|  |  | 
|  | return result | 
|  |  | 
|  | elif isinstance(ttype, StructType): | 
|  | return "struct "+ttype.name | 
|  |  | 
|  | elif isinstance(ttype, TypedefType): | 
|  | return ttype.name; | 
|  |  | 
|  | elif isinstance(ttype, EnumType): | 
|  | return ttype.name; | 
|  |  | 
|  | elif isinstance(ttype, Function): | 
|  | result = toCTypeDeclaration(ttype.returnType())+ " "+ttype.name+"("+string.join([toCTypeDeclaration(arg) for arg in ttype.args()], ", ")+")" | 
|  | if len(ttype.exceptions()): | 
|  | result+= " throw("+string.join([toCTypeDeclaration(exceptions.type) for exceptions in ttype.exceptions()], ", ")+")" | 
|  | return result | 
|  |  | 
|  | elif isinstance(ttype, Field): | 
|  | return toCTypeDeclaration(ttype.type)+ " "+ttype.name | 
|  |  | 
|  | else: | 
|  | raise Exception, "Unknown type "+str(ttype) | 
|  |  | 
|  | def toTypeDefDefinition(typedef): | 
|  | """ Converts a thrift typedef to a C/C++ typedef """ | 
|  |  | 
|  | return "typedef "+toCTypeDeclaration(typedef.definitionType)+" "+typedef.name+";" | 
|  |  | 
|  | def toEnumDefinition(enum): | 
|  | """ Converts a thrift enum to a C/C++ enum """ | 
|  |  | 
|  | result = "enum "+enum.name+" {\n" | 
|  |  | 
|  | first = True | 
|  |  | 
|  | for ed in enum.enumDefs: | 
|  | if first: | 
|  | first = False | 
|  | else: | 
|  | result+= ",\n" | 
|  | result+= "    "+ed.name+" = "+str(ed.id) | 
|  |  | 
|  | result+= "\n};\n" | 
|  |  | 
|  | return result | 
|  |  | 
|  | def toStructDefinition(struct): | 
|  | """Converts a thrift struct to a C/C++ struct""" | 
|  |  | 
|  | result = "struct "+struct.name+" {\n" | 
|  |  | 
|  | # Create constructor defaults for primitive types | 
|  |  | 
|  | ctorValues = string.join([field.name+"(0)" for field in struct.fieldList if isinstance(toCanonicalType(field.type), PrimitiveType) and toCanonicalType(field.type) not in [STRING_TYPE, UTF8_TYPE, UTF16_TYPE, VOID_TYPE]], ", ") | 
|  |  | 
|  | if len(ctorValues) > 0: | 
|  | result+= "    "+struct.name+"() : "+ctorValues+ " {}\n" | 
|  |  | 
|  | # Field declarations | 
|  |  | 
|  | result+= string.join(["    "+toCTypeDeclaration(field)+";\n" for field in struct.fieldList if toCanonicalType(field.type) != VOID_TYPE], "") | 
|  |  | 
|  | # is-field-set struct and ctor | 
|  |  | 
|  | ctorValues = string.join([field.name+"(false)" for field in struct.fieldList if toCanonicalType(field.type) != VOID_TYPE], ", ") | 
|  |  | 
|  | if len(ctorValues) > 0: | 
|  | result+= "    struct __isset {\n" | 
|  | result+= "        __isset() : "+ctorValues+" {}\n" | 
|  | result+= string.join(["        bool "+field.name+";\n" for field in struct.fieldList if toCanonicalType(field.type) != VOID_TYPE], "") | 
|  | result+= "   } __isset;\n" | 
|  |  | 
|  | # bring it on home | 
|  |  | 
|  | result+= "};\n" | 
|  |  | 
|  | return result | 
|  |  | 
|  | CPP_DEFINITION_MAP = { | 
|  | TypedefType : toTypeDefDefinition, | 
|  | EnumType : toEnumDefinition, | 
|  | StructType : toStructDefinition, | 
|  | ExceptionType : toStructDefinition, | 
|  | Service : None | 
|  | } | 
|  |  | 
|  | def toDefinitions(definitions): | 
|  | """Converts an arbitrafy thrift grammatical unit definition to the corresponding C/C++ definition""" | 
|  |  | 
|  | result = "" | 
|  |  | 
|  | for definition in definitions: | 
|  |  | 
|  | writer = CPP_DEFINITION_MAP[type(definition)] | 
|  |  | 
|  | if writer: | 
|  | result+= writer(definition)+"\n" | 
|  |  | 
|  | return result | 
|  |  | 
|  | CPP_THRIFT_NS = "facebook::thrift" | 
|  |  | 
|  | CPP_INTERFACE_FUNCTION_DECLARATION = Template("""    virtual ${functionDeclaration} = 0; | 
|  | """) | 
|  |  | 
|  | CPP_INTERFACE_DECLARATION = Template(""" | 
|  | class ${service}If { | 
|  | public: | 
|  | virtual ~${service}If() {} | 
|  | ${functionDeclarations}}; | 
|  | """) | 
|  |  | 
|  | def toServiceInterfaceDeclaration(service, debugp=None): | 
|  | """Converts a thrift service definition into a C++ abstract base class""" | 
|  |  | 
|  | functionDeclarations = string.join([CPP_INTERFACE_FUNCTION_DECLARATION.substitute(service=service.name, functionDeclaration=toCTypeDeclaration(function)) for function in service.functionList], "") | 
|  |  | 
|  | return CPP_INTERFACE_DECLARATION.substitute(service=service.name, functionDeclarations=functionDeclarations) | 
|  |  | 
|  | CPP_EXCEPTION = CPP_THRIFT_NS+"::Exception" | 
|  |  | 
|  | CPP_SP = Template("boost::shared_ptr<${klass}> ") | 
|  |  | 
|  | CPP_PROCESSOR = CPP_THRIFT_NS+"::TProcessor" | 
|  | CPP_PROCESSORP = CPP_SP.substitute(klass=CPP_PROCESSOR) | 
|  |  | 
|  | CPP_PROTOCOL_NS = CPP_THRIFT_NS+"::protocol" | 
|  | CPP_PROTOCOL = CPP_PROTOCOL_NS+"::TProtocol" | 
|  | CPP_PROTOCOLP = CPP_SP.substitute(klass="const "+CPP_PROTOCOL) | 
|  |  | 
|  |  | 
|  | CPP_TRANSPORT_NS = CPP_THRIFT_NS+"::transport" | 
|  | CPP_TRANSPORT = CPP_TRANSPORT_NS+"::TTransport" | 
|  | CPP_TRANSPORTP = CPP_SP.substitute(klass=CPP_TRANSPORT) | 
|  |  | 
|  | CPP_PROTOCOL_TSTOP = CPP_PROTOCOL_NS+"::T_STOP" | 
|  | CPP_PROTOCOL_TTYPE = CPP_PROTOCOL_NS+"::TType" | 
|  | CPP_PROTOCOL_MESSAGE_TYPE = CPP_PROTOCOL_NS+"::TMessageType" | 
|  | CPP_PROTOCOL_CALL = CPP_PROTOCOL_NS+"::T_CALL" | 
|  | CPP_PROTOCOL_REPLY = CPP_PROTOCOL_NS+"::T_REPLY" | 
|  |  | 
|  | CPP_TTYPE_MAP = { | 
|  | STOP_TYPE : CPP_PROTOCOL_NS+"::T_STOP", | 
|  | VOID_TYPE : CPP_PROTOCOL_NS+"::T_VOID", | 
|  | BOOL_TYPE : CPP_PROTOCOL_NS+"::T_BOOL", | 
|  | UTF7_TYPE : CPP_PROTOCOL_NS+"::T_UTF7", | 
|  | UTF7_TYPE : CPP_PROTOCOL_NS+"::T_UTF7", | 
|  | UTF8_TYPE : CPP_PROTOCOL_NS+"::T_UTF8", | 
|  | UTF16_TYPE : CPP_PROTOCOL_NS+"::T_UTF16", | 
|  | U08_TYPE : CPP_PROTOCOL_NS+"::T_U08", | 
|  | I08_TYPE : CPP_PROTOCOL_NS+"::T_I08", | 
|  | I16_TYPE : CPP_PROTOCOL_NS+"::T_I16", | 
|  | I32_TYPE : CPP_PROTOCOL_NS+"::T_I32", | 
|  | I64_TYPE : CPP_PROTOCOL_NS+"::T_I64", | 
|  | U08_TYPE : CPP_PROTOCOL_NS+"::T_U08", | 
|  | U16_TYPE : CPP_PROTOCOL_NS+"::T_U16", | 
|  | U32_TYPE : CPP_PROTOCOL_NS+"::T_U32", | 
|  | U64_TYPE : CPP_PROTOCOL_NS+"::T_U64", | 
|  | FLOAT_TYPE : CPP_PROTOCOL_NS+"::T_FLOAT", | 
|  | DOUBLE_TYPE : CPP_PROTOCOL_NS+"::T_DOUBLE", | 
|  | StructType : CPP_PROTOCOL_NS+"::T_STRUCT", | 
|  | ExceptionType : CPP_PROTOCOL_NS+"::T_STRUCT", | 
|  | ListType : CPP_PROTOCOL_NS+"::T_LIST", | 
|  | MapType : CPP_PROTOCOL_NS+"::T_MAP", | 
|  | SetType : CPP_PROTOCOL_NS+"::T_SET" | 
|  | } | 
|  |  | 
|  |  | 
|  | CPP_SERVER_FUNCTION_DECLARATION = Template("""    void process_${function}(uint32_t seqid, """+CPP_TRANSPORTP+""" itrans, """+CPP_TRANSPORTP+""" otrans); | 
|  | """) | 
|  |  | 
|  | CPP_SERVER_FUNCTION_DEFINITION = Template(""" | 
|  | void ${service}ServerIf::process_${function}(uint32_t seqid, """+CPP_TRANSPORTP+""" itrans, """+CPP_TRANSPORTP+""" otrans) { | 
|  |  | 
|  | uint32_t xfer = 0; | 
|  |  | 
|  | ${argsStructDeclaration}; | 
|  |  | 
|  | ${argsStructReader}; | 
|  |  | 
|  | _iprot->readMessageEnd(itrans); | 
|  |  | 
|  | ${resultStructDeclaration}; | 
|  |  | 
|  | ${functionCall} | 
|  |  | 
|  | _oprot->writeMessageBegin(otrans, \"${function}\", """+CPP_PROTOCOL_REPLY+""", seqid); | 
|  |  | 
|  | ${resultStructWriter}; | 
|  |  | 
|  | _oprot->writeMessageEnd(otrans); | 
|  |  | 
|  | otrans->flush(); | 
|  | } | 
|  | """) | 
|  |  | 
|  | CPP_SERVER_PROCESS_DEFINITION = Template(""" | 
|  | bool ${service}ServerIf::process("""+CPP_TRANSPORTP+""" itrans, """+CPP_TRANSPORTP+""" otrans) { | 
|  |  | 
|  | std::string name; | 
|  |  | 
|  | """+CPP_PROTOCOL_MESSAGE_TYPE+""" messageType; | 
|  |  | 
|  | uint32_t seqid; | 
|  |  | 
|  | _iprot->readMessageBegin(itrans, name, messageType, seqid); | 
|  |  | 
|  | if(messageType == """+CPP_PROTOCOL_CALL+""") { | 
|  | ${callProcessSwitch} | 
|  | } else { | 
|  | throw """+CPP_EXCEPTION+"""(\"Unexpected message type\"); | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  | """) | 
|  |  | 
|  | def toWireType(ttype): | 
|  | """Converts a thrift type to the corresponding wire type.   This differs from toCTypeDeclaration in that it reduces typedefs | 
|  | to their canonical form and converts enums to signedf 32 bit integers""" | 
|  |  | 
|  | if isinstance(ttype, PrimitiveType): | 
|  | return CPP_TTYPE_MAP[ttype] | 
|  |  | 
|  | elif isinstance(ttype, EnumType): | 
|  | return CPP_TTYPE_MAP[I32_TYPE] | 
|  |  | 
|  | elif isinstance(ttype, TypedefType): | 
|  | return toWireType(toCanonicalType(ttype)) | 
|  |  | 
|  | elif isinstance(ttype, StructType) or isinstance(ttype, CollectionType): | 
|  | return CPP_TTYPE_MAP[type(ttype)] | 
|  |  | 
|  | else: | 
|  | raise Exception, "No wire type for thrift type: "+str(ttype) | 
|  |  | 
|  | CPP_SERVER_DECLARATION = Template(""" | 
|  | class ${service}ServerIf : public ${service}If, public """+CPP_PROCESSOR+""" { | 
|  | public: | 
|  | ${service}ServerIf("""+CPP_PROTOCOLP+""" protocol): _iprot(protocol), _oprot(protocol) {} | 
|  | ${service}ServerIf("""+CPP_PROTOCOLP+""" iprot, """+CPP_PROTOCOLP+""" oprot) : _iprot(iprot), _oprot(oprot) {} | 
|  | virtual ~${service}ServerIf() {} | 
|  | bool process("""+CPP_TRANSPORTP+""" _itrans,"""+CPP_TRANSPORTP+""" _otrans); | 
|  | protected: | 
|  | """+CPP_PROTOCOLP+""" _iprot; | 
|  | """+CPP_PROTOCOLP+""" _oprot; | 
|  | private: | 
|  | ${functionDeclarations}}; | 
|  | """) | 
|  |  | 
|  | def toServerDeclaration(service, debugp=None): | 
|  | """Converts a thrift service definition to the Server skeleton class declaration.""" | 
|  |  | 
|  | functionDeclarations = string.join([CPP_SERVER_FUNCTION_DECLARATION.substitute(function=function.name) for function in service.functionList], "") | 
|  |  | 
|  | return CPP_SERVER_DECLARATION.substitute(service=service.name, functionDeclarations=functionDeclarations) | 
|  |  | 
|  | CPP_CLIENT_FUNCTION_DECLARATION = Template("""    ${functionDeclaration}; | 
|  | """) | 
|  |  | 
|  |  | 
|  | CPP_CLIENT_FUNCTION_DEFINITION = Template(""" | 
|  | ${returnDeclaration} ${service}Client::${function}(${argsDeclaration}) ${exceptionDeclaration} { | 
|  |  | 
|  | uint32_t xfer = 0; | 
|  | std::string name; | 
|  | """+CPP_PROTOCOL_MESSAGE_TYPE+""" messageType; | 
|  | uint32_t cseqid = 0; | 
|  | uint32_t rseqid = 0; | 
|  |  | 
|  | _oprot->writeMessageBegin(_otrans, \"${function}\", """+CPP_PROTOCOL_CALL+""", cseqid); | 
|  |  | 
|  | ${argsStructDeclaration}; | 
|  |  | 
|  | ${argsToStruct}; | 
|  |  | 
|  | ${argsStructWriter}; | 
|  |  | 
|  | _otrans->flush(); | 
|  |  | 
|  | _iprot->readMessageBegin(_itrans, name, messageType, rseqid); | 
|  |  | 
|  | if(messageType != """+CPP_PROTOCOL_REPLY+""" || | 
|  | rseqid != cseqid) { | 
|  | throw """+CPP_EXCEPTION+"""(\"unexpected message type or id\"); | 
|  | } | 
|  |  | 
|  | ${resultStructDeclaration}; | 
|  |  | 
|  | ${resultStructReader}; | 
|  |  | 
|  | _iprot->readMessageEnd(_itrans); | 
|  |  | 
|  | ${returnResult} | 
|  | throw """+CPP_EXCEPTION+"""(\"${function} failed: unknown result"); | 
|  | } | 
|  | """) | 
|  |  | 
|  | CPP_CLIENT_DECLARATION = Template(""" | 
|  | class ${service}Client : public ${service}If { | 
|  |  | 
|  | public: | 
|  |  | 
|  | ${service}Client("""+CPP_TRANSPORTP+""" transport, """+CPP_PROTOCOLP+""" protocol): _itrans(transport), _otrans(transport), _iprot(protocol), _oprot(protocol) {} | 
|  |  | 
|  | ${service}Client("""+CPP_TRANSPORTP+""" itrans, """+CPP_TRANSPORTP+""" otrans, """+CPP_PROTOCOLP+""" iprot, """+CPP_PROTOCOLP+""" oprot) : _itrans(itrans), _otrans(otrans), _iprot(iprot), _oprot(oprot) {} | 
|  |  | 
|  | ${functionDeclarations} | 
|  | private: | 
|  | """+CPP_TRANSPORTP+""" _itrans; | 
|  | """+CPP_TRANSPORTP+""" _otrans; | 
|  | """+CPP_PROTOCOLP+""" _iprot; | 
|  | """+CPP_PROTOCOLP+""" _oprot; | 
|  | };""") | 
|  |  | 
|  | def toServerFunctionDefinition(servicePrefix, function, debugp=None): | 
|  | """Converts a thrift service method declaration into a server method-call processoror function""" | 
|  | result = "" | 
|  |  | 
|  | argsStructDeclaration = toCTypeDeclaration(function.argsStruct)+" __args" | 
|  |  | 
|  | argsStructReader = toReaderCall("__args", function.argsStruct, "_iprot") | 
|  |  | 
|  | resultStructDeclaration = toCTypeDeclaration(function.resultStruct)+" __result" | 
|  |  | 
|  | resultStructWriter = toWriterCall("__result", function.resultStruct, "_oprot") | 
|  |  | 
|  | if toCanonicalType(function.returnType()) != VOID_TYPE: | 
|  | functionCallPrefix= "__result.success = " | 
|  | functionCallSuffix = "\n    __result.__isset.success = true;" | 
|  | else: | 
|  | functionCallPrefix = "" | 
|  | functionCallSuffix = "" | 
|  |  | 
|  | functionCall= function.name+"("+string.join(["__args."+arg.name for arg in function.args()], ", ")+");" | 
|  |  | 
|  | exceptions = function.exceptions() | 
|  |  | 
|  | if len(exceptions) > 0: | 
|  | functionCallPrefix= "try {\n        "+functionCallPrefix | 
|  |  | 
|  | functionCallSuffix+= "\n    }"+string.join([" catch("+toCTypeDeclaration(exceptions[ix].type)+"& e"+str(ix)+") {\n        __result."+exceptions[ix].name+" = e"+str(ix)+";\n        __result.__isset."+exceptions[ix].name+" = true;\n    }" | 
|  | for ix in range(len(exceptions))], "") | 
|  |  | 
|  | functionCall = functionCallPrefix+functionCall+functionCallSuffix | 
|  |  | 
|  | result+= CPP_SERVER_FUNCTION_DEFINITION.substitute(service=servicePrefix, function=function.name, | 
|  | argsStructDeclaration=argsStructDeclaration, | 
|  | argsStructReader=argsStructReader, | 
|  | functionCall=functionCall, | 
|  | resultStructDeclaration=resultStructDeclaration, | 
|  | resultStructWriter=resultStructWriter) | 
|  | return result | 
|  |  | 
|  | def toServerServiceDefinition(service, debugp=None): | 
|  | """Converts a thrift service definiton to a server skeleton implementation""" | 
|  |  | 
|  | result = "" | 
|  |  | 
|  | for function in service.functionList: | 
|  |  | 
|  | result+= toServerFunctionDefinition(service.name, function, debugp) | 
|  |  | 
|  | callProcessSwitch = "        if"+string.join(["(name.compare(\""+function.name+"\") == 0) { process_"+function.name+"(seqid, itrans, otrans);\n}" for function in service.functionList], "\n        else if")+" else {throw "+CPP_EXCEPTION+"(\"Unknown function name \\\"\"+name+\"\\\"\");}" | 
|  |  | 
|  | result+= CPP_SERVER_PROCESS_DEFINITION.substitute(service=service.name, callProcessSwitch=callProcessSwitch) | 
|  |  | 
|  | return result | 
|  |  | 
|  | def toServerDefinition(program, debugp=None): | 
|  |  | 
|  | return string.join([toServerServiceDefinition(service) for service in program.serviceMap.values()], "\n") | 
|  |  | 
|  | def toClientDeclaration(service, debugp=None): | 
|  |  | 
|  | functionDeclarations = string.join([CPP_CLIENT_FUNCTION_DECLARATION.substitute(functionDeclaration=toCTypeDeclaration(function)) for function in service.functionList], "") | 
|  |  | 
|  | return CPP_CLIENT_DECLARATION.substitute(service=service.name, functionDeclarations=functionDeclarations)+"\n" | 
|  |  | 
|  | def toClientFunctionDefinition(servicePrefix, function, debugp=None): | 
|  | """Converts a thrift service method declaration to a client stub implementation""" | 
|  |  | 
|  | isVoid = toCanonicalType(function.returnType()) == VOID_TYPE | 
|  |  | 
|  | returnDeclaration = toCTypeDeclaration(function.returnType()) | 
|  |  | 
|  | argsDeclaration = string.join([toCTypeDeclaration(function.args()[ix].type)+" __arg"+str(ix) for ix in range(len(function.args()))], ", ") | 
|  |  | 
|  | exceptionDeclaration = string.join([toCTypeDeclaration(exception.type) for exception in function.exceptions()], ", ") | 
|  |  | 
|  | if len(exceptionDeclaration)> 0: | 
|  | exceptionDeclaration = "throw("+exceptionDeclaration+")" | 
|  |  | 
|  | argsStructDeclaration = toCTypeDeclaration(function.argsStruct)+" __args" | 
|  |  | 
|  | argsStructWriter = toWriterCall("__args", function.argsStruct, "_oprot", "_otrans") | 
|  |  | 
|  | argsToStruct= string.join(["    __args."+function.args()[ix].name+" = __arg"+str(ix) for ix in range(len(function.args()))], ";\n") | 
|  |  | 
|  | resultStructDeclaration = toCTypeDeclaration(function.resultStruct)+" __result" | 
|  |  | 
|  | resultStructReader = toReaderCall("__result", function.resultStruct, "_iprot", "_itrans") | 
|  |  | 
|  | exceptions = function.exceptions() | 
|  |  | 
|  | """ void return and non-void returns require very different arrangments.  For void returns, we don't actually expect | 
|  | anything to have been sent from the remote side, therefore  we need to check for explicit exception returns first, | 
|  | then, if none were encountered, return.  For void we test for success first - since this is the most likey result - | 
|  | and then check for exceptions.  In both cases, we need to handle the case where there are no specified exceptions. """ | 
|  |  | 
|  | if len(exceptions) > 0: | 
|  | errors= ["if(__result.__isset."+exception.name+") {\n        throw  __result."+exception.name+";\n    }" for exception in exceptions] | 
|  | else: | 
|  | errors = [] | 
|  |  | 
|  | if not isVoid: | 
|  | returnResult = "    if(__result.__isset.success) {\n        return __result.success;\n}" | 
|  | if len(errors) > 0: | 
|  | returnResult+= " else "+string.join(errors, " else ") | 
|  | else: | 
|  | if len(errors) > 0: | 
|  | returnResult= "    "+string.join(errors, " else ")+" else {\n        return;\n    }\n" | 
|  | else: | 
|  | returnResult="    return;\n" | 
|  |  | 
|  | return CPP_CLIENT_FUNCTION_DEFINITION.substitute(service=servicePrefix, | 
|  | function=function.name, | 
|  | returnDeclaration=returnDeclaration, | 
|  | argsDeclaration=argsDeclaration, | 
|  | exceptionDeclaration=exceptionDeclaration, | 
|  | argsStructDeclaration=argsStructDeclaration, | 
|  | argsStructWriter=argsStructWriter, | 
|  | argsToStruct=argsToStruct, | 
|  | resultStructDeclaration=resultStructDeclaration, | 
|  | resultStructReader=resultStructReader, | 
|  | returnResult=returnResult) | 
|  |  | 
|  | def toClientServiceDefinition(service, debugp=None): | 
|  | """Converts a thrift service definition to a client stub implementation""" | 
|  |  | 
|  | result = "" | 
|  |  | 
|  | for function in service.functionList: | 
|  |  | 
|  | result+= toClientFunctionDefinition(service.name, function) | 
|  |  | 
|  | return result | 
|  |  | 
|  | def toClientDefinition(program, debugp=None): | 
|  | """Converts all services in a thrift program to client stub implementations""" | 
|  |  | 
|  | return string.join([toClientServiceDefinition(service) for service in program.serviceMap.values()], "\n") | 
|  |  | 
|  | def toServiceDeclaration(service, debugp=None): | 
|  | """Converts all services in a thrift program to service interface or abstract base class declarations""" | 
|  |  | 
|  | return toServiceInterfaceDeclaration(service, debugp) + toServerDeclaration(service, debugp) + toClientDeclaration(service, debugp) | 
|  |  | 
|  | def toGenDir(filename, suffix="cpp-gen", debugp=None): | 
|  | """creates a generated-code subdirectory for C++ code based on filename of thrift source file and optional suffix""" | 
|  |  | 
|  | result = os.path.join(os.path.split(filename)[0], suffix) | 
|  |  | 
|  | if not os.path.exists(result): | 
|  | os.mkdir(result) | 
|  |  | 
|  | return result | 
|  |  | 
|  | def toBasename(filename, debugp=None): | 
|  | """ Take the filename minus the path and\".thrift\" extension  if present """ | 
|  |  | 
|  | basename = os.path.split(filename)[1] | 
|  |  | 
|  | tokens = os.path.splitext(basename) | 
|  |  | 
|  | if tokens[1].lower() == ".thrift": | 
|  | basename = tokens[0] | 
|  |  | 
|  | if debugp: | 
|  | debugp("toBasename("+str(filename)+") => "+str(basename)) | 
|  |  | 
|  | return basename | 
|  |  | 
|  | def toDefinitionHeaderName(filename, genDir=None, debugp=None): | 
|  | """Creates a file name for the public thrift data types based on filename of thrift source file and optional suffix""" | 
|  |  | 
|  | if not genDir: | 
|  | genDir = toGenDir(filename) | 
|  |  | 
|  | basename = toBasename(filename) | 
|  |  | 
|  | result = os.path.join(genDir, basename+"_types.h") | 
|  |  | 
|  | if debugp: | 
|  | debugp("toDefinitionHeaderName("+str(filename)+", "+str(genDir)+") => "+str(basename)) | 
|  |  | 
|  | return result | 
|  |  | 
|  | def writeDefinitionHeader(program, filename, genDir=None, debugp=None): | 
|  | """Writes public thrift data types defined in program into a public data types header file.  Uses the name of the original | 
|  | thrift source, filename, and the optional generated C++ code directory, genDir, to determine the name and location of header file""" | 
|  |  | 
|  | definitionHeader = toDefinitionHeaderName(filename, genDir) | 
|  |  | 
|  | if debugp: | 
|  | debugp("definitionHeader: "+str(definitionHeader)) | 
|  |  | 
|  | cfile = CFile(definitionHeader, "w") | 
|  |  | 
|  | basename = toBasename(filename) | 
|  |  | 
|  | cfile.writeln(CPP_TYPES_HEADER.substitute(source=basename, date=time.ctime(), namespacePrefix=toCNamespacePrefix(program.namespace))) | 
|  |  | 
|  | cfile.write(toDefinitions(program.definitions)) | 
|  |  | 
|  | cfile.writeln(CPP_TYPES_FOOTER.substitute(source=basename, namespaceSuffix=toCNamespaceSuffix(program.namespace))) | 
|  |  | 
|  | cfile.close() | 
|  |  | 
|  | def toServicesHeaderName(filename, genDir=None, debugp=None): | 
|  | """Creates a file name for the public thrift services based on filename of thrift source file and optional suffix""" | 
|  |  | 
|  | if not genDir: | 
|  | genDir = toGenDir(filename) | 
|  |  | 
|  | basename = toBasename(filename) | 
|  |  | 
|  | result = os.path.join(genDir, basename+".h") | 
|  |  | 
|  | if debugp: | 
|  | debugp("toDefinitionHeaderName("+str(filename)+", "+str(genDir)+") => "+str(basename)) | 
|  |  | 
|  | return result | 
|  |  | 
|  | def writeServicesHeader(program, filename, genDir=None, debugp=None): | 
|  | """Writes public thrift service abstract base class, client class, and server class for all services defined in program into a public services header file.  Uses the name of the original thrift source, filename, and the optional generated C++ code directory, genDir, to determine the name and location of header file""" | 
|  |  | 
|  | servicesHeader = toServicesHeaderName(filename, genDir) | 
|  |  | 
|  | if debugp: | 
|  | debugp("servicesHeader: "+str(servicesHeader)) | 
|  |  | 
|  | cfile = CFile(servicesHeader, "w") | 
|  |  | 
|  | basename = toBasename(filename) | 
|  |  | 
|  | cfile.writeln(CPP_SERVICES_HEADER.substitute(source=basename, date=time.ctime(), namespacePrefix=toCNamespacePrefix(program.namespace))) | 
|  |  | 
|  | services = [] | 
|  |  | 
|  | # Build orderered list of service definitions by scanning definitions list for services | 
|  |  | 
|  | for definition in  program.definitions: | 
|  | if isinstance(definition, Service) and definition.name in program.serviceMap: | 
|  | services.append(definition) | 
|  |  | 
|  | for service in services: | 
|  |  | 
|  | cfile.write(toServiceDeclaration(service)) | 
|  |  | 
|  | cfile.writeln(CPP_SERVICES_FOOTER.substitute(source=basename, namespaceSuffix=toCNamespaceSuffix(program.namespace))) | 
|  |  | 
|  | cfile.close() | 
|  |  | 
|  |  | 
|  | CPP_STRUCT_READ = Template(""" | 
|  | uint32_t read${name}Struct("""+CPP_PROTOCOLP+""" _iprot, """+CPP_TRANSPORTP+""" itrans, ${declaration}& value) { | 
|  |  | 
|  | std::string name; | 
|  | uint32_t id; | 
|  | uint32_t type; | 
|  | uint32_t xfer = 0; | 
|  |  | 
|  | while(true) { | 
|  | xfer+= _iprot->readFieldBegin(_itrans, name, type, id); | 
|  | if(type == """+CPP_PROTOCOL_TSTOP+""") { | 
|  | break; | 
|  | } | 
|  | switch(id) { | 
|  | ${readFieldListSwitch} | 
|  | } | 
|  | } | 
|  |  | 
|  | xfer+= _iprot->readStructEnd(_itrans); | 
|  |  | 
|  | return xfer; | 
|  | } | 
|  | """) | 
|  |  | 
|  | CPP_PRIMITIVE_TYPE_IO_METHOD_SUFFIX_MAP = { | 
|  | "void" :"Void", | 
|  | "bool" : "Bool", | 
|  | "string": "String", | 
|  | "utf7": "String", | 
|  | "utf8": "String", | 
|  | "utf16": "String", | 
|  | "i08": "Byte", | 
|  | "i16": "I16", | 
|  | "i32": "I32", | 
|  | "i64": "I64", | 
|  | "u08": "Byte", | 
|  | "u16": "U16", | 
|  | "u32": "U32", | 
|  | "u64": "U64", | 
|  | "float": "Float", | 
|  | "double": "Double" | 
|  | } | 
|  |  | 
|  | CPP_COLLECTION_TYPE_IO_METHOD_SUFFIX_MAP = { | 
|  | MapType : "map", | 
|  | ListType : "list", | 
|  | SetType : "set" | 
|  | } | 
|  |  | 
|  | def typeToIOMethodSuffix(ttype): | 
|  | """Converts type to a name suitable as a suffix with TProtocol primitive read and write methods or with a generated read or write | 
|  | method for a complex type""" | 
|  |  | 
|  | if isinstance(ttype, PrimitiveType): | 
|  | return CPP_PRIMITIVE_TYPE_IO_METHOD_SUFFIX_MAP[ttype.name] | 
|  |  | 
|  | elif isinstance(ttype, CollectionType): | 
|  |  | 
|  | result = CPP_COLLECTION_TYPE_IO_METHOD_SUFFIX_MAP[type(ttype)]+"_" | 
|  |  | 
|  | if isinstance(ttype, MapType): | 
|  | result+= "k_"+typeToIOMethodSuffix(ttype.keyType)+"_" | 
|  |  | 
|  | result += "v_"+typeToIOMethodSuffix(ttype.valueType) | 
|  |  | 
|  | return result | 
|  |  | 
|  | elif isinstance(ttype, StructType): | 
|  | return "struct_"+ttype.name | 
|  |  | 
|  | elif isinstance(ttype, TypedefType): | 
|  | return ttype.name | 
|  |  | 
|  | elif isinstance(ttype, EnumType): | 
|  | return ttype.name | 
|  |  | 
|  | else: | 
|  | raise Exception, "Unknown type "+str(ttype) | 
|  |  | 
|  | def toReaderCall(value, ttype, reader="iprot", transport="itrans"): | 
|  | """Converts type to a name suitable as a suffix with TProtocol primitive read methods or with a generated read | 
|  | method for a complex type""" | 
|  |  | 
|  | suffix = typeToIOMethodSuffix(ttype) | 
|  |  | 
|  | if isinstance(ttype, PrimitiveType): | 
|  | if ttype != VOID_TYPE: | 
|  | return "xfer += "+reader+"->read"+suffix+"("+transport+", "+value+")" | 
|  | else: | 
|  | return "" | 
|  |  | 
|  | elif isinstance(ttype, CollectionType): | 
|  | return "xfer+= read_"+suffix+"("+reader+", "+transport+", "+value+")" | 
|  |  | 
|  | elif isinstance(ttype, StructType): | 
|  | return "xfer+= read_"+suffix+"("+reader+", "+transport+", "+value+")" | 
|  |  | 
|  | elif isinstance(ttype, TypedefType): | 
|  | return toReaderCall("reinterpret_cast<"+toCTypeDeclaration(ttype.definitionType)+"&>("+value+")", ttype.definitionType, reader) | 
|  |  | 
|  | elif isinstance(ttype, EnumType): | 
|  | return toReaderCall("reinterpret_cast<"+toCTypeDeclaration(I32_TYPE)+"&>("+value+")", I32_TYPE, reader) | 
|  |  | 
|  | else: | 
|  | raise Exception, "Unknown type "+str(ttype) | 
|  |  | 
|  | def toWriterCall(value, ttype, writer="oprot", transport="otrans"): | 
|  | """Converts type to a name suitable as a suffix with TProtocol primitive write methods or with a generated write | 
|  | method for a complex type""" | 
|  |  | 
|  | suffix = typeToIOMethodSuffix(ttype) | 
|  |  | 
|  | if isinstance(ttype, PrimitiveType): | 
|  | if ttype != VOID_TYPE: | 
|  | return "xfer+= "+writer+"->write"+suffix+"("+transport+", "+value+")" | 
|  | else: | 
|  | return "" | 
|  |  | 
|  | elif isinstance(ttype, CollectionType): | 
|  | return "xfer+= write_"+suffix+"("+writer+", "+transport+", "+value+")" | 
|  |  | 
|  | elif isinstance(ttype, StructType): | 
|  | return "xfer+= write_"+suffix+"("+writer+", "+transport+", "+value+")" | 
|  |  | 
|  | elif isinstance(ttype, TypedefType): | 
|  | return toWriterCall("reinterpret_cast<const "+toCTypeDeclaration(ttype.definitionType)+"&>("+value+")", ttype.definitionType, writer) | 
|  |  | 
|  | elif isinstance(ttype, EnumType): | 
|  | return toWriterCall("reinterpret_cast<const "+toCTypeDeclaration(I32_TYPE)+"&>("+value+")", I32_TYPE, writer) | 
|  |  | 
|  | else: | 
|  | raise Exception, "Unknown type "+str(ttype) | 
|  |  | 
|  | CPP_READ_MAP_DEFINITION = Template(""" | 
|  | uint32_t read_${suffix}("""+CPP_PROTOCOLP+""" iprot, """+CPP_TRANSPORTP+""" itrans, ${declaration}& value) { | 
|  |  | 
|  | uint32_t count; | 
|  | ${keyType} key; | 
|  | ${valueType} elem; | 
|  | uint32_t xfer = 0; | 
|  |  | 
|  | xfer += iprot->readU32(itrans, count); | 
|  |  | 
|  | for(uint32_t ix = 0; ix < count; ix++) { | 
|  | ${keyReaderCall}; | 
|  | ${valueReaderCall}; | 
|  | value.insert(std::make_pair(key, elem)); | 
|  | } | 
|  |  | 
|  | return xfer; | 
|  | } | 
|  | """) | 
|  |  | 
|  | CPP_WRITE_MAP_DEFINITION = Template(""" | 
|  | uint32_t write_${suffix}("""+CPP_PROTOCOLP+""" oprot, """+CPP_TRANSPORTP+""" otrans, const ${declaration}& value) { | 
|  |  | 
|  | uint32_t xfer = 0; | 
|  |  | 
|  | xfer += oprot->writeU32(otrans, value.size()); | 
|  |  | 
|  | for(${declaration}::const_iterator ix = value.begin(); ix != value.end(); ++ix) { | 
|  | ${keyWriterCall}; | 
|  | ${valueWriterCall}; | 
|  | } | 
|  | return xfer; | 
|  | } | 
|  | """) | 
|  |  | 
|  | CPP_READ_LIST_DEFINITION = Template(""" | 
|  | uint32_t read_${suffix}("""+CPP_PROTOCOLP+""" iprot, """+CPP_TRANSPORTP+""" itrans, ${declaration}& value) { | 
|  |  | 
|  | uint32_t count; | 
|  | ${valueType} elem; | 
|  | uint32_t xfer = 0; | 
|  |  | 
|  | xfer+= iprot->readU32(itrans,  count); | 
|  |  | 
|  | for(uint32_t ix = 0; ix < count; ix++) { | 
|  | ${valueReaderCall}; | 
|  | value.${insert}(elem); | 
|  | } | 
|  | return xfer; | 
|  | } | 
|  | """) | 
|  |  | 
|  | CPP_WRITE_LIST_DEFINITION = Template(""" | 
|  | uint32_t write_${suffix}("""+CPP_PROTOCOLP+""" oprot, """+CPP_TRANSPORTP+""" otrans, const ${declaration}& value) { | 
|  |  | 
|  | uint32_t xfer = 0; | 
|  |  | 
|  | xfer+= oprot->writeU32(otrans, value.size()); | 
|  |  | 
|  | for(${declaration}::const_iterator ix = value.begin(); ix != value.end(); ++ix) { | 
|  | ${valueWriterCall}; | 
|  | } | 
|  | return xfer; | 
|  | } | 
|  | """) | 
|  |  | 
|  | def toCollectionReaderDefinition(collection): | 
|  | """Converts collection type to reader function definition""" | 
|  |  | 
|  | suffix = typeToIOMethodSuffix(collection) | 
|  |  | 
|  | if isinstance(collection, MapType): | 
|  | keyReaderCall = toReaderCall("key", collection.keyType) | 
|  |  | 
|  | valueReaderCall= toReaderCall("elem", collection.valueType) | 
|  |  | 
|  | if isinstance(collection, MapType): | 
|  | return CPP_READ_MAP_DEFINITION.substitute(suffix=suffix, declaration=toCTypeDeclaration(collection), | 
|  | keyType=toCTypeDeclaration(collection.keyType), | 
|  | keyReaderCall=keyReaderCall, | 
|  | valueType=toCTypeDeclaration(collection.valueType), | 
|  | valueReaderCall=valueReaderCall) | 
|  |  | 
|  | else: | 
|  | if isinstance(collection, ListType): | 
|  | insert="push_back" | 
|  | else: | 
|  | insert="insert" | 
|  |  | 
|  | return CPP_READ_LIST_DEFINITION.substitute(suffix=suffix, declaration=toCTypeDeclaration(collection), | 
|  | valueReaderCall=valueReaderCall, | 
|  | valueType=toCTypeDeclaration(collection.valueType), | 
|  | insert=insert) | 
|  |  | 
|  |  | 
|  | def toCollectionWriterDefinition(collection): | 
|  | """Converts collection type to writer function definition""" | 
|  |  | 
|  | suffix = typeToIOMethodSuffix(collection) | 
|  |  | 
|  | if isinstance(collection, MapType): | 
|  | keyWriterCall = toWriterCall("ix->first", collection.keyType) | 
|  | valueWriterCall = toWriterCall("ix->second", collection.valueType) | 
|  |  | 
|  | else: | 
|  | valueWriterCall= toWriterCall("*ix", collection.valueType) | 
|  |  | 
|  | if isinstance(collection, MapType): | 
|  | return CPP_WRITE_MAP_DEFINITION.substitute(suffix=suffix, declaration=toCTypeDeclaration(collection), | 
|  | keyType=toCTypeDeclaration(collection.keyType), | 
|  | keyWriterCall=keyWriterCall, | 
|  | valueType=toCTypeDeclaration(collection.valueType), | 
|  | valueWriterCall=valueWriterCall) | 
|  |  | 
|  | else: | 
|  | return CPP_WRITE_LIST_DEFINITION.substitute(suffix=suffix, declaration=toCTypeDeclaration(collection), | 
|  | valueWriterCall=valueWriterCall, | 
|  | valueType=toCTypeDeclaration(collection.valueType)) | 
|  |  | 
|  |  | 
|  | CPP_READ_STRUCT_DEFINITION = Template(""" | 
|  | uint32_t read_${suffix}("""+CPP_PROTOCOLP+""" iprot, """+CPP_TRANSPORTP+""" itrans, ${declaration}& value) { | 
|  |  | 
|  | std::string name; | 
|  | """+CPP_PROTOCOL_TTYPE+""" type; | 
|  | int16_t id; | 
|  | uint32_t xfer = 0; | 
|  |  | 
|  | xfer+= iprot->readStructBegin(itrans, name); | 
|  |  | 
|  | while(true) { | 
|  |  | 
|  | xfer+= iprot->readFieldBegin(itrans, name, type, id); | 
|  |  | 
|  | if(type == """+CPP_PROTOCOL_TSTOP+""") {break;} | 
|  |  | 
|  | switch(id) { | 
|  | ${fieldSwitch} | 
|  | default: xfer += iprot->skip(itrans, type); break; | 
|  | } | 
|  |  | 
|  | xfer+= iprot->readFieldEnd(itrans); | 
|  | } | 
|  |  | 
|  | xfer+= iprot->readStructEnd(itrans); | 
|  |  | 
|  | return xfer; | 
|  | } | 
|  | """) | 
|  |  | 
|  | CPP_WRITE_FIELD_DEFINITION  = Template("""oprot->writeFieldBegin(otrans, \"${name}\", ${type}, ${id}); ${fieldWriterCall}; oprot->writeFieldEnd(otrans)""") | 
|  |  | 
|  | CPP_WRITE_STRUCT_DEFINITION = Template(""" | 
|  | uint32_t write_${suffix}("""+CPP_PROTOCOLP+""" oprot, """+CPP_TRANSPORTP+""" otrans, const ${declaration}& value) { | 
|  |  | 
|  | uint32_t xfer = 0; | 
|  |  | 
|  | xfer+= oprot->writeStructBegin(otrans, \"${name}\"); | 
|  | ${fieldWriterCalls} | 
|  | xfer+= oprot->writeFieldStop(otrans); | 
|  | xfer += oprot->writeStructEnd(otrans); | 
|  | return xfer; | 
|  | } | 
|  | """) | 
|  |  | 
|  | def toStructReaderDefinition(struct): | 
|  | """Converts struct type to reader function definition""" | 
|  |  | 
|  | suffix = typeToIOMethodSuffix(struct) | 
|  |  | 
|  | # Sort field list in order of increasing ids | 
|  |  | 
|  | fieldList = [] | 
|  | fieldList+= struct.fieldList | 
|  |  | 
|  | fieldList.sort(lambda a,b: a.id - b.id) | 
|  |  | 
|  | fieldSwitch="" | 
|  |  | 
|  | for field in fieldList: | 
|  | if toCanonicalType(field.type) == VOID_TYPE: | 
|  | continue; | 
|  | fieldSwitch+= "            case "+str(field.id)+": " | 
|  | fieldSwitch+= toReaderCall("value."+field.name, field.type)+"; value.__isset."+field.name+" = true; break;\n" | 
|  |  | 
|  | return CPP_READ_STRUCT_DEFINITION.substitute(suffix=suffix, declaration=toCTypeDeclaration(struct), fieldSwitch=fieldSwitch) | 
|  |  | 
|  |  | 
|  | def toStructWriterDefinition(struct): | 
|  | """Converts struct type to writer function definition""" | 
|  |  | 
|  | suffix = typeToIOMethodSuffix(struct) | 
|  |  | 
|  | fieldWriterCalls = [] | 
|  |  | 
|  | fieldWriterCalls = [CPP_WRITE_FIELD_DEFINITION.substitute(name=field.name, | 
|  | type=toWireType(toCanonicalType(field.type)), | 
|  | id=field.id, | 
|  | fieldWriterCall=toWriterCall("value."+field.name, field.type))+";" | 
|  | for field in struct.fieldList if toCanonicalType(field.type) != VOID_TYPE | 
|  | ] | 
|  |  | 
|  | fieldWriterCalls = "    "+string.join(fieldWriterCalls, "\n    ") | 
|  |  | 
|  | return CPP_WRITE_STRUCT_DEFINITION.substitute(name=struct.name, suffix=suffix, declaration=toCTypeDeclaration(struct), fieldWriterCalls=fieldWriterCalls) | 
|  |  | 
|  | CPP_WRITE_RESULT_STRUCT_DEFINITION = Template(""" | 
|  | uint32_t write_${suffix}("""+CPP_PROTOCOLP+""" oprot, """+CPP_TRANSPORTP+""" otrans, const ${declaration}& value) { | 
|  |  | 
|  | uint32_t xfer = 0; | 
|  |  | 
|  | xfer+= oprot->writeStructBegin(otrans, \"${name}\"); | 
|  | if(${value}.__isset.x) | 
|  | ${fieldWriterCalls} | 
|  | xfer+= oprot->writeFieldStop(otrans); | 
|  | xfer += oprot->writeStructEnd(otrans); | 
|  | return xfer; | 
|  | } | 
|  | """) | 
|  |  | 
|  | def toResultStructReaderDefinition(struct): | 
|  | """Converts internal results struct to a reader function definition""" | 
|  |  | 
|  | return toStructReaderDefinition(struct) | 
|  |  | 
|  | def toResultStructWriterDefinition(struct): | 
|  | """Converts internal results struct to a reader function definition.  The difference between this function and toStructWriterDefinition is that this only sends one field, either success or an exception field, depending on which field is set""" | 
|  |  | 
|  | suffix = typeToIOMethodSuffix(struct) | 
|  |  | 
|  | fieldWriterCalls = ["if(value.__isset."+field.name+") { "+ | 
|  | CPP_WRITE_FIELD_DEFINITION.substitute(name=field.name, | 
|  | type=toWireType(toCanonicalType(field.type)), | 
|  | id=field.id, | 
|  | fieldWriterCall=toWriterCall("value."+field.name, field.type))+";}" | 
|  | for field in struct.fieldList if toCanonicalType(field.type) != VOID_TYPE] | 
|  |  | 
|  | fieldWriterCalls = "    "+string.join(fieldWriterCalls, "\n    else ") | 
|  |  | 
|  | return CPP_WRITE_STRUCT_DEFINITION.substitute(name=struct.name, suffix=suffix, declaration=toCTypeDeclaration(struct), fieldWriterCalls=fieldWriterCalls) | 
|  |  | 
|  | def toReaderDefinition(ttype): | 
|  | """Converts thrift type to a reader function definition""" | 
|  |  | 
|  | if isinstance(ttype, CollectionType): | 
|  | return toCollectionReaderDefinition(ttype) | 
|  |  | 
|  | elif isinstance(ttype, StructType): | 
|  | return toStructReaderDefinition(ttype) | 
|  |  | 
|  | elif isinstance(ttype, TypedefType): | 
|  | return "" | 
|  |  | 
|  | elif isinstance(ttype, EnumType): | 
|  | return "" | 
|  |  | 
|  | else: | 
|  | raise Exception, "Unsupported type: "+str(ttype) | 
|  |  | 
|  | def toWriterDefinition(ttype): | 
|  | """Converts thrift type to a writer function definition""" | 
|  |  | 
|  | if isinstance(ttype, CollectionType): | 
|  | return toCollectionWriterDefinition(ttype) | 
|  |  | 
|  | elif isinstance(ttype, StructType): | 
|  | return toStructWriterDefinition(ttype) | 
|  |  | 
|  | elif isinstance(ttype, TypedefType): | 
|  | return "" | 
|  |  | 
|  | elif isinstance(ttype, EnumType): | 
|  | return "" | 
|  |  | 
|  | else: | 
|  | raise Exception, "Unsupported type: "+str(ttype) | 
|  |  | 
|  | def toOrderedIOList(ttype, result=None): | 
|  | """Builds a list of types ordered by doing a depth first traverse of all thrift type definitions.  This gives us a list from which we can | 
|  | generate read/write methods without making forward references.""" | 
|  |  | 
|  | if not result: | 
|  | result = [] | 
|  |  | 
|  | if ttype in result: | 
|  | return result | 
|  |  | 
|  | elif isinstance(ttype, PrimitiveType): | 
|  | return result | 
|  |  | 
|  | elif isinstance(ttype, CollectionType): | 
|  |  | 
|  | if isinstance(ttype, MapType): | 
|  | result = toOrderedIOList(ttype.keyType, result) | 
|  |  | 
|  | result = toOrderedIOList(ttype.valueType, result) | 
|  |  | 
|  | result.append(ttype) | 
|  |  | 
|  | elif isinstance(ttype, StructType): | 
|  | for field in ttype.fieldList: | 
|  | result = toOrderedIOList(field.type, result) | 
|  | result.append(ttype) | 
|  |  | 
|  | elif isinstance(ttype, TypedefType): | 
|  | result.append(ttype) | 
|  | return result | 
|  |  | 
|  | elif isinstance(ttype, EnumType): | 
|  | result.append(ttype) | 
|  | return result | 
|  |  | 
|  | elif isinstance(ttype, Program): | 
|  |  | 
|  | for struct in ttype.structMap.values(): | 
|  | result = toOrderedIOList(struct, result) | 
|  |  | 
|  | for service in ttype.serviceMap.values(): | 
|  | result = toOrderedIOList(service, result) | 
|  |  | 
|  | elif isinstance(ttype, Service): | 
|  | for function in ttype.functionList: | 
|  | result = toOrderedIOList(function, result) | 
|  |  | 
|  | elif isinstance(ttype, Function): | 
|  | result = toOrderedIOList(ttype.returnType(), result) | 
|  |  | 
|  | # skip the args struct itself and just order the arguments themselves | 
|  | # we don't want the arg struct to be referred to until later, since we need to | 
|  | # inline those struct definitions with the implementation, not in the types header | 
|  |  | 
|  | for field in ttype.args(): | 
|  | result = toOrderedIOList(field.type, result) | 
|  |  | 
|  | else: | 
|  | raise Exception, "Unsupported thrift type: "+str(ttype) | 
|  |  | 
|  | return result | 
|  |  | 
|  | def toIOMethodImplementations(program): | 
|  | """Generates read and write methods for all non-primitive types in a thrift program as well as for the internal argStruct and resultStruct types for | 
|  | all service functions""" | 
|  |  | 
|  | # get ordered list of all types that need marshallers: | 
|  |  | 
|  | iolist = toOrderedIOList(program) | 
|  |  | 
|  | result = "" | 
|  |  | 
|  | for ttype in iolist: | 
|  | result+= toReaderDefinition(ttype) | 
|  | result+= toWriterDefinition(ttype) | 
|  |  | 
|  | # For all function argument lists, we need to create both struct definitions | 
|  | # and io methods.  We keep the struct definitions local, since they aren't part of the service API | 
|  | # | 
|  | # Note that we don't need to do a depth-first traverse of arg structs since they can only include fields | 
|  | # we've already seen | 
|  |  | 
|  | for service in program.serviceMap.values(): | 
|  | for function in service.functionList: | 
|  | result+= toStructDefinition(function.argsStruct) | 
|  | result+= toReaderDefinition(function.argsStruct) | 
|  | result+= toWriterDefinition(function.argsStruct) | 
|  | result+= toStructDefinition(function.resultStruct) | 
|  | result+= toResultStructReaderDefinition(function.resultStruct) | 
|  | result+= toResultStructWriterDefinition(function.resultStruct) | 
|  |  | 
|  | return result; | 
|  |  | 
|  | def toImplementationSourceName(filename, genDir=None, debugp=None): | 
|  | """Creates a file name for the implementation of client stubs, server skeletons, and non-primitive read/write methods.""" | 
|  |  | 
|  | if not genDir: | 
|  | genDir = toGenDir(filename) | 
|  |  | 
|  | basename = toBasename(filename) | 
|  |  | 
|  | result = os.path.join(genDir, basename+".cc") | 
|  |  | 
|  | if debugp: | 
|  | debugp("toDefinitionHeaderName("+str(filename)+", "+str(genDir)+") => "+str(basename)) | 
|  |  | 
|  | return result | 
|  |  | 
|  | def writeImplementationSource(program, filename, genDir=None, debugp=None): | 
|  | """Writes client stub, server skeleton, and non-primitive type I/O functions for all servciesf defined in program into a C/C++ source file.  Uses the name of the original | 
|  | thrift source, filename, and the optional generated C++ code directory, genDir, to determine the name and location of header file""" | 
|  |  | 
|  | implementationSource = toImplementationSourceName(filename, genDir) | 
|  |  | 
|  | if debugp: | 
|  | debugp("implementationSource: "+str(implementationSource)) | 
|  |  | 
|  | cfile = CFile(implementationSource, "w") | 
|  |  | 
|  | basename = toBasename(filename) | 
|  |  | 
|  | cfile.writeln(CPP_IMPL_HEADER.substitute(source=basename, date=time.ctime(), namespacePrefix=toCNamespacePrefix(program.namespace))) | 
|  |  | 
|  | cfile.write(toIOMethodImplementations(program)) | 
|  |  | 
|  | cfile.write(toServerDefinition(program)) | 
|  |  | 
|  | cfile.write(toClientDefinition(program)) | 
|  |  | 
|  | cfile.writeln(CPP_IMPL_FOOTER.substitute(source=basename, namespaceSuffix=toCNamespaceSuffix(program.namespace))) | 
|  |  | 
|  | cfile.close() | 
|  |  | 
|  | class CPPGenerator(Generator): | 
|  |  | 
|  | def __call__(self, program, filename, genDir=None, debugp=None): | 
|  |  | 
|  | writeDefinitionHeader(program, filename, genDir, debugp) | 
|  |  | 
|  | writeServicesHeader(program, filename, genDir, debugp) | 
|  |  | 
|  | writeImplementationSource(program, filename, genDir, debugp) |