blob: fd25e17c9556203255ef4720c95eb8a7119ba0c7 [file] [log] [blame]
Marc Slemkob2039e72006-08-09 01:00:17 +00001import time
2import os
3import os.path
4from string import Template
5from parser import *
6from generator import *
7
8HEADER_COMMENT = """/**
9 * Autogenerated by Thrift
10 * ${date}
11 *
12 * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
13 */
14 """
15
16CPP_TYPES_HEADER = Template(HEADER_COMMENT+"""
17#if !defined(${source}_types_h_)
18#define ${source}_types_h_ 1
19
Marc Slemkoc4eb9e82006-08-10 03:29:29 +000020#include <Thrift.h>
Marc Slemko17859852006-08-15 00:21:31 +000021${namespacePrefix}
Marc Slemkob2039e72006-08-09 01:00:17 +000022""")
23
24CPP_TYPES_FOOTER = Template("""
Marc Slemko17859852006-08-15 00:21:31 +000025${namespaceSuffix}
Marc Slemkob2039e72006-08-09 01:00:17 +000026#endif // !defined(${source}_types_h_)
27""")
28
29CPP_SERVICES_HEADER = Template(HEADER_COMMENT+"""
30#if !defined(${source}_h_)
31#define ${source}_h_ 1
32
Marc Slemkoc4eb9e82006-08-10 03:29:29 +000033#include <Thrift.h>
34#include <TProcessor.h>
35#include <protocol/TProtocol.h>
36#include <transport/TTransport.h>
Marc Slemkodb14e172006-08-09 23:36:18 +000037#include \"${source}_types.h\"
Marc Slemko17859852006-08-15 00:21:31 +000038
39${namespacePrefix}
Marc Slemkob2039e72006-08-09 01:00:17 +000040""")
41
42CPP_SERVICES_FOOTER = Template("""
Marc Slemko17859852006-08-15 00:21:31 +000043${namespaceSuffix}
Marc Slemkob2039e72006-08-09 01:00:17 +000044#endif // !defined(${source}_h_)""")
45
Marc Slemkodb14e172006-08-09 23:36:18 +000046CPP_IMPL_HEADER = Template(HEADER_COMMENT+"""
47#include \"${source}.h\"
Marc Slemko17859852006-08-15 00:21:31 +000048
49${namespacePrefix}
Marc Slemkodb14e172006-08-09 23:36:18 +000050""")
51
Marc Slemko17859852006-08-15 00:21:31 +000052CPP_IMPL_FOOTER = Template("""
53${namespaceSuffix}
54""")
Marc Slemkodb14e172006-08-09 23:36:18 +000055
Marc Slemkob2039e72006-08-09 01:00:17 +000056def cpp_debug(arg):
57 print(arg)
58
59class Indenter(object):
60 def __init__(self, level=0, step=4):
61 self.level = level
62 self.step = step
63 self.chunk = ""
64 for i in range(step):
65 self.chunk+= " "
66 self.prefix=""
67
68 def inc(self):
69 self.level+= self.step
70 self.prefix += self.chunk
71
72 def dec(self):
73 self.level-= self.step
74 if(self.level < 0):
75 raise Exception, "Illegal indent level"
76 self.prefix = self.prefix[:self.level]
77
78 def __call__(self):
79 return self.prefix
80
81class CFile(file):
82
83 def __init__(self, name, flags):
84 file.__init__(self, name, flags)
85 self.indent = Indenter()
86 self.newline = True
87
88 def rwrite(self, value):
89 file.write(self, value)
90
91 def write(self, value=""):
92 if self.newline:
93 self.rwrite(self.indent())
94 self.newline = False
95 self.rwrite(value)
96
97 def writeln(self, value=""):
98 self.write(value+"\n")
99 self.newline = True
100
101 def beginBlock(self):
102 self.writeln("{")
103 self.indent.inc();
104
105 def endBlock(self, suffix=""):
106 self.indent.dec();
107 self.writeln("}"+suffix)
108
109CPP_PRIMITIVE_MAP = {
110 "void" : "void",
111 "bool" : "bool",
112 "string": "std::string",
113 "utf7": "std::string",
114 "utf8": "std::wstring",
115 "utf16": "std::utf16",
116 "byte" : "uint8_t",
117 "i08": "int8_t",
118 "i16": "int16_t",
119 "i32": "int32_t",
120 "i64": "int64_t",
121 "u08": "uint8_t",
122 "u16": "uint16_t",
123 "u32": "uint32_t",
124 "u64": "uint64_t",
Marc Slemkod8b10512006-08-14 23:30:37 +0000125 "float": "float",
126 "double": "double"
Marc Slemkob2039e72006-08-09 01:00:17 +0000127}
128
129CPP_CONTAINER_MAP = {
Marc Slemko5b126d62006-08-11 23:03:42 +0000130 MapType : "std::map",
131 ListType: "std::list",
132 SetType : "std::set",
Marc Slemkob2039e72006-08-09 01:00:17 +0000133}
134
Marc Slemko17859852006-08-15 00:21:31 +0000135def toCNamespacePrefix(namespace):
136 if not namespace:
137 return ""
138 else:
139 return string.join(["namespace "+token + " {" for token in string.split(namespace, ".")], " ")
140
141def toCNamespaceSuffix(namespace):
142 if not namespace:
143 return ""
144 else:
145 return string.join(["}" for token in string.split(namespace, ".")], "")
146
147def toCTypeDeclaration(ttype):
Marc Slemkod8b10512006-08-14 23:30:37 +0000148 """ Converts the thrift IDL type to the corresponding C/C++ type. Note that if ttype is FieldType, this function c
149converts to type declaration followed by field name, i.e. \"string string_thing\""""
Marc Slemkob2039e72006-08-09 01:00:17 +0000150
151 if isinstance(ttype, PrimitiveType):
152 return CPP_PRIMITIVE_MAP[ttype.name]
153
154 elif isinstance(ttype, CollectionType):
155
156 result = CPP_CONTAINER_MAP[type(ttype)]+"<"
157
Marc Slemko5b126d62006-08-11 23:03:42 +0000158 if isinstance(ttype, MapType):
Marc Slemko17859852006-08-15 00:21:31 +0000159 result+= toCTypeDeclaration(ttype.keyType)+", "+ toCTypeDeclaration(ttype.valueType)
Marc Slemkob2039e72006-08-09 01:00:17 +0000160
Marc Slemko5b126d62006-08-11 23:03:42 +0000161 elif isinstance(ttype, SetType) or isinstance(ttype, ListType):
Marc Slemko17859852006-08-15 00:21:31 +0000162 result+= toCTypeDeclaration(ttype.valueType)
Marc Slemkob2039e72006-08-09 01:00:17 +0000163
164 else:
165 raise Exception, "Unknown Collection Type "+str(ttype)
166
167 result+= "> "
168
169 return result
170
Marc Slemko5b126d62006-08-11 23:03:42 +0000171 elif isinstance(ttype, StructType):
Marc Slemkob2039e72006-08-09 01:00:17 +0000172 return "struct "+ttype.name
173
Marc Slemko5b126d62006-08-11 23:03:42 +0000174 elif isinstance(ttype, TypedefType):
Marc Slemkob2039e72006-08-09 01:00:17 +0000175 return ttype.name;
176
Marc Slemko5b126d62006-08-11 23:03:42 +0000177 elif isinstance(ttype, EnumType):
Marc Slemkob2039e72006-08-09 01:00:17 +0000178 return ttype.name;
179
180 elif isinstance(ttype, Function):
Marc Slemko17859852006-08-15 00:21:31 +0000181 result = toCTypeDeclaration(ttype.returnType())+ " "+ttype.name+"("+string.join([toCTypeDeclaration(arg) for arg in ttype.args()], ", ")+")"
Marc Slemkod8b10512006-08-14 23:30:37 +0000182 if len(ttype.exceptions()):
Marc Slemko17859852006-08-15 00:21:31 +0000183 result+= " throw("+string.join([toCTypeDeclaration(exceptions.type) for exceptions in ttype.exceptions()], ", ")+")"
Marc Slemkod8b10512006-08-14 23:30:37 +0000184 return result
Marc Slemkob2039e72006-08-09 01:00:17 +0000185
186 elif isinstance(ttype, Field):
Marc Slemko17859852006-08-15 00:21:31 +0000187 return toCTypeDeclaration(ttype.type)+ " "+ttype.name
Marc Slemkob2039e72006-08-09 01:00:17 +0000188
189 else:
190 raise Exception, "Unknown type "+str(ttype)
191
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000192def toTypeDefDefinition(typedef):
Marc Slemkod8b10512006-08-14 23:30:37 +0000193 """ Converts a thrift typedef to a C/C++ typedef """
Marc Slemkob2039e72006-08-09 01:00:17 +0000194
Marc Slemko17859852006-08-15 00:21:31 +0000195 return "typedef "+toCTypeDeclaration(typedef.definitionType)+" "+typedef.name+";"
Marc Slemkob2039e72006-08-09 01:00:17 +0000196
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000197def toEnumDefinition(enum):
Marc Slemkod8b10512006-08-14 23:30:37 +0000198 """ Converts a thrift enum to a C/C++ enum """
Marc Slemkob2039e72006-08-09 01:00:17 +0000199
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000200 result = "enum "+enum.name+" {\n"
Marc Slemkob2039e72006-08-09 01:00:17 +0000201
202 first = True
203
204 for ed in enum.enumDefs:
205 if first:
206 first = False
207 else:
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000208 result+= ",\n"
209 result+= " "+ed.name+" = "+str(ed.id)
Marc Slemkob2039e72006-08-09 01:00:17 +0000210
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000211 result+= "\n};\n"
Marc Slemkob2039e72006-08-09 01:00:17 +0000212
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000213 return result
Marc Slemkob2039e72006-08-09 01:00:17 +0000214
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000215def toStructDefinition(struct):
Marc Slemkod8b10512006-08-14 23:30:37 +0000216 """Converts a thrift struct to a C/C++ struct"""
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000217
218 result = "struct "+struct.name+" {\n"
Marc Slemkob2039e72006-08-09 01:00:17 +0000219
Marc Slemkobf4fd192006-08-15 21:29:39 +0000220 # Create constructor defaults for primitive types
Marc Slemko5b126d62006-08-11 23:03:42 +0000221
Marc Slemkobf4fd192006-08-15 21:29:39 +0000222 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]], ", ")
Marc Slemko5b126d62006-08-11 23:03:42 +0000223
Marc Slemkobf4fd192006-08-15 21:29:39 +0000224 if len(ctorValues) > 0:
225 result+= " "+struct.name+"() : "+ctorValues+ " {}\n"
226
227 # Field declarations
228
229 result+= string.join([" "+toCTypeDeclaration(field)+";\n" for field in struct.fieldList if toCanonicalType(field.type) != VOID_TYPE], "")
230
231 # is-field-set struct and ctor
232
233 ctorValues = string.join([field.name+"(false)" for field in struct.fieldList if toCanonicalType(field.type) != VOID_TYPE], ", ")
234
235 if len(ctorValues) > 0:
236 result+= " struct __isset {\n"
237 result+= " __isset() : "+ctorValues+" {}\n"
238 result+= string.join([" bool "+field.name+";\n" for field in struct.fieldList if toCanonicalType(field.type) != VOID_TYPE], "")
239 result+= " } __isset;\n"
240
241 # bring it on home
Marc Slemkob2039e72006-08-09 01:00:17 +0000242
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000243 result+= "};\n"
Marc Slemkob2039e72006-08-09 01:00:17 +0000244
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000245 return result
Marc Slemkob2039e72006-08-09 01:00:17 +0000246
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000247CPP_DEFINITION_MAP = {
Marc Slemko5b126d62006-08-11 23:03:42 +0000248 TypedefType : toTypeDefDefinition,
249 EnumType : toEnumDefinition,
250 StructType : toStructDefinition,
Marc Slemkod8b10512006-08-14 23:30:37 +0000251 ExceptionType : toStructDefinition,
Marc Slemkob2039e72006-08-09 01:00:17 +0000252 Service : None
253 }
254
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000255def toDefinitions(definitions):
Marc Slemkod8b10512006-08-14 23:30:37 +0000256 """Converts an arbitrafy thrift grammatical unit definition to the corresponding C/C++ definition"""
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000257
258 result = ""
259
Marc Slemkob2039e72006-08-09 01:00:17 +0000260 for definition in definitions:
261
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000262 writer = CPP_DEFINITION_MAP[type(definition)]
Marc Slemkob2039e72006-08-09 01:00:17 +0000263
264 if writer:
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000265 result+= writer(definition)+"\n"
Marc Slemkob2039e72006-08-09 01:00:17 +0000266
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000267 return result
Marc Slemkob2039e72006-08-09 01:00:17 +0000268
269CPP_THRIFT_NS = "facebook::thrift"
270
271CPP_INTERFACE_FUNCTION_DECLARATION = Template(""" virtual ${functionDeclaration} = 0;
272""")
273
274CPP_INTERFACE_DECLARATION = Template("""
275class ${service}If {
276 public:
Marc Slemkoe6889de2006-08-12 00:32:53 +0000277 virtual ~${service}If() {}
Marc Slemkob2039e72006-08-09 01:00:17 +0000278${functionDeclarations}};
279""")
280
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000281def toServiceInterfaceDeclaration(service, debugp=None):
Marc Slemkod8b10512006-08-14 23:30:37 +0000282 """Converts a thrift service definition into a C++ abstract base class"""
Marc Slemkob2039e72006-08-09 01:00:17 +0000283
Marc Slemko17859852006-08-15 00:21:31 +0000284 functionDeclarations = string.join([CPP_INTERFACE_FUNCTION_DECLARATION.substitute(service=service.name, functionDeclaration=toCTypeDeclaration(function)) for function in service.functionList], "")
Marc Slemkob2039e72006-08-09 01:00:17 +0000285
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000286 return CPP_INTERFACE_DECLARATION.substitute(service=service.name, functionDeclarations=functionDeclarations)
Marc Slemkob2039e72006-08-09 01:00:17 +0000287
Marc Slemko5b126d62006-08-11 23:03:42 +0000288CPP_EXCEPTION = CPP_THRIFT_NS+"::Exception"
289
Marc Slemkob2039e72006-08-09 01:00:17 +0000290CPP_SP = Template("boost::shared_ptr<${klass}> ")
291
292CPP_PROCESSOR = CPP_THRIFT_NS+"::TProcessor"
293CPP_PROCESSORP = CPP_SP.substitute(klass=CPP_PROCESSOR)
294
295CPP_PROTOCOL_NS = CPP_THRIFT_NS+"::protocol"
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000296CPP_PROTOCOL = CPP_PROTOCOL_NS+"::TProtocol"
297CPP_PROTOCOLP = CPP_SP.substitute(klass="const "+CPP_PROTOCOL)
Marc Slemkob2039e72006-08-09 01:00:17 +0000298
299
300CPP_TRANSPORT_NS = CPP_THRIFT_NS+"::transport"
301CPP_TRANSPORT = CPP_TRANSPORT_NS+"::TTransport"
302CPP_TRANSPORTP = CPP_SP.substitute(klass=CPP_TRANSPORT)
303
Marc Slemkob2039e72006-08-09 01:00:17 +0000304CPP_PROTOCOL_TSTOP = CPP_PROTOCOL_NS+"::T_STOP"
305CPP_PROTOCOL_TTYPE = CPP_PROTOCOL_NS+"::TType"
Marc Slemko5b126d62006-08-11 23:03:42 +0000306CPP_PROTOCOL_MESSAGE_TYPE = CPP_PROTOCOL_NS+"::TMessageType"
307CPP_PROTOCOL_CALL = CPP_PROTOCOL_NS+"::T_CALL"
308CPP_PROTOCOL_REPLY = CPP_PROTOCOL_NS+"::T_REPLY"
Marc Slemkob2039e72006-08-09 01:00:17 +0000309
Marc Slemkodb14e172006-08-09 23:36:18 +0000310CPP_TTYPE_MAP = {
311 STOP_TYPE : CPP_PROTOCOL_NS+"::T_STOP",
312 VOID_TYPE : CPP_PROTOCOL_NS+"::T_VOID",
313 BOOL_TYPE : CPP_PROTOCOL_NS+"::T_BOOL",
314 UTF7_TYPE : CPP_PROTOCOL_NS+"::T_UTF7",
315 UTF7_TYPE : CPP_PROTOCOL_NS+"::T_UTF7",
316 UTF8_TYPE : CPP_PROTOCOL_NS+"::T_UTF8",
317 UTF16_TYPE : CPP_PROTOCOL_NS+"::T_UTF16",
318 U08_TYPE : CPP_PROTOCOL_NS+"::T_U08",
319 I08_TYPE : CPP_PROTOCOL_NS+"::T_I08",
320 I16_TYPE : CPP_PROTOCOL_NS+"::T_I16",
321 I32_TYPE : CPP_PROTOCOL_NS+"::T_I32",
322 I64_TYPE : CPP_PROTOCOL_NS+"::T_I64",
323 U08_TYPE : CPP_PROTOCOL_NS+"::T_U08",
324 U16_TYPE : CPP_PROTOCOL_NS+"::T_U16",
325 U32_TYPE : CPP_PROTOCOL_NS+"::T_U32",
326 U64_TYPE : CPP_PROTOCOL_NS+"::T_U64",
327 FLOAT_TYPE : CPP_PROTOCOL_NS+"::T_FLOAT",
Marc Slemkod8b10512006-08-14 23:30:37 +0000328 DOUBLE_TYPE : CPP_PROTOCOL_NS+"::T_DOUBLE",
Marc Slemko5b126d62006-08-11 23:03:42 +0000329 StructType : CPP_PROTOCOL_NS+"::T_STRUCT",
Marc Slemkod8b10512006-08-14 23:30:37 +0000330 ExceptionType : CPP_PROTOCOL_NS+"::T_STRUCT",
Marc Slemko5b126d62006-08-11 23:03:42 +0000331 ListType : CPP_PROTOCOL_NS+"::T_LIST",
332 MapType : CPP_PROTOCOL_NS+"::T_MAP",
333 SetType : CPP_PROTOCOL_NS+"::T_SET"
Marc Slemkodb14e172006-08-09 23:36:18 +0000334}
335
Marc Slemko91f67482006-08-11 23:58:57 +0000336
337CPP_SERVER_FUNCTION_DECLARATION = Template(""" void process_${function}(uint32_t seqid, """+CPP_TRANSPORTP+""" itrans, """+CPP_TRANSPORTP+""" otrans);
338""")
339
340CPP_SERVER_FUNCTION_DEFINITION = Template("""
341void ${service}ServerIf::process_${function}(uint32_t seqid, """+CPP_TRANSPORTP+""" itrans, """+CPP_TRANSPORTP+""" otrans) {
342
343 uint32_t xfer = 0;
344
345 ${argsStructDeclaration};
346
347 ${argsStructReader};
348
349 _iprot->readMessageEnd(itrans);
350
Marc Slemko91f67482006-08-11 23:58:57 +0000351 ${resultStructDeclaration};
352
Marc Slemkobf4fd192006-08-15 21:29:39 +0000353 ${functionCall}
Marc Slemko91f67482006-08-11 23:58:57 +0000354
355 _oprot->writeMessageBegin(otrans, \"${function}\", """+CPP_PROTOCOL_REPLY+""", seqid);
356
357 ${resultStructWriter};
358
359 _oprot->writeMessageEnd(otrans);
360
361 otrans->flush();
362}
363""")
364
365CPP_SERVER_PROCESS_DEFINITION = Template("""
366bool ${service}ServerIf::process("""+CPP_TRANSPORTP+""" itrans, """+CPP_TRANSPORTP+""" otrans) {
367
Marc Slemko91f67482006-08-11 23:58:57 +0000368 std::string name;
369
370 """+CPP_PROTOCOL_MESSAGE_TYPE+""" messageType;
371
372 uint32_t seqid;
373
374 _iprot->readMessageBegin(itrans, name, messageType, seqid);
375
376 if(messageType == """+CPP_PROTOCOL_CALL+""") {
377${callProcessSwitch}
378 } else {
379 throw """+CPP_EXCEPTION+"""(\"Unexpected message type\");
380 }
Marc Slemkoe6889de2006-08-12 00:32:53 +0000381
382 return true;
Marc Slemko91f67482006-08-11 23:58:57 +0000383}
384""")
385
Marc Slemkodb14e172006-08-09 23:36:18 +0000386def toWireType(ttype):
Marc Slemko17859852006-08-15 00:21:31 +0000387 """Converts a thrift type to the corresponding wire type. This differs from toCTypeDeclaration in that it reduces typedefs
Marc Slemkod8b10512006-08-14 23:30:37 +0000388to their canonical form and converts enums to signedf 32 bit integers"""
Marc Slemkodb14e172006-08-09 23:36:18 +0000389
390 if isinstance(ttype, PrimitiveType):
391 return CPP_TTYPE_MAP[ttype]
392
Marc Slemko5b126d62006-08-11 23:03:42 +0000393 elif isinstance(ttype, EnumType):
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000394 return CPP_TTYPE_MAP[I32_TYPE]
395
Marc Slemko5b126d62006-08-11 23:03:42 +0000396 elif isinstance(ttype, TypedefType):
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000397 return toWireType(toCanonicalType(ttype))
398
Marc Slemko5b126d62006-08-11 23:03:42 +0000399 elif isinstance(ttype, StructType) or isinstance(ttype, CollectionType):
Marc Slemkodb14e172006-08-09 23:36:18 +0000400 return CPP_TTYPE_MAP[type(ttype)]
401
402 else:
403 raise Exception, "No wire type for thrift type: "+str(ttype)
404
Marc Slemkob2039e72006-08-09 01:00:17 +0000405CPP_SERVER_DECLARATION = Template("""
406class ${service}ServerIf : public ${service}If, public """+CPP_PROCESSOR+""" {
407 public:
408 ${service}ServerIf("""+CPP_PROTOCOLP+""" protocol): _iprot(protocol), _oprot(protocol) {}
409 ${service}ServerIf("""+CPP_PROTOCOLP+""" iprot, """+CPP_PROTOCOLP+""" oprot) : _iprot(iprot), _oprot(oprot) {}
410 virtual ~${service}ServerIf() {}
411 bool process("""+CPP_TRANSPORTP+""" _itrans,"""+CPP_TRANSPORTP+""" _otrans);
412 protected:
413 """+CPP_PROTOCOLP+""" _iprot;
414 """+CPP_PROTOCOLP+""" _oprot;
415 private:
416${functionDeclarations}};
417""")
418
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000419def toServerDeclaration(service, debugp=None):
Marc Slemkod8b10512006-08-14 23:30:37 +0000420 """Converts a thrift service definition to the Server skeleton class declaration."""
Marc Slemkob2039e72006-08-09 01:00:17 +0000421
422 functionDeclarations = string.join([CPP_SERVER_FUNCTION_DECLARATION.substitute(function=function.name) for function in service.functionList], "")
423
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000424 return CPP_SERVER_DECLARATION.substitute(service=service.name, functionDeclarations=functionDeclarations)
Marc Slemkob2039e72006-08-09 01:00:17 +0000425
426CPP_CLIENT_FUNCTION_DECLARATION = Template(""" ${functionDeclaration};
427""")
428
Marc Slemko5b126d62006-08-11 23:03:42 +0000429
430CPP_CLIENT_FUNCTION_DEFINITION = Template("""
Marc Slemkod8b10512006-08-14 23:30:37 +0000431${returnDeclaration} ${service}Client::${function}(${argsDeclaration}) ${exceptionDeclaration} {
Marc Slemko5b126d62006-08-11 23:03:42 +0000432
433 uint32_t xfer = 0;
Marc Slemko91f67482006-08-11 23:58:57 +0000434 std::string name;
Marc Slemko5b126d62006-08-11 23:03:42 +0000435 """+CPP_PROTOCOL_MESSAGE_TYPE+""" messageType;
436 uint32_t cseqid = 0;
437 uint32_t rseqid = 0;
438
Marc Slemko91f67482006-08-11 23:58:57 +0000439 _oprot->writeMessageBegin(_otrans, \"${function}\", """+CPP_PROTOCOL_CALL+""", cseqid);
Marc Slemko5b126d62006-08-11 23:03:42 +0000440
441 ${argsStructDeclaration};
442
443${argsToStruct};
444
445 ${argsStructWriter};
446
447 _otrans->flush();
448
Marc Slemko91f67482006-08-11 23:58:57 +0000449 _iprot->readMessageBegin(_itrans, name, messageType, rseqid);
Marc Slemko5b126d62006-08-11 23:03:42 +0000450
451 if(messageType != """+CPP_PROTOCOL_REPLY+""" ||
452 rseqid != cseqid) {
453 throw """+CPP_EXCEPTION+"""(\"unexpected message type or id\");
454 }
455
456 ${resultStructDeclaration};
457
458 ${resultStructReader};
459
460 _iprot->readMessageEnd(_itrans);
461
Marc Slemkobf4fd192006-08-15 21:29:39 +0000462${returnResult}
463 throw """+CPP_EXCEPTION+"""(\"${function} failed: unknown result");
Marc Slemko5b126d62006-08-11 23:03:42 +0000464}
465""")
466
Marc Slemkob2039e72006-08-09 01:00:17 +0000467CPP_CLIENT_DECLARATION = Template("""
468class ${service}Client : public ${service}If {
469
470 public:
471
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000472 ${service}Client("""+CPP_TRANSPORTP+""" transport, """+CPP_PROTOCOLP+""" protocol): _itrans(transport), _otrans(transport), _iprot(protocol), _oprot(protocol) {}
Marc Slemkob2039e72006-08-09 01:00:17 +0000473
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000474 ${service}Client("""+CPP_TRANSPORTP+""" itrans, """+CPP_TRANSPORTP+""" otrans, """+CPP_PROTOCOLP+""" iprot, """+CPP_PROTOCOLP+""" oprot) : _itrans(itrans), _otrans(otrans), _iprot(iprot), _oprot(oprot) {}
Marc Slemkob2039e72006-08-09 01:00:17 +0000475
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000476${functionDeclarations}
477 private:
478 """+CPP_TRANSPORTP+""" _itrans;
479 """+CPP_TRANSPORTP+""" _otrans;
480 """+CPP_PROTOCOLP+""" _iprot;
481 """+CPP_PROTOCOLP+""" _oprot;
482};""")
Marc Slemkob2039e72006-08-09 01:00:17 +0000483
Marc Slemko5b126d62006-08-11 23:03:42 +0000484def toServerFunctionDefinition(servicePrefix, function, debugp=None):
Marc Slemkod8b10512006-08-14 23:30:37 +0000485 """Converts a thrift service method declaration into a server method-call processoror function"""
Marc Slemko5b126d62006-08-11 23:03:42 +0000486 result = ""
487
Marc Slemko17859852006-08-15 00:21:31 +0000488 argsStructDeclaration = toCTypeDeclaration(function.argsStruct)+" __args"
Marc Slemko5b126d62006-08-11 23:03:42 +0000489
490 argsStructReader = toReaderCall("__args", function.argsStruct, "_iprot")
491
Marc Slemko17859852006-08-15 00:21:31 +0000492 resultStructDeclaration = toCTypeDeclaration(function.resultStruct)+" __result"
Marc Slemko5b126d62006-08-11 23:03:42 +0000493
494 resultStructWriter = toWriterCall("__result", function.resultStruct, "_oprot")
495
Marc Slemkobf4fd192006-08-15 21:29:39 +0000496 if toCanonicalType(function.returnType()) != VOID_TYPE:
Marc Slemkod8b10512006-08-14 23:30:37 +0000497 functionCallPrefix= "__result.success = "
Marc Slemkobf4fd192006-08-15 21:29:39 +0000498 functionCallSuffix = "\n __result.__isset.success = true;"
Marc Slemkod8b10512006-08-14 23:30:37 +0000499 else:
500 functionCallPrefix = ""
501 functionCallSuffix = ""
502
503 functionCall= function.name+"("+string.join(["__args."+arg.name for arg in function.args()], ", ")+");"
504
505 exceptions = function.exceptions()
506
507 if len(exceptions) > 0:
Marc Slemkobf4fd192006-08-15 21:29:39 +0000508 functionCallPrefix= "try {\n "+functionCallPrefix
Marc Slemkod8b10512006-08-14 23:30:37 +0000509
Marc Slemkobf4fd192006-08-15 21:29:39 +0000510 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 }"
511 for ix in range(len(exceptions))], "")
Marc Slemkod8b10512006-08-14 23:30:37 +0000512
513 functionCall = functionCallPrefix+functionCall+functionCallSuffix
Marc Slemko5b126d62006-08-11 23:03:42 +0000514
515 result+= CPP_SERVER_FUNCTION_DEFINITION.substitute(service=servicePrefix, function=function.name,
516 argsStructDeclaration=argsStructDeclaration,
517 argsStructReader=argsStructReader,
518 functionCall=functionCall,
Marc Slemko5b126d62006-08-11 23:03:42 +0000519 resultStructDeclaration=resultStructDeclaration,
Marc Slemkod8b10512006-08-14 23:30:37 +0000520 resultStructWriter=resultStructWriter)
Marc Slemko5b126d62006-08-11 23:03:42 +0000521 return result
522
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000523def toServerServiceDefinition(service, debugp=None):
Marc Slemkod8b10512006-08-14 23:30:37 +0000524 """Converts a thrift service definiton to a server skeleton implementation"""
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000525
526 result = ""
527
528 for function in service.functionList:
Marc Slemko5b126d62006-08-11 23:03:42 +0000529
530 result+= toServerFunctionDefinition(service.name, function, debugp)
Marc Slemko66d67d82006-08-11 23:33:08 +0000531
Marc Slemkobf4fd192006-08-15 21:29:39 +0000532 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+\"\\\"\");}"
Marc Slemko66d67d82006-08-11 23:33:08 +0000533
Marc Slemko91f67482006-08-11 23:58:57 +0000534 result+= CPP_SERVER_PROCESS_DEFINITION.substitute(service=service.name, callProcessSwitch=callProcessSwitch)
Marc Slemko66d67d82006-08-11 23:33:08 +0000535
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000536 return result
537
538def toServerDefinition(program, debugp=None):
539
540 return string.join([toServerServiceDefinition(service) for service in program.serviceMap.values()], "\n")
541
542def toClientDeclaration(service, debugp=None):
Marc Slemkob2039e72006-08-09 01:00:17 +0000543
Marc Slemko17859852006-08-15 00:21:31 +0000544 functionDeclarations = string.join([CPP_CLIENT_FUNCTION_DECLARATION.substitute(functionDeclaration=toCTypeDeclaration(function)) for function in service.functionList], "")
Marc Slemkob2039e72006-08-09 01:00:17 +0000545
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000546 return CPP_CLIENT_DECLARATION.substitute(service=service.name, functionDeclarations=functionDeclarations)+"\n"
Marc Slemkob2039e72006-08-09 01:00:17 +0000547
Marc Slemko5b126d62006-08-11 23:03:42 +0000548def toClientFunctionDefinition(servicePrefix, function, debugp=None):
Marc Slemkod8b10512006-08-14 23:30:37 +0000549 """Converts a thrift service method declaration to a client stub implementation"""
Marc Slemko5b126d62006-08-11 23:03:42 +0000550
Marc Slemkobf4fd192006-08-15 21:29:39 +0000551 isVoid = toCanonicalType(function.returnType()) == VOID_TYPE
552
Marc Slemko17859852006-08-15 00:21:31 +0000553 returnDeclaration = toCTypeDeclaration(function.returnType())
Marc Slemko5b126d62006-08-11 23:03:42 +0000554
Marc Slemko17859852006-08-15 00:21:31 +0000555 argsDeclaration = string.join([toCTypeDeclaration(function.args()[ix].type)+" __arg"+str(ix) for ix in range(len(function.args()))], ", ")
Marc Slemko5b126d62006-08-11 23:03:42 +0000556
Marc Slemko17859852006-08-15 00:21:31 +0000557 exceptionDeclaration = string.join([toCTypeDeclaration(exception.type) for exception in function.exceptions()], ", ")
Marc Slemkod8b10512006-08-14 23:30:37 +0000558
559 if len(exceptionDeclaration)> 0:
560 exceptionDeclaration = "throw("+exceptionDeclaration+")"
561
Marc Slemko17859852006-08-15 00:21:31 +0000562 argsStructDeclaration = toCTypeDeclaration(function.argsStruct)+" __args"
Marc Slemko5b126d62006-08-11 23:03:42 +0000563
564 argsStructWriter = toWriterCall("__args", function.argsStruct, "_oprot", "_otrans")
565
566 argsToStruct= string.join([" __args."+function.args()[ix].name+" = __arg"+str(ix) for ix in range(len(function.args()))], ";\n")
567
Marc Slemko17859852006-08-15 00:21:31 +0000568 resultStructDeclaration = toCTypeDeclaration(function.resultStruct)+" __result"
Marc Slemko5b126d62006-08-11 23:03:42 +0000569
570 resultStructReader = toReaderCall("__result", function.resultStruct, "_iprot", "_itrans")
571
Marc Slemkod8b10512006-08-14 23:30:37 +0000572 exceptions = function.exceptions()
573
Marc Slemkobf4fd192006-08-15 21:29:39 +0000574 """ void return and non-void returns require very different arrangments. For void returns, we don't actually expect
575 anything to have been sent from the remote side, therefore we need to check for explicit exception returns first,
576 then, if none were encountered, return. For void we test for success first - since this is the most likey result -
577 and then check for exceptions. In both cases, we need to handle the case where there are no specified exceptions. """
578
Marc Slemkod8b10512006-08-14 23:30:37 +0000579 if len(exceptions) > 0:
Marc Slemkobf4fd192006-08-15 21:29:39 +0000580 errors= ["if(__result.__isset."+exception.name+") {\n throw __result."+exception.name+";\n }" for exception in exceptions]
Marc Slemkod8b10512006-08-14 23:30:37 +0000581 else:
Marc Slemkobf4fd192006-08-15 21:29:39 +0000582 errors = []
583
584 if not isVoid:
585 returnResult = " if(__result.__isset.success) {\n return __result.success;\n}"
586 if len(errors) > 0:
587 returnResult+= " else "+string.join(errors, " else ")
588 else:
589 if len(errors) > 0:
590 returnResult= " "+string.join(errors, " else ")+" else {\n return;\n }\n"
591 else:
592 returnResult=" return;\n"
Marc Slemko5b126d62006-08-11 23:03:42 +0000593
594 return CPP_CLIENT_FUNCTION_DEFINITION.substitute(service=servicePrefix,
595 function=function.name,
596 returnDeclaration=returnDeclaration,
597 argsDeclaration=argsDeclaration,
Marc Slemkod8b10512006-08-14 23:30:37 +0000598 exceptionDeclaration=exceptionDeclaration,
Marc Slemko5b126d62006-08-11 23:03:42 +0000599 argsStructDeclaration=argsStructDeclaration,
600 argsStructWriter=argsStructWriter,
601 argsToStruct=argsToStruct,
602 resultStructDeclaration=resultStructDeclaration,
603 resultStructReader=resultStructReader,
Marc Slemkobf4fd192006-08-15 21:29:39 +0000604 returnResult=returnResult)
Marc Slemko5b126d62006-08-11 23:03:42 +0000605
606def toClientServiceDefinition(service, debugp=None):
Marc Slemkod8b10512006-08-14 23:30:37 +0000607 """Converts a thrift service definition to a client stub implementation"""
Marc Slemko5b126d62006-08-11 23:03:42 +0000608
609 result = ""
610
611 for function in service.functionList:
612
613 result+= toClientFunctionDefinition(service.name, function)
614
615 return result
616
617def toClientDefinition(program, debugp=None):
Marc Slemkod8b10512006-08-14 23:30:37 +0000618 """Converts all services in a thrift program to client stub implementations"""
Marc Slemko5b126d62006-08-11 23:03:42 +0000619
620 return string.join([toClientServiceDefinition(service) for service in program.serviceMap.values()], "\n")
621
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000622def toServiceDeclaration(service, debugp=None):
Marc Slemkod8b10512006-08-14 23:30:37 +0000623 """Converts all services in a thrift program to service interface or abstract base class declarations"""
624
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000625 return toServiceInterfaceDeclaration(service, debugp) + toServerDeclaration(service, debugp) + toClientDeclaration(service, debugp)
Marc Slemkob2039e72006-08-09 01:00:17 +0000626
627def toGenDir(filename, suffix="cpp-gen", debugp=None):
Marc Slemkod8b10512006-08-14 23:30:37 +0000628 """creates a generated-code subdirectory for C++ code based on filename of thrift source file and optional suffix"""
Marc Slemkob2039e72006-08-09 01:00:17 +0000629
630 result = os.path.join(os.path.split(filename)[0], suffix)
631
632 if not os.path.exists(result):
633 os.mkdir(result)
634
635 return result
636
637def toBasename(filename, debugp=None):
638 """ Take the filename minus the path and\".thrift\" extension if present """
639
640 basename = os.path.split(filename)[1]
641
642 tokens = os.path.splitext(basename)
643
644 if tokens[1].lower() == ".thrift":
645 basename = tokens[0]
646
647 if debugp:
648 debugp("toBasename("+str(filename)+") => "+str(basename))
649
650 return basename
651
652def toDefinitionHeaderName(filename, genDir=None, debugp=None):
Marc Slemkod8b10512006-08-14 23:30:37 +0000653 """Creates a file name for the public thrift data types based on filename of thrift source file and optional suffix"""
Marc Slemkob2039e72006-08-09 01:00:17 +0000654
655 if not genDir:
656 genDir = toGenDir(filename)
657
658 basename = toBasename(filename)
659
660 result = os.path.join(genDir, basename+"_types.h")
661
662 if debugp:
663 debugp("toDefinitionHeaderName("+str(filename)+", "+str(genDir)+") => "+str(basename))
664
665 return result
666
667def writeDefinitionHeader(program, filename, genDir=None, debugp=None):
Marc Slemkod8b10512006-08-14 23:30:37 +0000668 """Writes public thrift data types defined in program into a public data types header file. Uses the name of the original
669thrift source, filename, and the optional generated C++ code directory, genDir, to determine the name and location of header file"""
Marc Slemkob2039e72006-08-09 01:00:17 +0000670
671 definitionHeader = toDefinitionHeaderName(filename, genDir)
672
673 if debugp:
674 debugp("definitionHeader: "+str(definitionHeader))
675
676 cfile = CFile(definitionHeader, "w")
677
678 basename = toBasename(filename)
679
Marc Slemko17859852006-08-15 00:21:31 +0000680 cfile.writeln(CPP_TYPES_HEADER.substitute(source=basename, date=time.ctime(), namespacePrefix=toCNamespacePrefix(program.namespace)))
Marc Slemkob2039e72006-08-09 01:00:17 +0000681
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000682 cfile.write(toDefinitions(program.definitions))
Marc Slemkob2039e72006-08-09 01:00:17 +0000683
Marc Slemko17859852006-08-15 00:21:31 +0000684 cfile.writeln(CPP_TYPES_FOOTER.substitute(source=basename, namespaceSuffix=toCNamespaceSuffix(program.namespace)))
Marc Slemkob2039e72006-08-09 01:00:17 +0000685
686 cfile.close()
687
688def toServicesHeaderName(filename, genDir=None, debugp=None):
Marc Slemkod8b10512006-08-14 23:30:37 +0000689 """Creates a file name for the public thrift services based on filename of thrift source file and optional suffix"""
Marc Slemkob2039e72006-08-09 01:00:17 +0000690
691 if not genDir:
692 genDir = toGenDir(filename)
693
694 basename = toBasename(filename)
695
696 result = os.path.join(genDir, basename+".h")
697
698 if debugp:
699 debugp("toDefinitionHeaderName("+str(filename)+", "+str(genDir)+") => "+str(basename))
700
701 return result
702
Marc Slemkob2039e72006-08-09 01:00:17 +0000703def writeServicesHeader(program, filename, genDir=None, debugp=None):
Marc Slemkod8b10512006-08-14 23:30:37 +0000704 """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"""
Marc Slemkob2039e72006-08-09 01:00:17 +0000705
706 servicesHeader = toServicesHeaderName(filename, genDir)
707
708 if debugp:
709 debugp("servicesHeader: "+str(servicesHeader))
710
711 cfile = CFile(servicesHeader, "w")
712
713 basename = toBasename(filename)
714
Marc Slemko17859852006-08-15 00:21:31 +0000715 cfile.writeln(CPP_SERVICES_HEADER.substitute(source=basename, date=time.ctime(), namespacePrefix=toCNamespacePrefix(program.namespace)))
Marc Slemkob2039e72006-08-09 01:00:17 +0000716
717 services = []
718
719 # Build orderered list of service definitions by scanning definitions list for services
720
721 for definition in program.definitions:
722 if isinstance(definition, Service) and definition.name in program.serviceMap:
723 services.append(definition)
724
725 for service in services:
726
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000727 cfile.write(toServiceDeclaration(service))
Marc Slemkob2039e72006-08-09 01:00:17 +0000728
Marc Slemko17859852006-08-15 00:21:31 +0000729 cfile.writeln(CPP_SERVICES_FOOTER.substitute(source=basename, namespaceSuffix=toCNamespaceSuffix(program.namespace)))
Marc Slemkob2039e72006-08-09 01:00:17 +0000730
731 cfile.close()
732
733
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000734CPP_STRUCT_READ = Template("""
735uint32_t read${name}Struct("""+CPP_PROTOCOLP+""" _iprot, """+CPP_TRANSPORTP+""" itrans, ${declaration}& value) {
736
Marc Slemkob2039e72006-08-09 01:00:17 +0000737 std::string name;
738 uint32_t id;
739 uint32_t type;
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000740 uint32_t xfer = 0;
741
Marc Slemkob2039e72006-08-09 01:00:17 +0000742 while(true) {
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000743 xfer+= _iprot->readFieldBegin(_itrans, name, type, id);
Marc Slemkob2039e72006-08-09 01:00:17 +0000744 if(type == """+CPP_PROTOCOL_TSTOP+""") {
745 break;
746 }
747 switch(id) {
748${readFieldListSwitch}
749 }
750 }
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000751
752 xfer+= _iprot->readStructEnd(_itrans);
753
754 return xfer;
Marc Slemkob2039e72006-08-09 01:00:17 +0000755}
756""")
757
758CPP_PRIMITIVE_TYPE_IO_METHOD_SUFFIX_MAP = {
Marc Slemko5b126d62006-08-11 23:03:42 +0000759 "void" :"Void",
Marc Slemkob2039e72006-08-09 01:00:17 +0000760 "bool" : "Bool",
761 "string": "String",
762 "utf7": "String",
763 "utf8": "String",
764 "utf16": "String",
765 "i08": "Byte",
766 "i16": "I16",
767 "i32": "I32",
768 "i64": "I64",
769 "u08": "Byte",
770 "u16": "U16",
771 "u32": "U32",
772 "u64": "U64",
Marc Slemkod8b10512006-08-14 23:30:37 +0000773 "float": "Float",
774 "double": "Double"
Marc Slemkob2039e72006-08-09 01:00:17 +0000775}
776
777CPP_COLLECTION_TYPE_IO_METHOD_SUFFIX_MAP = {
Marc Slemko5b126d62006-08-11 23:03:42 +0000778 MapType : "map",
779 ListType : "list",
780 SetType : "set"
Marc Slemkob2039e72006-08-09 01:00:17 +0000781}
782
783def typeToIOMethodSuffix(ttype):
Marc Slemkod8b10512006-08-14 23:30:37 +0000784 """Converts type to a name suitable as a suffix with TProtocol primitive read and write methods or with a generated read or write
785method for a complex type"""
Marc Slemkob2039e72006-08-09 01:00:17 +0000786
787 if isinstance(ttype, PrimitiveType):
788 return CPP_PRIMITIVE_TYPE_IO_METHOD_SUFFIX_MAP[ttype.name]
789
790 elif isinstance(ttype, CollectionType):
791
792 result = CPP_COLLECTION_TYPE_IO_METHOD_SUFFIX_MAP[type(ttype)]+"_"
793
Marc Slemko5b126d62006-08-11 23:03:42 +0000794 if isinstance(ttype, MapType):
Marc Slemkob2039e72006-08-09 01:00:17 +0000795 result+= "k_"+typeToIOMethodSuffix(ttype.keyType)+"_"
796
797 result += "v_"+typeToIOMethodSuffix(ttype.valueType)
798
799 return result
800
Marc Slemko5b126d62006-08-11 23:03:42 +0000801 elif isinstance(ttype, StructType):
Marc Slemkob2039e72006-08-09 01:00:17 +0000802 return "struct_"+ttype.name
803
Marc Slemko5b126d62006-08-11 23:03:42 +0000804 elif isinstance(ttype, TypedefType):
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000805 return ttype.name
Marc Slemkob2039e72006-08-09 01:00:17 +0000806
Marc Slemko5b126d62006-08-11 23:03:42 +0000807 elif isinstance(ttype, EnumType):
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000808 return ttype.name
Marc Slemkob2039e72006-08-09 01:00:17 +0000809
810 else:
811 raise Exception, "Unknown type "+str(ttype)
812
Marc Slemko5b126d62006-08-11 23:03:42 +0000813def toReaderCall(value, ttype, reader="iprot", transport="itrans"):
Marc Slemkod8b10512006-08-14 23:30:37 +0000814 """Converts type to a name suitable as a suffix with TProtocol primitive read methods or with a generated read
815method for a complex type"""
Marc Slemkob2039e72006-08-09 01:00:17 +0000816
817 suffix = typeToIOMethodSuffix(ttype)
818
819 if isinstance(ttype, PrimitiveType):
Marc Slemko5b126d62006-08-11 23:03:42 +0000820 if ttype != VOID_TYPE:
821 return "xfer += "+reader+"->read"+suffix+"("+transport+", "+value+")"
822 else:
823 return ""
Marc Slemkob2039e72006-08-09 01:00:17 +0000824
825 elif isinstance(ttype, CollectionType):
Marc Slemko5b126d62006-08-11 23:03:42 +0000826 return "xfer+= read_"+suffix+"("+reader+", "+transport+", "+value+")"
Marc Slemkob2039e72006-08-09 01:00:17 +0000827
Marc Slemko5b126d62006-08-11 23:03:42 +0000828 elif isinstance(ttype, StructType):
829 return "xfer+= read_"+suffix+"("+reader+", "+transport+", "+value+")"
Marc Slemkob2039e72006-08-09 01:00:17 +0000830
Marc Slemko5b126d62006-08-11 23:03:42 +0000831 elif isinstance(ttype, TypedefType):
Marc Slemko17859852006-08-15 00:21:31 +0000832 return toReaderCall("reinterpret_cast<"+toCTypeDeclaration(ttype.definitionType)+"&>("+value+")", ttype.definitionType, reader)
Marc Slemkob2039e72006-08-09 01:00:17 +0000833
Marc Slemko5b126d62006-08-11 23:03:42 +0000834 elif isinstance(ttype, EnumType):
Marc Slemko17859852006-08-15 00:21:31 +0000835 return toReaderCall("reinterpret_cast<"+toCTypeDeclaration(I32_TYPE)+"&>("+value+")", I32_TYPE, reader)
Marc Slemkodb14e172006-08-09 23:36:18 +0000836
837 else:
838 raise Exception, "Unknown type "+str(ttype)
839
Marc Slemko5b126d62006-08-11 23:03:42 +0000840def toWriterCall(value, ttype, writer="oprot", transport="otrans"):
Marc Slemkod8b10512006-08-14 23:30:37 +0000841 """Converts type to a name suitable as a suffix with TProtocol primitive write methods or with a generated write
842method for a complex type"""
Marc Slemkodb14e172006-08-09 23:36:18 +0000843
844 suffix = typeToIOMethodSuffix(ttype)
845
846 if isinstance(ttype, PrimitiveType):
Marc Slemko5b126d62006-08-11 23:03:42 +0000847 if ttype != VOID_TYPE:
848 return "xfer+= "+writer+"->write"+suffix+"("+transport+", "+value+")"
849 else:
850 return ""
Marc Slemkodb14e172006-08-09 23:36:18 +0000851
852 elif isinstance(ttype, CollectionType):
Marc Slemko5b126d62006-08-11 23:03:42 +0000853 return "xfer+= write_"+suffix+"("+writer+", "+transport+", "+value+")"
Marc Slemkodb14e172006-08-09 23:36:18 +0000854
Marc Slemko5b126d62006-08-11 23:03:42 +0000855 elif isinstance(ttype, StructType):
856 return "xfer+= write_"+suffix+"("+writer+", "+transport+", "+value+")"
Marc Slemkodb14e172006-08-09 23:36:18 +0000857
Marc Slemko5b126d62006-08-11 23:03:42 +0000858 elif isinstance(ttype, TypedefType):
Marc Slemko17859852006-08-15 00:21:31 +0000859 return toWriterCall("reinterpret_cast<const "+toCTypeDeclaration(ttype.definitionType)+"&>("+value+")", ttype.definitionType, writer)
Marc Slemkodb14e172006-08-09 23:36:18 +0000860
Marc Slemko5b126d62006-08-11 23:03:42 +0000861 elif isinstance(ttype, EnumType):
Marc Slemko17859852006-08-15 00:21:31 +0000862 return toWriterCall("reinterpret_cast<const "+toCTypeDeclaration(I32_TYPE)+"&>("+value+")", I32_TYPE, writer)
Marc Slemkob2039e72006-08-09 01:00:17 +0000863
864 else:
865 raise Exception, "Unknown type "+str(ttype)
866
867CPP_READ_MAP_DEFINITION = Template("""
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000868uint32_t read_${suffix}("""+CPP_PROTOCOLP+""" iprot, """+CPP_TRANSPORTP+""" itrans, ${declaration}& value) {
Marc Slemkob2039e72006-08-09 01:00:17 +0000869
870 uint32_t count;
871 ${keyType} key;
872 ${valueType} elem;
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000873 uint32_t xfer = 0;
Marc Slemkob2039e72006-08-09 01:00:17 +0000874
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000875 xfer += iprot->readU32(itrans, count);
Marc Slemkob2039e72006-08-09 01:00:17 +0000876
Marc Slemkoe6889de2006-08-12 00:32:53 +0000877 for(uint32_t ix = 0; ix < count; ix++) {
Marc Slemkodb14e172006-08-09 23:36:18 +0000878 ${keyReaderCall};
879 ${valueReaderCall};
Marc Slemkob2039e72006-08-09 01:00:17 +0000880 value.insert(std::make_pair(key, elem));
881 }
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000882
883 return xfer;
Marc Slemkob2039e72006-08-09 01:00:17 +0000884}
885""")
886
887CPP_WRITE_MAP_DEFINITION = Template("""
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000888uint32_t write_${suffix}("""+CPP_PROTOCOLP+""" oprot, """+CPP_TRANSPORTP+""" otrans, const ${declaration}& value) {
Marc Slemkob2039e72006-08-09 01:00:17 +0000889
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000890 uint32_t xfer = 0;
Marc Slemkob2039e72006-08-09 01:00:17 +0000891
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000892 xfer += oprot->writeU32(otrans, value.size());
Marc Slemkob2039e72006-08-09 01:00:17 +0000893
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000894 for(${declaration}::const_iterator ix = value.begin(); ix != value.end(); ++ix) {
Marc Slemkodb14e172006-08-09 23:36:18 +0000895 ${keyWriterCall};
896 ${valueWriterCall};
Marc Slemkob2039e72006-08-09 01:00:17 +0000897 }
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000898 return xfer;
Marc Slemkob2039e72006-08-09 01:00:17 +0000899}
900""")
901
Marc Slemkob2039e72006-08-09 01:00:17 +0000902CPP_READ_LIST_DEFINITION = Template("""
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000903uint32_t read_${suffix}("""+CPP_PROTOCOLP+""" iprot, """+CPP_TRANSPORTP+""" itrans, ${declaration}& value) {
Marc Slemkob2039e72006-08-09 01:00:17 +0000904
905 uint32_t count;
906 ${valueType} elem;
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000907 uint32_t xfer = 0;
Marc Slemkob2039e72006-08-09 01:00:17 +0000908
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000909 xfer+= iprot->readU32(itrans, count);
Marc Slemkob2039e72006-08-09 01:00:17 +0000910
Marc Slemkoe6889de2006-08-12 00:32:53 +0000911 for(uint32_t ix = 0; ix < count; ix++) {
Marc Slemkodb14e172006-08-09 23:36:18 +0000912 ${valueReaderCall};
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000913 value.${insert}(elem);
Marc Slemkob2039e72006-08-09 01:00:17 +0000914 }
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000915 return xfer;
Marc Slemkob2039e72006-08-09 01:00:17 +0000916}
917""")
918
Marc Slemkodb14e172006-08-09 23:36:18 +0000919CPP_WRITE_LIST_DEFINITION = Template("""
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000920uint32_t write_${suffix}("""+CPP_PROTOCOLP+""" oprot, """+CPP_TRANSPORTP+""" otrans, const ${declaration}& value) {
Marc Slemkodb14e172006-08-09 23:36:18 +0000921
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000922 uint32_t xfer = 0;
Marc Slemkodb14e172006-08-09 23:36:18 +0000923
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000924 xfer+= oprot->writeU32(otrans, value.size());
Marc Slemkodb14e172006-08-09 23:36:18 +0000925
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000926 for(${declaration}::const_iterator ix = value.begin(); ix != value.end(); ++ix) {
Marc Slemkodb14e172006-08-09 23:36:18 +0000927 ${valueWriterCall};
928 }
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000929 return xfer;
Marc Slemkodb14e172006-08-09 23:36:18 +0000930}
931""")
932
Marc Slemkod8b10512006-08-14 23:30:37 +0000933def toCollectionReaderDefinition(collection):
934 """Converts collection type to reader function definition"""
Marc Slemkob2039e72006-08-09 01:00:17 +0000935
Marc Slemkod8b10512006-08-14 23:30:37 +0000936 suffix = typeToIOMethodSuffix(collection)
Marc Slemkob2039e72006-08-09 01:00:17 +0000937
Marc Slemkod8b10512006-08-14 23:30:37 +0000938 if isinstance(collection, MapType):
939 keyReaderCall = toReaderCall("key", collection.keyType)
Marc Slemkob2039e72006-08-09 01:00:17 +0000940
Marc Slemkod8b10512006-08-14 23:30:37 +0000941 valueReaderCall= toReaderCall("elem", collection.valueType)
Marc Slemkob2039e72006-08-09 01:00:17 +0000942
Marc Slemkod8b10512006-08-14 23:30:37 +0000943 if isinstance(collection, MapType):
Marc Slemko17859852006-08-15 00:21:31 +0000944 return CPP_READ_MAP_DEFINITION.substitute(suffix=suffix, declaration=toCTypeDeclaration(collection),
945 keyType=toCTypeDeclaration(collection.keyType),
Marc Slemkodb14e172006-08-09 23:36:18 +0000946 keyReaderCall=keyReaderCall,
Marc Slemko17859852006-08-15 00:21:31 +0000947 valueType=toCTypeDeclaration(collection.valueType),
Marc Slemkodb14e172006-08-09 23:36:18 +0000948 valueReaderCall=valueReaderCall)
Marc Slemkob2039e72006-08-09 01:00:17 +0000949
950 else:
Marc Slemkod8b10512006-08-14 23:30:37 +0000951 if isinstance(collection, ListType):
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000952 insert="push_back"
953 else:
954 insert="insert"
955
Marc Slemko17859852006-08-15 00:21:31 +0000956 return CPP_READ_LIST_DEFINITION.substitute(suffix=suffix, declaration=toCTypeDeclaration(collection),
Marc Slemkodb14e172006-08-09 23:36:18 +0000957 valueReaderCall=valueReaderCall,
Marc Slemko17859852006-08-15 00:21:31 +0000958 valueType=toCTypeDeclaration(collection.valueType),
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000959 insert=insert)
Marc Slemkodb14e172006-08-09 23:36:18 +0000960
961
Marc Slemkod8b10512006-08-14 23:30:37 +0000962def toCollectionWriterDefinition(collection):
963 """Converts collection type to writer function definition"""
Marc Slemkodb14e172006-08-09 23:36:18 +0000964
Marc Slemkod8b10512006-08-14 23:30:37 +0000965 suffix = typeToIOMethodSuffix(collection)
Marc Slemkodb14e172006-08-09 23:36:18 +0000966
Marc Slemkod8b10512006-08-14 23:30:37 +0000967 if isinstance(collection, MapType):
968 keyWriterCall = toWriterCall("ix->first", collection.keyType)
969 valueWriterCall = toWriterCall("ix->second", collection.valueType)
Marc Slemkodb14e172006-08-09 23:36:18 +0000970
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000971 else:
Marc Slemkod8b10512006-08-14 23:30:37 +0000972 valueWriterCall= toWriterCall("*ix", collection.valueType)
Marc Slemkodb14e172006-08-09 23:36:18 +0000973
Marc Slemkod8b10512006-08-14 23:30:37 +0000974 if isinstance(collection, MapType):
Marc Slemko17859852006-08-15 00:21:31 +0000975 return CPP_WRITE_MAP_DEFINITION.substitute(suffix=suffix, declaration=toCTypeDeclaration(collection),
976 keyType=toCTypeDeclaration(collection.keyType),
Marc Slemkodb14e172006-08-09 23:36:18 +0000977 keyWriterCall=keyWriterCall,
Marc Slemko17859852006-08-15 00:21:31 +0000978 valueType=toCTypeDeclaration(collection.valueType),
Marc Slemkodb14e172006-08-09 23:36:18 +0000979 valueWriterCall=valueWriterCall)
980
981 else:
Marc Slemko17859852006-08-15 00:21:31 +0000982 return CPP_WRITE_LIST_DEFINITION.substitute(suffix=suffix, declaration=toCTypeDeclaration(collection),
Marc Slemkodb14e172006-08-09 23:36:18 +0000983 valueWriterCall=valueWriterCall,
Marc Slemko17859852006-08-15 00:21:31 +0000984 valueType=toCTypeDeclaration(collection.valueType))
Marc Slemkob2039e72006-08-09 01:00:17 +0000985
986
987CPP_READ_STRUCT_DEFINITION = Template("""
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000988uint32_t read_${suffix}("""+CPP_PROTOCOLP+""" iprot, """+CPP_TRANSPORTP+""" itrans, ${declaration}& value) {
Marc Slemkob2039e72006-08-09 01:00:17 +0000989
990 std::string name;
991 """+CPP_PROTOCOL_TTYPE+""" type;
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000992 int16_t id;
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000993 uint32_t xfer = 0;
Marc Slemkob2039e72006-08-09 01:00:17 +0000994
Marc Slemko5b126d62006-08-11 23:03:42 +0000995 xfer+= iprot->readStructBegin(itrans, name);
996
Marc Slemkob2039e72006-08-09 01:00:17 +0000997 while(true) {
998
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000999 xfer+= iprot->readFieldBegin(itrans, name, type, id);
Marc Slemkob2039e72006-08-09 01:00:17 +00001000
1001 if(type == """+CPP_PROTOCOL_TSTOP+""") {break;}
1002
1003 switch(id) {
1004${fieldSwitch}
Marc Slemko5b126d62006-08-11 23:03:42 +00001005 default: xfer += iprot->skip(itrans, type); break;
1006 }
Marc Slemkob2039e72006-08-09 01:00:17 +00001007
Marc Slemkoc4eb9e82006-08-10 03:29:29 +00001008 xfer+= iprot->readFieldEnd(itrans);
Marc Slemkob2039e72006-08-09 01:00:17 +00001009 }
Marc Slemko5b126d62006-08-11 23:03:42 +00001010
1011 xfer+= iprot->readStructEnd(itrans);
1012
Marc Slemkoc4eb9e82006-08-10 03:29:29 +00001013 return xfer;
Marc Slemkob2039e72006-08-09 01:00:17 +00001014}
1015""")
1016
Marc Slemkod8b10512006-08-14 23:30:37 +00001017CPP_WRITE_FIELD_DEFINITION = Template("""oprot->writeFieldBegin(otrans, \"${name}\", ${type}, ${id}); ${fieldWriterCall}; oprot->writeFieldEnd(otrans)""")
1018
Marc Slemkodb14e172006-08-09 23:36:18 +00001019CPP_WRITE_STRUCT_DEFINITION = Template("""
Marc Slemkoc4eb9e82006-08-10 03:29:29 +00001020uint32_t write_${suffix}("""+CPP_PROTOCOLP+""" oprot, """+CPP_TRANSPORTP+""" otrans, const ${declaration}& value) {
Marc Slemkodb14e172006-08-09 23:36:18 +00001021
Marc Slemkoc4eb9e82006-08-10 03:29:29 +00001022 uint32_t xfer = 0;
1023
1024 xfer+= oprot->writeStructBegin(otrans, \"${name}\");
Marc Slemkodb14e172006-08-09 23:36:18 +00001025${fieldWriterCalls}
Marc Slemkoc4eb9e82006-08-10 03:29:29 +00001026 xfer+= oprot->writeFieldStop(otrans);
1027 xfer += oprot->writeStructEnd(otrans);
1028 return xfer;
Marc Slemkodb14e172006-08-09 23:36:18 +00001029}
1030""")
1031
Marc Slemkod8b10512006-08-14 23:30:37 +00001032def toStructReaderDefinition(struct):
1033 """Converts struct type to reader function definition"""
Marc Slemkob2039e72006-08-09 01:00:17 +00001034
Marc Slemkod8b10512006-08-14 23:30:37 +00001035 suffix = typeToIOMethodSuffix(struct)
Marc Slemkob2039e72006-08-09 01:00:17 +00001036
1037 # Sort field list in order of increasing ids
1038
1039 fieldList = []
Marc Slemkod8b10512006-08-14 23:30:37 +00001040 fieldList+= struct.fieldList
Marc Slemkob2039e72006-08-09 01:00:17 +00001041
1042 fieldList.sort(lambda a,b: a.id - b.id)
1043
1044 fieldSwitch=""
1045
1046 for field in fieldList:
Marc Slemkobf4fd192006-08-15 21:29:39 +00001047 if toCanonicalType(field.type) == VOID_TYPE:
1048 continue;
Marc Slemkob2039e72006-08-09 01:00:17 +00001049 fieldSwitch+= " case "+str(field.id)+": "
Marc Slemko5b126d62006-08-11 23:03:42 +00001050 fieldSwitch+= toReaderCall("value."+field.name, field.type)+"; value.__isset."+field.name+" = true; break;\n"
Marc Slemkob2039e72006-08-09 01:00:17 +00001051
Marc Slemko17859852006-08-15 00:21:31 +00001052 return CPP_READ_STRUCT_DEFINITION.substitute(suffix=suffix, declaration=toCTypeDeclaration(struct), fieldSwitch=fieldSwitch)
Marc Slemkodb14e172006-08-09 23:36:18 +00001053
Marc Slemkodb14e172006-08-09 23:36:18 +00001054
Marc Slemkod8b10512006-08-14 23:30:37 +00001055def toStructWriterDefinition(struct):
1056 """Converts struct type to writer function definition"""
Marc Slemkodb14e172006-08-09 23:36:18 +00001057
Marc Slemkod8b10512006-08-14 23:30:37 +00001058 suffix = typeToIOMethodSuffix(struct)
Marc Slemkodb14e172006-08-09 23:36:18 +00001059
Marc Slemkod8b10512006-08-14 23:30:37 +00001060 fieldWriterCalls = []
Marc Slemkodb14e172006-08-09 23:36:18 +00001061
Marc Slemkod8b10512006-08-14 23:30:37 +00001062 fieldWriterCalls = [CPP_WRITE_FIELD_DEFINITION.substitute(name=field.name,
1063 type=toWireType(toCanonicalType(field.type)),
1064 id=field.id,
1065 fieldWriterCall=toWriterCall("value."+field.name, field.type))+";"
Marc Slemkobf4fd192006-08-15 21:29:39 +00001066 for field in struct.fieldList if toCanonicalType(field.type) != VOID_TYPE
1067 ]
Marc Slemkod8b10512006-08-14 23:30:37 +00001068
1069 fieldWriterCalls = " "+string.join(fieldWriterCalls, "\n ")
1070
Marc Slemko17859852006-08-15 00:21:31 +00001071 return CPP_WRITE_STRUCT_DEFINITION.substitute(name=struct.name, suffix=suffix, declaration=toCTypeDeclaration(struct), fieldWriterCalls=fieldWriterCalls)
Marc Slemkob2039e72006-08-09 01:00:17 +00001072
Marc Slemkod8b10512006-08-14 23:30:37 +00001073CPP_WRITE_RESULT_STRUCT_DEFINITION = Template("""
1074uint32_t write_${suffix}("""+CPP_PROTOCOLP+""" oprot, """+CPP_TRANSPORTP+""" otrans, const ${declaration}& value) {
1075
1076 uint32_t xfer = 0;
1077
1078 xfer+= oprot->writeStructBegin(otrans, \"${name}\");
1079 if(${value}.__isset.x)
1080${fieldWriterCalls}
1081 xfer+= oprot->writeFieldStop(otrans);
1082 xfer += oprot->writeStructEnd(otrans);
1083 return xfer;
1084}
1085""")
1086
1087def toResultStructReaderDefinition(struct):
1088 """Converts internal results struct to a reader function definition"""
Marc Slemkobf4fd192006-08-15 21:29:39 +00001089
Marc Slemkod8b10512006-08-14 23:30:37 +00001090 return toStructReaderDefinition(struct)
1091
1092def toResultStructWriterDefinition(struct):
1093 """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"""
1094
1095 suffix = typeToIOMethodSuffix(struct)
1096
Marc Slemkobf4fd192006-08-15 21:29:39 +00001097 fieldWriterCalls = ["if(value.__isset."+field.name+") { "+
1098 CPP_WRITE_FIELD_DEFINITION.substitute(name=field.name,
1099 type=toWireType(toCanonicalType(field.type)),
1100 id=field.id,
1101 fieldWriterCall=toWriterCall("value."+field.name, field.type))+";}"
1102 for field in struct.fieldList if toCanonicalType(field.type) != VOID_TYPE]
Marc Slemkod8b10512006-08-14 23:30:37 +00001103
1104 fieldWriterCalls = " "+string.join(fieldWriterCalls, "\n else ")
1105
Marc Slemko17859852006-08-15 00:21:31 +00001106 return CPP_WRITE_STRUCT_DEFINITION.substitute(name=struct.name, suffix=suffix, declaration=toCTypeDeclaration(struct), fieldWriterCalls=fieldWriterCalls)
Marc Slemkod8b10512006-08-14 23:30:37 +00001107
Marc Slemkodb14e172006-08-09 23:36:18 +00001108def toReaderDefinition(ttype):
Marc Slemkod8b10512006-08-14 23:30:37 +00001109 """Converts thrift type to a reader function definition"""
1110
Marc Slemkob2039e72006-08-09 01:00:17 +00001111 if isinstance(ttype, CollectionType):
Marc Slemkodb14e172006-08-09 23:36:18 +00001112 return toCollectionReaderDefinition(ttype)
Marc Slemkob2039e72006-08-09 01:00:17 +00001113
Marc Slemko5b126d62006-08-11 23:03:42 +00001114 elif isinstance(ttype, StructType):
Marc Slemkodb14e172006-08-09 23:36:18 +00001115 return toStructReaderDefinition(ttype)
1116
Marc Slemko5b126d62006-08-11 23:03:42 +00001117 elif isinstance(ttype, TypedefType):
Marc Slemkoc4eb9e82006-08-10 03:29:29 +00001118 return ""
1119
Marc Slemko5b126d62006-08-11 23:03:42 +00001120 elif isinstance(ttype, EnumType):
Marc Slemkoc4eb9e82006-08-10 03:29:29 +00001121 return ""
1122
1123 else:
1124 raise Exception, "Unsupported type: "+str(ttype)
1125
Marc Slemkodb14e172006-08-09 23:36:18 +00001126def toWriterDefinition(ttype):
Marc Slemkod8b10512006-08-14 23:30:37 +00001127 """Converts thrift type to a writer function definition"""
1128
Marc Slemkodb14e172006-08-09 23:36:18 +00001129 if isinstance(ttype, CollectionType):
1130 return toCollectionWriterDefinition(ttype)
1131
Marc Slemko5b126d62006-08-11 23:03:42 +00001132 elif isinstance(ttype, StructType):
Marc Slemkodb14e172006-08-09 23:36:18 +00001133 return toStructWriterDefinition(ttype)
1134
Marc Slemko5b126d62006-08-11 23:03:42 +00001135 elif isinstance(ttype, TypedefType):
Marc Slemkoc4eb9e82006-08-10 03:29:29 +00001136 return ""
1137
Marc Slemko5b126d62006-08-11 23:03:42 +00001138 elif isinstance(ttype, EnumType):
Marc Slemkoc4eb9e82006-08-10 03:29:29 +00001139 return ""
1140
1141 else:
1142 raise Exception, "Unsupported type: "+str(ttype)
1143
Marc Slemkodb14e172006-08-09 23:36:18 +00001144def toOrderedIOList(ttype, result=None):
Marc Slemkod8b10512006-08-14 23:30:37 +00001145 """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
1146generate read/write methods without making forward references."""
1147
Marc Slemkodb14e172006-08-09 23:36:18 +00001148 if not result:
1149 result = []
1150
1151 if ttype in result:
1152 return result
1153
1154 elif isinstance(ttype, PrimitiveType):
1155 return result
1156
1157 elif isinstance(ttype, CollectionType):
1158
Marc Slemko5b126d62006-08-11 23:03:42 +00001159 if isinstance(ttype, MapType):
Marc Slemkodb14e172006-08-09 23:36:18 +00001160 result = toOrderedIOList(ttype.keyType, result)
1161
1162 result = toOrderedIOList(ttype.valueType, result)
1163
1164 result.append(ttype)
1165
Marc Slemko5b126d62006-08-11 23:03:42 +00001166 elif isinstance(ttype, StructType):
Marc Slemkodb14e172006-08-09 23:36:18 +00001167 for field in ttype.fieldList:
1168 result = toOrderedIOList(field.type, result)
1169 result.append(ttype)
1170
Marc Slemko5b126d62006-08-11 23:03:42 +00001171 elif isinstance(ttype, TypedefType):
Marc Slemkoc4eb9e82006-08-10 03:29:29 +00001172 result.append(ttype)
Marc Slemkodb14e172006-08-09 23:36:18 +00001173 return result
1174
Marc Slemko5b126d62006-08-11 23:03:42 +00001175 elif isinstance(ttype, EnumType):
Marc Slemkoc4eb9e82006-08-10 03:29:29 +00001176 result.append(ttype)
Marc Slemkodb14e172006-08-09 23:36:18 +00001177 return result
1178
1179 elif isinstance(ttype, Program):
1180
1181 for struct in ttype.structMap.values():
1182 result = toOrderedIOList(struct, result)
1183
1184 for service in ttype.serviceMap.values():
1185 result = toOrderedIOList(service, result)
1186
1187 elif isinstance(ttype, Service):
1188 for function in ttype.functionList:
1189 result = toOrderedIOList(function, result)
1190
1191 elif isinstance(ttype, Function):
Marc Slemko5b126d62006-08-11 23:03:42 +00001192 result = toOrderedIOList(ttype.returnType(), result)
Marc Slemkodb14e172006-08-09 23:36:18 +00001193
Marc Slemko0b4ffa92006-08-11 02:49:29 +00001194 # skip the args struct itself and just order the arguments themselves
Marc Slemko5b126d62006-08-11 23:03:42 +00001195 # we don't want the arg struct to be referred to until later, since we need to
Marc Slemko0b4ffa92006-08-11 02:49:29 +00001196 # inline those struct definitions with the implementation, not in the types header
1197
Marc Slemko5b126d62006-08-11 23:03:42 +00001198 for field in ttype.args():
Marc Slemko0b4ffa92006-08-11 02:49:29 +00001199 result = toOrderedIOList(field.type, result)
Marc Slemkodb14e172006-08-09 23:36:18 +00001200
1201 else:
1202 raise Exception, "Unsupported thrift type: "+str(ttype)
1203
1204 return result
1205
1206def toIOMethodImplementations(program):
Marc Slemkod8b10512006-08-14 23:30:37 +00001207 """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
1208all service functions"""
Marc Slemkodb14e172006-08-09 23:36:18 +00001209
Marc Slemko0b4ffa92006-08-11 02:49:29 +00001210 # get ordered list of all types that need marshallers:
Marc Slemkodb14e172006-08-09 23:36:18 +00001211
1212 iolist = toOrderedIOList(program)
1213
1214 result = ""
1215
1216 for ttype in iolist:
Marc Slemkodb14e172006-08-09 23:36:18 +00001217 result+= toReaderDefinition(ttype)
1218 result+= toWriterDefinition(ttype)
1219
Marc Slemko5b126d62006-08-11 23:03:42 +00001220 # For all function argument lists, we need to create both struct definitions
1221 # and io methods. We keep the struct definitions local, since they aren't part of the service API
1222 #
Marc Slemko0b4ffa92006-08-11 02:49:29 +00001223 # Note that we don't need to do a depth-first traverse of arg structs since they can only include fields
1224 # we've already seen
1225
1226 for service in program.serviceMap.values():
1227 for function in service.functionList:
Marc Slemko0b4ffa92006-08-11 02:49:29 +00001228 result+= toStructDefinition(function.argsStruct)
Marc Slemko5b126d62006-08-11 23:03:42 +00001229 result+= toReaderDefinition(function.argsStruct)
1230 result+= toWriterDefinition(function.argsStruct)
1231 result+= toStructDefinition(function.resultStruct)
Marc Slemkod8b10512006-08-14 23:30:37 +00001232 result+= toResultStructReaderDefinition(function.resultStruct)
1233 result+= toResultStructWriterDefinition(function.resultStruct)
Marc Slemko0b4ffa92006-08-11 02:49:29 +00001234
Marc Slemkodb14e172006-08-09 23:36:18 +00001235 return result;
1236
1237def toImplementationSourceName(filename, genDir=None, debugp=None):
Marc Slemkod8b10512006-08-14 23:30:37 +00001238 """Creates a file name for the implementation of client stubs, server skeletons, and non-primitive read/write methods."""
Marc Slemkodb14e172006-08-09 23:36:18 +00001239
1240 if not genDir:
1241 genDir = toGenDir(filename)
1242
1243 basename = toBasename(filename)
1244
1245 result = os.path.join(genDir, basename+".cc")
1246
1247 if debugp:
1248 debugp("toDefinitionHeaderName("+str(filename)+", "+str(genDir)+") => "+str(basename))
1249
1250 return result
1251
1252def writeImplementationSource(program, filename, genDir=None, debugp=None):
Marc Slemkod8b10512006-08-14 23:30:37 +00001253 """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
1254thrift source, filename, and the optional generated C++ code directory, genDir, to determine the name and location of header file"""
Marc Slemkodb14e172006-08-09 23:36:18 +00001255
1256 implementationSource = toImplementationSourceName(filename, genDir)
1257
1258 if debugp:
1259 debugp("implementationSource: "+str(implementationSource))
1260
1261 cfile = CFile(implementationSource, "w")
1262
1263 basename = toBasename(filename)
1264
Marc Slemko17859852006-08-15 00:21:31 +00001265 cfile.writeln(CPP_IMPL_HEADER.substitute(source=basename, date=time.ctime(), namespacePrefix=toCNamespacePrefix(program.namespace)))
Marc Slemkodb14e172006-08-09 23:36:18 +00001266
1267 cfile.write(toIOMethodImplementations(program))
1268
Marc Slemko0b4ffa92006-08-11 02:49:29 +00001269 cfile.write(toServerDefinition(program))
1270
Marc Slemko5b126d62006-08-11 23:03:42 +00001271 cfile.write(toClientDefinition(program))
1272
Marc Slemko17859852006-08-15 00:21:31 +00001273 cfile.writeln(CPP_IMPL_FOOTER.substitute(source=basename, namespaceSuffix=toCNamespaceSuffix(program.namespace)))
Marc Slemkodb14e172006-08-09 23:36:18 +00001274
1275 cfile.close()
Marc Slemkob2039e72006-08-09 01:00:17 +00001276
1277class CPPGenerator(Generator):
1278
1279 def __call__(self, program, filename, genDir=None, debugp=None):
1280
Marc Slemkodb14e172006-08-09 23:36:18 +00001281 writeDefinitionHeader(program, filename, genDir, debugp)
Marc Slemkob2039e72006-08-09 01:00:17 +00001282
Marc Slemkodb14e172006-08-09 23:36:18 +00001283 writeServicesHeader(program, filename, genDir, debugp)
Marc Slemkob2039e72006-08-09 01:00:17 +00001284
Marc Slemkodb14e172006-08-09 23:36:18 +00001285 writeImplementationSource(program, filename, genDir, debugp)