2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
19 * Contains some contributions under the Thrift Software License.
20 * Please see doc/old-thrift-license.txt in the Thrift distribution for
32 #include "thrift/platform.h"
33 #include "thrift/generate/t_oop_generator.h"
37 using std::ostringstream
;
39 using std::stringstream
;
42 static const string endl
= "\n"; // avoid ostream << std::endl flushes
44 /* forward declarations */
45 string
initial_caps_to_underscores(string name
);
46 string
underscores_to_initial_caps(string name
);
47 string
to_upper_case(string name
);
48 string
to_lower_case(string name
);
51 * C code generator, using glib for C typing.
53 class t_c_glib_generator
: public t_oop_generator
{
56 t_c_glib_generator(t_program
* program
,
57 const map
<string
, string
>& parsed_options
,
58 const string
& option_string
)
59 : t_oop_generator(program
) {
61 std::map
<std::string
, std::string
>::const_iterator iter
;
63 /* set the output directory */
64 this->out_dir_base_
= "gen-c_glib";
67 for( iter
= parsed_options
.begin(); iter
!= parsed_options
.end(); ++iter
) {
68 throw "unknown option c_glib:" + iter
->first
;
71 /* set the namespace */
72 this->nspace
= program_
->get_namespace("c_glib");
74 if (this->nspace
.empty()) {
80 /* replace dots with underscores */
81 char* tmp
= strdup(this->nspace
.c_str());
82 for (unsigned int i
= 0; i
< strlen(tmp
); i
++) {
87 this->nspace
= string(tmp
, strlen(tmp
));
90 /* clean up the namespace for C.
91 * An input of 'namespace foo' should result in:
92 * - nspace = foo - for thrift objects and typedefs
93 * - nspace_u = Foo - for internal GObject prefixes
94 * - nspace_uc = FOO_ - for macro prefixes
95 * - nspace_lc = foo_ - for filename and method prefixes
96 * The underscores are there since uc and lc strings are used as file and
99 this->nspace_u
= initial_caps_to_underscores(this->nspace
);
100 this->nspace_uc
= to_upper_case(this->nspace_u
) + "_";
101 this->nspace_lc
= to_lower_case(this->nspace_u
) + "_";
105 /* initialization and destruction */
106 void init_generator() override
;
107 void close_generator() override
;
109 /* generation functions */
110 void generate_typedef(t_typedef
* ttypedef
) override
;
111 void generate_enum(t_enum
* tenum
) override
;
112 void generate_consts(vector
<t_const
*> consts
) override
;
113 void generate_struct(t_struct
* tstruct
) override
;
114 void generate_service(t_service
* tservice
) override
;
115 void generate_xception(t_struct
* tstruct
) override
;
119 ofstream_with_content_based_conditional_update f_types_
;
120 ofstream_with_content_based_conditional_update f_types_impl_
;
121 ofstream_with_content_based_conditional_update f_header_
;
122 ofstream_with_content_based_conditional_update f_service_
;
124 /* namespace variables */
130 /* helper functions */
131 bool is_complex_type(t_type
* ttype
);
132 bool is_numeric(t_type
* ttype
);
133 string
type_name(t_type
* ttype
, bool in_typedef
= false, bool is_const
= false);
134 string
property_type_name(t_type
* ttype
, bool in_typedef
= false, bool is_const
= false);
135 string
base_type_name(t_type
* type
);
136 string
type_to_enum(t_type
* type
);
137 string
constant_literal(t_type
* type
, t_const_value
* value
);
138 string
constant_value(string name
, t_type
* type
, t_const_value
* value
);
139 string
constant_value_with_storage(string name
, t_type
* type
, t_const_value
* value
);
140 string
function_signature(t_function
* tfunction
);
141 string
argument_list(t_struct
* tstruct
);
142 string
xception_list(t_struct
* tstruct
);
143 string
declare_field(t_field
* tfield
,
145 bool pointer
= false,
146 bool constant
= false,
147 bool reference
= false);
148 void declare_local_variable(ostream
& out
, t_type
* ttype
, string
& base_name
, bool for_hash_table
);
149 void declore_local_variable_for_write(ostream
& out
, t_type
* ttype
, string
& base_name
);
151 /* generation functions */
152 void generate_const_initializer(string name
,
154 t_const_value
* value
,
155 bool top_level
= false);
156 void generate_service_helpers(t_service
* tservice
);
157 void generate_service_client(t_service
* tservice
);
158 void generate_service_handler(t_service
* tservice
);
159 void generate_service_processor(t_service
* tservice
);
160 void generate_service_server(t_service
* tservice
);
161 void generate_object(t_struct
* tstruct
);
162 void generate_struct_writer(ostream
& out
,
165 string this_get
= "",
166 bool is_function
= true);
167 void generate_struct_reader(ostream
& out
,
170 string this_get
= "",
171 bool is_function
= true);
173 void generate_serialize_field(ostream
& out
,
178 void generate_serialize_struct(ostream
& out
, t_struct
* tstruct
, string prefix
, int error_ret
);
179 void generate_serialize_container(ostream
& out
, t_type
* ttype
, string prefix
, int error_ret
);
180 void generate_serialize_map_element(ostream
& out
,
185 void generate_serialize_set_element(ostream
& out
, t_set
* tset
, string element
, int error_ret
);
186 void generate_serialize_list_element(ostream
& out
,
192 void generate_deserialize_field(ostream
& out
,
197 bool allocate
= true);
198 void generate_deserialize_struct(ostream
& out
,
202 bool allocate
= true);
203 void generate_deserialize_container(ostream
& out
, t_type
* ttype
, string prefix
, int error_ret
);
204 void generate_deserialize_map_element(ostream
& out
, t_map
* tmap
, string prefix
, int error_ret
);
205 void generate_deserialize_set_element(ostream
& out
, t_set
* tset
, string prefix
, int error_ret
);
206 void generate_deserialize_list_element(ostream
& out
,
212 string
generate_new_hash_from_type(t_type
* key
, t_type
* value
);
213 string
generate_new_array_from_type(t_type
* ttype
);
215 string
generate_free_func_from_type(t_type
* ttype
);
216 string
generate_hash_func_from_type(t_type
* ttype
);
217 string
generate_cmp_func_from_type(t_type
* ttype
);
221 * Prepare for file generation by opening up the necessary file
224 void t_c_glib_generator::init_generator() {
225 /* create output directory */
226 MKDIR(get_out_dir().c_str());
228 string program_name_u
= initial_caps_to_underscores(program_name_
);
229 string program_name_uc
= to_upper_case(program_name_u
);
230 string program_name_lc
= to_lower_case(program_name_u
);
232 /* create output files */
233 string f_types_name
= get_out_dir() + this->nspace_lc
+ program_name_lc
+ "_types.h";
234 f_types_
.open(f_types_name
.c_str());
235 string f_types_impl_name
= get_out_dir() + this->nspace_lc
+ program_name_lc
+ "_types.c";
236 f_types_impl_
.open(f_types_impl_name
.c_str());
238 /* add thrift boilerplate headers */
239 f_types_
<< autogen_comment();
240 f_types_impl_
<< autogen_comment();
242 /* include inclusion guard */
243 f_types_
<< "#ifndef " << this->nspace_uc
<< program_name_uc
<< "_TYPES_H" << endl
<< "#define "
244 << this->nspace_uc
<< program_name_uc
<< "_TYPES_H" << endl
<< endl
;
246 /* include base types */
247 f_types_
<< "/* base includes */" << endl
<< "#include <glib-object.h>" << endl
248 << "#include <thrift/c_glib/thrift_struct.h>" << endl
249 << "#include <thrift/c_glib/protocol/thrift_protocol.h>" << endl
;
251 /* include other thrift includes */
252 const vector
<t_program
*>& includes
= program_
->get_includes();
253 if (!includes
.empty()) {
254 f_types_
<< "/* other thrift includes */" << endl
;
256 for (auto include
: includes
) {
257 const std::string
& include_nspace
= include
->get_namespace("c_glib");
258 std::string include_nspace_prefix
=
259 include_nspace
.empty() ? "" : initial_caps_to_underscores(include_nspace
) + "_";
261 f_types_
<< "#include \"" << include_nspace_prefix
262 << initial_caps_to_underscores(include
->get_name()) << "_types.h\"" << endl
;
267 /* include custom headers */
268 const vector
<string
>& c_includes
= program_
->get_c_includes();
269 f_types_
<< "/* custom thrift includes */" << endl
;
270 for (const auto & c_include
: c_includes
) {
271 if (c_include
[0] == '<') {
272 f_types_
<< "#include " << c_include
<< endl
;
274 f_types_
<< "#include \"" << c_include
<< "\"" << endl
;
279 /* include math.h (for "INFINITY") in the implementation file, in case we
280 encounter a struct with a member of type double */
281 f_types_impl_
<< endl
<< "#include <math.h>" << endl
;
283 // include the types file
284 f_types_impl_
<< endl
<< "#include \"" << this->nspace_lc
<< program_name_u
<< "_types.h\""
285 << endl
<< "#include <thrift/c_glib/thrift.h>" << endl
<< endl
;
287 f_types_
<< "/* begin types */" << endl
<< endl
;
291 * Finish up generation and close all file streams.
293 void t_c_glib_generator::close_generator() {
294 string program_name_uc
= to_upper_case(initial_caps_to_underscores(program_name_
));
296 /* end the header inclusion guard */
297 f_types_
<< "#endif /* " << this->nspace_uc
<< program_name_uc
<< "_TYPES_H */" << endl
;
299 /* close output file */
301 f_types_impl_
.close();
305 * Generates a Thrift typedef in C code. For example:
308 * typedef map<i32,i32> SomeMap
311 * typedef GHashTable * ThriftSomeMap;
313 void t_c_glib_generator::generate_typedef(t_typedef
* ttypedef
) {
314 f_types_
<< indent() << "typedef " << type_name(ttypedef
->get_type(), true) << " " << this->nspace
315 << ttypedef
->get_symbolic() << ";" << endl
<< endl
;
319 * Generates a C enumeration. For example:
328 * enum _ThriftMyEnum {
329 * THRIFT_MY_ENUM_ONE = 1,
332 * typedef enum _ThriftMyEnum ThriftMyEnum;
334 void t_c_glib_generator::generate_enum(t_enum
* tenum
) {
335 string name
= tenum
->get_name();
336 string name_uc
= to_upper_case(initial_caps_to_underscores(name
));
338 f_types_
<< indent() << "enum _" << this->nspace
<< name
<< " {" << endl
;
342 vector
<t_enum_value
*> constants
= tenum
->get_constants();
343 vector
<t_enum_value
*>::iterator c_iter
;
346 /* output each of the enumeration elements */
347 for (c_iter
= constants
.begin(); c_iter
!= constants
.end(); ++c_iter
) {
351 f_types_
<< "," << endl
;
354 f_types_
<< indent() << this->nspace_uc
<< name_uc
<< "_" << (*c_iter
)->get_name();
355 f_types_
<< " = " << (*c_iter
)->get_value();
359 f_types_
<< endl
<< "};" << endl
<< "typedef enum _" << this->nspace
<< name
<< " "
360 << this->nspace
<< name
<< ";" << endl
<< endl
;
362 f_types_
<< "/* return the name of the constant */" << endl
;
363 f_types_
<< "const char *" << endl
;
364 f_types_
<< "toString_" << name
<< "(int value); " << endl
<< endl
;
366 f_types_impl_
<< "/* return the name of the constant */" << endl
;
367 f_types_impl_
<< "const char *" << endl
;
368 f_types_impl_
<< "toString_" << name
<< "(int value) " << endl
;
369 f_types_impl_
<< "{" << endl
;
370 f_types_impl_
<< " static __thread char buf[16] = {0};" << endl
;
371 f_types_impl_
<< " switch(value) {" << endl
;
373 for (c_iter
= constants
.begin(); c_iter
!= constants
.end(); ++c_iter
) {
374 int value
= (*c_iter
)->get_value();
375 // Skipping duplicate value
376 if (done
.find(value
) == done
.end()) {
378 f_types_impl_
<< " case " << this->nspace_uc
<< name_uc
<< "_" << (*c_iter
)->get_name()
380 << "return \"" << this->nspace_uc
<< name_uc
<< "_" << (*c_iter
)->get_name()
384 f_types_impl_
<< " default: g_snprintf(buf, 16, \"%d\", value); return buf;" << endl
;
385 f_types_impl_
<< " }" << endl
;
386 f_types_impl_
<< "}" << endl
<< endl
;
390 * Generates Thrift constants in C code.
392 void t_c_glib_generator::generate_consts(vector
<t_const
*> consts
) {
393 f_types_
<< "/* constants */" << endl
;
394 f_types_impl_
<< "/* constants */" << endl
;
396 vector
<t_const
*>::iterator c_iter
;
397 for (c_iter
= consts
.begin(); c_iter
!= consts
.end(); ++c_iter
) {
398 string name
= (*c_iter
)->get_name();
399 string name_uc
= to_upper_case(name
);
400 string name_lc
= to_lower_case(name
);
401 t_type
* type
= (*c_iter
)->get_type();
402 t_const_value
* value
= (*c_iter
)->get_value();
404 if (is_complex_type(type
)) {
405 f_types_
<< type_name(type
) << indent() << this->nspace_lc
<< name_lc
406 << "_constant();" << endl
;
409 f_types_
<< indent() << "#define " << this->nspace_uc
<< name_uc
<< " "
410 << constant_value(name_lc
, type
, value
) << endl
;
412 generate_const_initializer(name_lc
, type
, value
, true);
416 f_types_impl_
<< endl
;
420 * Generate Thrift structs in C code, as GObjects. Example:
429 * C GObject instance header:
437 * typedef struct _ThriftBonk ThriftBonk
438 * // ... additional GObject boilerplate ...
440 void t_c_glib_generator::generate_struct(t_struct
* tstruct
) {
441 f_types_
<< "/* struct " << tstruct
->get_name() << " */" << endl
;
442 generate_object(tstruct
);
446 * Generate C code to represent Thrift services. Creates a new GObject
447 * which can be used to access the service.
449 void t_c_glib_generator::generate_service(t_service
* tservice
) {
450 string svcname_u
= initial_caps_to_underscores(tservice
->get_name());
451 string svcname_uc
= this->nspace_uc
+ to_upper_case(svcname_u
);
452 string filename
= this->nspace_lc
+ to_lower_case(svcname_u
);
455 string f_header_name
= get_out_dir() + filename
+ ".h";
456 f_header_
.open(f_header_name
.c_str());
458 string program_name_u
= initial_caps_to_underscores(program_name_
);
459 string program_name_lc
= to_lower_case(program_name_u
);
461 // add header file boilerplate
462 f_header_
<< autogen_comment();
464 // add an inclusion guard
465 f_header_
<< "#ifndef " << svcname_uc
<< "_H" << endl
<< "#define " << svcname_uc
<< "_H" << endl
468 // add standard includes
469 f_header_
<< "#include <thrift/c_glib/processor/thrift_dispatch_processor.h>" << endl
<< endl
;
470 f_header_
<< "#include \"" << this->nspace_lc
<< program_name_lc
<< "_types.h\"" << endl
;
472 // if we are inheriting from another service, include its header
473 t_service
* extends_service
= tservice
->get_extends();
474 if (extends_service
!= NULL
) {
475 f_header_
<< "#include \"" << this->nspace_lc
476 << to_lower_case(initial_caps_to_underscores(extends_service
->get_name())) << ".h\""
481 // create the service implementation
482 string f_service_name
= get_out_dir() + filename
+ ".c";
483 f_service_
.open(f_service_name
.c_str());
485 // add the boilerplace header
486 f_service_
<< autogen_comment();
488 // include the headers
489 f_service_
<< "#include <string.h>" << endl
<< "#include <thrift/c_glib/thrift.h>" << endl
490 << "#include <thrift/c_glib/thrift_application_exception.h>" << endl
<< "#include \""
491 << filename
<< ".h\"" << endl
<< endl
;
493 // generate the service-helper classes
494 generate_service_helpers(tservice
);
496 // generate the client objects
497 generate_service_client(tservice
);
499 // generate the server objects
500 generate_service_server(tservice
);
502 // end the header inclusion guard
503 f_header_
<< "#endif /* " << svcname_uc
<< "_H */" << endl
;
513 void t_c_glib_generator::generate_xception(t_struct
* tstruct
) {
514 string name
= tstruct
->get_name();
515 string name_u
= initial_caps_to_underscores(name
);
516 string name_lc
= to_lower_case(name_u
);
517 string name_uc
= to_upper_case(name_u
);
519 generate_object(tstruct
);
521 f_types_
<< "/* exception */" << endl
522 << "typedef enum" << endl
525 f_types_
<< indent() << this->nspace_uc
<< name_uc
<< "_ERROR_CODE" << endl
;
527 f_types_
<< "} " << this->nspace
<< name
<< "Error;" << endl
529 << "GQuark " << this->nspace_lc
<< name_lc
530 << "_error_quark (void);" << endl
531 << "#define " << this->nspace_uc
<< name_uc
<< "_ERROR ("
532 << this->nspace_lc
<< name_lc
<< "_error_quark())" << endl
536 f_types_impl_
<< "/* define the GError domain for exceptions */" << endl
<< "#define "
537 << this->nspace_uc
<< name_uc
<< "_ERROR_DOMAIN \"" << this->nspace_lc
<< name_lc
538 << "_error_quark\"" << endl
<< "GQuark" << endl
<< this->nspace_lc
<< name_lc
539 << "_error_quark (void)" << endl
<< "{" << endl
540 << " return g_quark_from_static_string (" << this->nspace_uc
<< name_uc
541 << "_ERROR_DOMAIN);" << endl
<< "}" << endl
<< endl
;
544 /********************
546 ********************/
549 * Returns true if ttype is not a primitive.
551 bool t_c_glib_generator::is_complex_type(t_type
* ttype
) {
552 ttype
= get_true_type(ttype
);
554 return ttype
->is_container() || ttype
->is_struct() || ttype
->is_xception();
557 bool t_c_glib_generator::is_numeric(t_type
* ttype
) {
558 return ttype
->is_enum() || (ttype
->is_base_type() && !ttype
->is_string());
562 * Maps a Thrift t_type to a C type.
564 string
t_c_glib_generator::type_name(t_type
* ttype
, bool in_typedef
, bool is_const
) {
565 if (ttype
->is_base_type()) {
566 string bname
= base_type_name(ttype
);
569 return "const " + bname
;
575 if (ttype
->is_container()) {
578 t_container
* tcontainer
= (t_container
*)ttype
;
579 if (tcontainer
->has_cpp_name()) {
580 cname
= tcontainer
->get_cpp_name();
581 } else if (ttype
->is_map()) {
582 cname
= "GHashTable";
583 } else if (ttype
->is_set()) {
584 // since a set requires unique elements, use a GHashTable, and
585 // populate the keys and values with the same data, using keys for
586 // the actual writes and reads.
587 // TODO: discuss whether or not to implement TSet, THashSet or GHashSet
588 cname
= "GHashTable";
589 } else if (ttype
->is_list()) {
590 t_type
* etype
= get_true_type(((t_list
*)ttype
)->get_elem_type());
591 if (etype
->is_void()) {
592 throw std::runtime_error("compiler error: list element type cannot be void");
594 // TODO: investigate other implementations besides GPtrArray
595 cname
= is_numeric(etype
) ? "GArray" : "GPtrArray";
598 /* Omit the dereference operator if we are aliasing this type within a
599 typedef, to allow the type to be used more naturally in client code;
600 otherwise, include it */
606 return "const " + cname
;
612 // check for a namespace
613 t_program
* tprogram
= ttype
->get_program();
614 string pname
= (tprogram
? tprogram
->get_namespace("c_glib") : "") + ttype
->get_name();
616 if (is_complex_type(ttype
)) {
621 return "const " + pname
;
628 * Maps a Thrift primitive to the type needed to hold its value when used as an
631 * This method is needed because all integer properties of width less than 64
632 * bits map to the same type, gint, as opposed to their width-specific type
633 * (gint8, gint16 or gint32).
635 string
t_c_glib_generator::property_type_name(t_type
* ttype
, bool in_typedef
, bool is_const
) {
638 if (ttype
->is_base_type()) {
639 switch (((t_base_type
*)ttype
)->get_base()) {
640 case t_base_type::TYPE_I8
:
641 case t_base_type::TYPE_I16
:
642 case t_base_type::TYPE_I32
:
644 result
= "const gint";
651 result
= type_name(ttype
, in_typedef
, is_const
);
654 result
= type_name(ttype
, in_typedef
, is_const
);
661 * Maps a Thrift primitive to a C primitive.
663 string
t_c_glib_generator::base_type_name(t_type
* type
) {
664 if (type
->is_enum()) {
665 return type_name(type
);
667 if (!type
->is_base_type()) {
668 throw std::invalid_argument("Only base types are suppported.");
670 t_base_type
* base_type
= reinterpret_cast<t_base_type
*>(type
);
671 t_base_type::t_base tbase
= base_type
->get_base();
673 case t_base_type::TYPE_VOID
:
675 case t_base_type::TYPE_STRING
:
676 if (base_type
->is_binary()) {
677 return "GByteArray *";
681 case t_base_type::TYPE_BOOL
:
683 case t_base_type::TYPE_I8
:
685 case t_base_type::TYPE_I16
:
687 case t_base_type::TYPE_I32
:
689 case t_base_type::TYPE_I64
:
691 case t_base_type::TYPE_DOUBLE
:
694 throw std::logic_error("compiler error: no C base type name for base type "
695 + t_base_type::t_base_name(tbase
));
700 * Returns a member of the ThriftType C enumeration in thrift_protocol.h
703 string
t_c_glib_generator::type_to_enum(t_type
* type
) {
704 type
= get_true_type(type
);
706 if (type
->is_base_type()) {
707 t_base_type::t_base tbase
= ((t_base_type
*)type
)->get_base();
710 case t_base_type::TYPE_VOID
:
711 throw "NO T_VOID CONSTRUCT";
712 case t_base_type::TYPE_STRING
:
714 case t_base_type::TYPE_BOOL
:
716 case t_base_type::TYPE_I8
:
718 case t_base_type::TYPE_I16
:
720 case t_base_type::TYPE_I32
:
722 case t_base_type::TYPE_I64
:
724 case t_base_type::TYPE_DOUBLE
:
727 } else if (type
->is_enum()) {
729 } else if (type
->is_struct()) {
731 } else if (type
->is_xception()) {
733 } else if (type
->is_map()) {
735 } else if (type
->is_set()) {
737 } else if (type
->is_list()) {
741 throw "INVALID TYPE IN type_to_enum: " + type
->get_name();
745 * Returns a Thrift constant formatted as a literal for inclusion in C code.
747 string
t_c_glib_generator::constant_literal(t_type
* type
, t_const_value
* value
) {
748 ostringstream render
;
750 if (type
->is_base_type()) {
752 t_base_type::t_base tbase
= ((t_base_type
*)type
)->get_base();
755 case t_base_type::TYPE_STRING
:
756 render
<< "\"" + value
->get_string() + "\"";
758 case t_base_type::TYPE_BOOL
:
759 render
<< ((value
->get_integer() != 0) ? "TRUE" : "FALSE");
761 case t_base_type::TYPE_I8
:
762 case t_base_type::TYPE_I16
:
763 case t_base_type::TYPE_I32
:
764 case t_base_type::TYPE_I64
:
765 render
<< value
->get_integer();
767 case t_base_type::TYPE_DOUBLE
:
768 render
<< value
->get_double();
771 throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase
);
774 t_const_value::t_const_value_type value_type
= value
->get_type();
776 switch (value_type
) {
777 case t_const_value::CV_IDENTIFIER
:
778 render
<< value
->get_integer();
780 case t_const_value::CV_LIST
:
783 t_type
* elem_type
= ((t_list
*)type
)->get_elem_type();
784 const vector
<t_const_value
*>& list
= value
->get_list();
785 vector
<t_const_value
*>::const_iterator list_iter
;
787 if (list
.size() > 0) {
788 list_iter
= list
.begin();
789 render
<< constant_literal(elem_type
, *list_iter
);
791 while (++list_iter
!= list
.end()) {
792 render
<< ", " << constant_literal(elem_type
, *list_iter
);
798 case t_const_value::CV_MAP
:
800 render
<< "NULL /* not supported */";
808 * Returns C code that represents a Thrift constant.
810 string
t_c_glib_generator::constant_value(string name
, t_type
* type
, t_const_value
* value
) {
811 ostringstream render
;
813 if (type
->is_base_type()) {
815 t_base_type::t_base tbase
= ((t_base_type
*)type
)->get_base();
817 case t_base_type::TYPE_STRING
:
818 render
<< "g_strdup (\"" + value
->get_string() + "\")";
820 case t_base_type::TYPE_BOOL
:
821 render
<< ((value
->get_integer() != 0) ? 1 : 0);
823 case t_base_type::TYPE_I8
:
824 case t_base_type::TYPE_I16
:
825 case t_base_type::TYPE_I32
:
826 render
<< value
->get_integer();
828 case t_base_type::TYPE_I64
:
829 render
<< "G_GINT64_CONSTANT (" << value
->get_integer() << ")";
831 case t_base_type::TYPE_DOUBLE
:
832 if (value
->get_type() == t_const_value::CV_INTEGER
) {
833 render
<< value
->get_integer();
835 render
<< value
->get_double();
839 throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase
);
841 } else if (type
->is_enum()) {
842 render
<< "(" << type_name(type
) << ")" << value
->get_integer();
843 } else if (is_complex_type(type
)) {
844 render
<< "(" << this->nspace_lc
<< to_lower_case(name
) << "_constant())";
846 render
<< "NULL /* not supported */";
853 * Renders a function signature of the form 'type name(args)'
855 * @param tfunction Function definition
856 * @return String of rendered function definition
858 string
t_c_glib_generator::function_signature(t_function
* tfunction
) {
859 t_type
* ttype
= tfunction
->get_returntype();
860 t_struct
* arglist
= tfunction
->get_arglist();
861 t_struct
* xlist
= tfunction
->get_xceptions();
862 string fname
= initial_caps_to_underscores(tfunction
->get_name());
864 bool has_return
= !ttype
->is_void();
865 bool has_args
= arglist
->get_members().size() == 0;
866 bool has_xceptions
= xlist
->get_members().size() == 0;
867 return "gboolean " + this->nspace_lc
+ fname
+ " (" + this->nspace
+ service_name_
+ "If * iface"
868 + (has_return
? ", " + type_name(ttype
) + "* _return" : "")
869 + (has_args
? "" : (", " + argument_list(arglist
)))
870 + (has_xceptions
? "" : (", " + xception_list(xlist
))) + ", GError ** error)";
874 * Renders a field list
876 * @param tstruct The struct definition
877 * @return Comma sepearated list of all field names in that struct
879 string
t_c_glib_generator::argument_list(t_struct
* tstruct
) {
882 const vector
<t_field
*>& fields
= tstruct
->get_members();
883 vector
<t_field
*>::const_iterator f_iter
;
885 for (f_iter
= fields
.begin(); f_iter
!= fields
.end(); ++f_iter
) {
891 result
+= type_name((*f_iter
)->get_type(), false, true) + " " + (*f_iter
)->get_name();
897 * Renders mutable exception lists
899 * @param tstruct The struct definition
900 * @return Comma sepearated list of all field names in that struct
902 string
t_c_glib_generator::xception_list(t_struct
* tstruct
) {
905 const vector
<t_field
*>& fields
= tstruct
->get_members();
906 vector
<t_field
*>::const_iterator f_iter
;
908 for (f_iter
= fields
.begin(); f_iter
!= fields
.end(); ++f_iter
) {
914 result
+= type_name((*f_iter
)->get_type(), false, false) + "* " + (*f_iter
)->get_name();
920 * Declares a field, including any necessary initialization.
922 string
t_c_glib_generator::declare_field(t_field
* tfield
,
931 result
+= type_name(tfield
->get_type());
938 result
+= " " + tfield
->get_name();
940 t_type
* type
= get_true_type(tfield
->get_type());
942 if (type
->is_base_type()) {
943 t_base_type::t_base tbase
= ((t_base_type
*)type
)->get_base();
945 case t_base_type::TYPE_VOID
:
947 case t_base_type::TYPE_BOOL
:
948 case t_base_type::TYPE_I8
:
949 case t_base_type::TYPE_I16
:
950 case t_base_type::TYPE_I32
:
951 case t_base_type::TYPE_I64
:
954 case t_base_type::TYPE_DOUBLE
:
955 result
+= " = (gdouble) 0";
957 case t_base_type::TYPE_STRING
:
961 throw "compiler error: no C intializer for base type " + t_base_type::t_base_name(tbase
);
963 } else if (type
->is_enum()) {
964 result
+= " = (" + type_name(type
) + ") 0";
965 } else if (type
->is_struct() || type
->is_container()) {
977 string
t_c_glib_generator::constant_value_with_storage(string fname
,
979 t_const_value
* value
) {
980 ostringstream render
;
981 if (is_numeric(etype
)) {
982 render
<< " " << type_name(etype
) << " *" << fname
<< " = "
983 << "g_new (" << base_type_name(etype
) << ", 1);" << endl
984 << " *" << fname
<< " = " << constant_value(fname
, (t_type
*)etype
, value
) << ";"
987 render
<< " " << type_name(etype
) << " " << fname
<< " = "
988 << constant_value(fname
, (t_type
*)etype
, value
) << ";" << endl
;
994 * Generates C code that initializes complex constants.
996 void t_c_glib_generator::generate_const_initializer(string name
,
998 t_const_value
* value
,
1000 string name_u
= initial_caps_to_underscores(name
);
1001 string name_lc
= to_lower_case(name_u
);
1002 string type_u
= initial_caps_to_underscores(type
->get_name());
1003 string type_uc
= to_upper_case(type_u
);
1004 string maybe_static
= top_level
? "" : "static ";
1006 if (type
->is_struct() || type
->is_xception()) {
1007 const vector
<t_field
*>& fields
= ((t_struct
*)type
)->get_members();
1008 vector
<t_field
*>::const_iterator f_iter
;
1009 const map
<t_const_value
*, t_const_value
*, t_const_value::value_compare
>& val
= value
->get_map();
1010 map
<t_const_value
*, t_const_value
*, t_const_value::value_compare
>::const_iterator v_iter
;
1011 ostringstream initializers
;
1013 // initialize any constants that may be referenced by this initializer
1014 for (v_iter
= val
.begin(); v_iter
!= val
.end(); ++v_iter
) {
1015 t_type
* field_type
= NULL
;
1016 string field_name
= "";
1018 for (f_iter
= fields
.begin(); f_iter
!= fields
.end(); ++f_iter
) {
1019 if ((*f_iter
)->get_name() == v_iter
->first
->get_string()) {
1020 field_type
= (*f_iter
)->get_type();
1021 field_name
= (*f_iter
)->get_name();
1025 if (field_type
== NULL
) {
1026 throw "type error: " + type
->get_name() + " has no field "
1027 + v_iter
->first
->get_string();
1029 field_name
= tmp(field_name
);
1031 generate_const_initializer(name
+ "_constant_" + field_name
,
1034 initializers
<< " constant->" << v_iter
->first
->get_string() << " = "
1035 << constant_value(name
+ "_constant_" + field_name
,
1037 v_iter
->second
) << ";" << endl
1038 << " constant->__isset_" << v_iter
->first
->get_string()
1039 << " = TRUE;" << endl
;
1042 // implement the initializer
1043 f_types_impl_
<< maybe_static
<< this->nspace
<< type
->get_name() << " *"
1045 << this->nspace_lc
<< name_lc
<< "_constant (void)" << endl
;
1046 scope_up(f_types_impl_
);
1047 f_types_impl_
<< indent() << "static " << this->nspace
<< type
->get_name()
1048 << " *constant = NULL;" << endl
1049 << indent() << "if (constant == NULL)" << endl
;
1050 scope_up(f_types_impl_
);
1051 f_types_impl_
<< indent() << "constant = g_object_new (" << this->nspace_uc
1052 << "TYPE_" << type_uc
<< ", NULL);" << endl
1053 << initializers
.str();
1054 scope_down(f_types_impl_
);
1056 for (v_iter
= val
.begin(); v_iter
!= val
.end(); ++v_iter
) {
1057 t_type
* field_type
= NULL
;
1058 string field_name
= "";
1060 for (f_iter
= fields
.begin(); f_iter
!= fields
.end(); ++f_iter
) {
1061 if ((*f_iter
)->get_name() == v_iter
->first
->get_string()) {
1062 field_type
= (*f_iter
)->get_type();
1063 field_name
= (*f_iter
)->get_name();
1067 if (field_type
== NULL
) {
1068 throw "type error: " + type
->get_name() + " has no field "
1069 + v_iter
->first
->get_string();
1071 field_name
= tmp(field_name
);
1074 f_types_impl_
<< indent() << "return constant;" << endl
;
1075 scope_down(f_types_impl_
);
1076 f_types_impl_
<< endl
;
1077 } else if (type
->is_list()) {
1078 string list_type
= "GPtrArray *";
1080 = generate_free_func_from_type(reinterpret_cast<t_list
*>(type
)->get_elem_type());
1081 string list_initializer
= "g_ptr_array_new_with_free_func (" + free_func
+ ");";
1082 string list_appender
= "g_ptr_array_add";
1083 bool list_variable
= false;
1085 t_type
* etype
= ((t_list
*)type
)->get_elem_type();
1086 const vector
<t_const_value
*>& val
= value
->get_list();
1087 vector
<t_const_value
*>::const_iterator v_iter
;
1088 ostringstream initializers
;
1089 ostringstream appenders
;
1091 list_initializer
= generate_new_array_from_type(etype
);
1092 if (etype
->is_base_type()) {
1093 t_base_type::t_base tbase
= ((t_base_type
*)etype
)->get_base();
1095 case t_base_type::TYPE_VOID
:
1096 throw "compiler error: cannot determine array type";
1097 case t_base_type::TYPE_BOOL
:
1098 case t_base_type::TYPE_I8
:
1099 case t_base_type::TYPE_I16
:
1100 case t_base_type::TYPE_I32
:
1101 case t_base_type::TYPE_I64
:
1102 case t_base_type::TYPE_DOUBLE
:
1103 list_type
= "GArray *";
1104 list_appender
= "g_array_append_val";
1105 list_variable
= true;
1107 case t_base_type::TYPE_STRING
:
1110 throw "compiler error: no array info for type";
1112 } else if (etype
->is_enum()) {
1113 list_type
= "GArray *";
1114 list_appender
= "g_array_append_val";
1115 list_variable
= true;
1118 for (v_iter
= val
.begin(); v_iter
!= val
.end(); ++v_iter
) {
1119 string fname
= tmp(name
);
1121 generate_const_initializer(fname
, etype
, (*v_iter
));
1122 if (list_variable
) {
1123 initializers
<< " " << type_name(etype
) << " " << fname
<< " = "
1124 << constant_value(fname
, (t_type
*)etype
, (*v_iter
)) << ";"
1126 appenders
<< " " << list_appender
<< "(constant, " << fname
<< ");"
1129 appenders
<< " " << list_appender
<< "(constant, "
1130 << constant_value(fname
, (t_type
*)etype
, (*v_iter
)) << ");"
1135 f_types_impl_
<< maybe_static
<< list_type
<< endl
1136 << this->nspace_lc
<< name_lc
<< "_constant (void)" << endl
;
1137 scope_up(f_types_impl_
);
1138 f_types_impl_
<< indent() << "static " << list_type
<< " constant = NULL;"
1140 << indent() << "if (constant == NULL)" << endl
;
1141 scope_up(f_types_impl_
);
1142 if (!initializers
.str().empty()) {
1143 f_types_impl_
<< initializers
.str()
1146 f_types_impl_
<< indent() << "constant = " << list_initializer
<< endl
1148 scope_down(f_types_impl_
);
1149 f_types_impl_
<< indent() << "return constant;" << endl
;
1150 scope_down(f_types_impl_
);
1151 f_types_impl_
<< endl
;
1152 } else if (type
->is_set()) {
1153 t_type
* etype
= ((t_set
*)type
)->get_elem_type();
1154 const vector
<t_const_value
*>& val
= value
->get_list();
1155 vector
<t_const_value
*>::const_iterator v_iter
;
1156 ostringstream initializers
;
1157 ostringstream appenders
;
1159 for (v_iter
= val
.begin(); v_iter
!= val
.end(); ++v_iter
) {
1160 string fname
= tmp(name
);
1161 string ptr
= is_numeric(etype
) ? "*" : "";
1162 generate_const_initializer(fname
, etype
, (*v_iter
));
1163 initializers
<< constant_value_with_storage(fname
, (t_type
*)etype
, *v_iter
);
1164 appenders
<< " g_hash_table_insert (constant, " << fname
<< ", 0);" << endl
;
1167 f_types_impl_
<< maybe_static
<< "GHashTable *" << endl
1168 << this->nspace_lc
<< name_lc
<< "_constant (void)" << endl
;
1169 scope_up(f_types_impl_
);
1170 f_types_impl_
<< indent() << "static GHashTable *constant = NULL;" << endl
1171 << indent() << "if (constant == NULL)" << endl
;
1172 scope_up(f_types_impl_
);
1173 f_types_impl_
<< initializers
.str() << endl
1174 << indent() << "constant = " << generate_new_hash_from_type(etype
, NULL
) << endl
1176 scope_down(f_types_impl_
);
1177 f_types_impl_
<< indent() << "return constant;" << endl
;
1178 scope_down(f_types_impl_
);
1179 f_types_impl_
<< endl
;
1180 } else if (type
->is_map()) {
1181 t_type
* ktype
= ((t_map
*)type
)->get_key_type();
1182 t_type
* vtype
= ((t_map
*)type
)->get_val_type();
1183 const map
<t_const_value
*, t_const_value
*, t_const_value::value_compare
>& val
= value
->get_map();
1184 map
<t_const_value
*, t_const_value
*, t_const_value::value_compare
>::const_iterator v_iter
;
1185 ostringstream initializers
;
1186 ostringstream appenders
;
1188 for (v_iter
= val
.begin(); v_iter
!= val
.end(); ++v_iter
) {
1189 string fname
= tmp(name
);
1190 string kname
= fname
+ "key";
1191 string vname
= fname
+ "val";
1192 generate_const_initializer(kname
, ktype
, v_iter
->first
);
1193 generate_const_initializer(vname
, vtype
, v_iter
->second
);
1195 initializers
<< constant_value_with_storage(kname
, (t_type
*)ktype
, v_iter
->first
);
1196 initializers
<< constant_value_with_storage(vname
, (t_type
*)vtype
, v_iter
->second
);
1197 appenders
<< " g_hash_table_insert (constant, " << kname
<< ", " << vname
<< ");" << endl
;
1200 f_types_impl_
<< maybe_static
<< "GHashTable *" << endl
1201 << this->nspace_lc
<< name_lc
<< "_constant (void)" << endl
;
1202 scope_up(f_types_impl_
);
1203 f_types_impl_
<< indent() << "static GHashTable *constant = NULL;" << endl
1204 << indent() << "if (constant == NULL)" << endl
;
1205 scope_up(f_types_impl_
);
1206 f_types_impl_
<< initializers
.str() << endl
1207 << indent() << "constant = " << generate_new_hash_from_type(ktype
, vtype
) << endl
1209 scope_down(f_types_impl_
);
1210 f_types_impl_
<< indent() << "return constant;" << endl
;
1211 scope_down(f_types_impl_
);
1212 f_types_impl_
<< endl
;
1217 * Generates helper classes for a service, consisting of a ThriftStruct subclass
1218 * for the arguments to and the result from each method.
1220 * @param tservice The service for which to generate helper classes
1222 void t_c_glib_generator::generate_service_helpers(t_service
* tservice
) {
1223 vector
<t_function
*> functions
= tservice
->get_functions();
1224 vector
<t_function
*>::iterator function_iter
;
1226 // Iterate through the service's methods
1227 for (function_iter
= functions
.begin(); function_iter
!= functions
.end(); ++function_iter
) {
1228 string function_name
= (*function_iter
)->get_name();
1229 t_struct
* arg_list
= (*function_iter
)->get_arglist();
1230 string arg_list_name_orig
= arg_list
->get_name();
1232 // Generate the arguments class
1233 arg_list
->set_name(tservice
->get_name() + underscores_to_initial_caps(function_name
) + "Args");
1234 generate_struct(arg_list
);
1236 arg_list
->set_name(arg_list_name_orig
);
1238 // Generate the result class
1239 if (!(*function_iter
)->is_oneway()) {
1240 t_struct
result(program_
,
1241 tservice
->get_name() + underscores_to_initial_caps(function_name
) + "Result");
1242 t_field
success((*function_iter
)->get_returntype(), "success", 0);
1243 success
.set_req(t_field::T_OPTIONAL
);
1244 if (!(*function_iter
)->get_returntype()->is_void()) {
1245 result
.append(&success
);
1248 t_struct
* xs
= (*function_iter
)->get_xceptions();
1249 const vector
<t_field
*>& fields
= xs
->get_members();
1250 vector
<t_field
*>::const_iterator field_iter
;
1251 for (field_iter
= fields
.begin(); field_iter
!= fields
.end(); ++field_iter
) {
1252 (*field_iter
)->set_req(t_field::T_OPTIONAL
);
1253 result
.append(*field_iter
);
1256 generate_struct(&result
);
1262 * Generates C code that represents a Thrift service client.
1264 void t_c_glib_generator::generate_service_client(t_service
* tservice
) {
1265 /* get some C friendly service names */
1266 string service_name_lc
= to_lower_case(initial_caps_to_underscores(service_name_
));
1267 string service_name_uc
= to_upper_case(service_name_lc
);
1269 string parent_service_name
;
1270 string parent_service_name_lc
;
1271 string parent_service_name_uc
;
1273 string parent_class_name
= "GObject";
1274 string parent_type_name
= "G_TYPE_OBJECT";
1276 // The service this service extends, or NULL if it extends no
1278 t_service
* extends_service
= tservice
->get_extends();
1279 if (extends_service
) {
1280 // The name of the parent service
1281 parent_service_name
= extends_service
->get_name();
1282 parent_service_name_lc
= to_lower_case(initial_caps_to_underscores(parent_service_name
));
1283 parent_service_name_uc
= to_upper_case(parent_service_name_lc
);
1285 // The names of the client class' parent class and type
1286 parent_class_name
= this->nspace
+ parent_service_name
+ "Client";
1287 parent_type_name
= this->nspace_uc
+ "TYPE_" + parent_service_name_uc
+ "_CLIENT";
1290 // The base service (the topmost in the "extends" hierarchy), on
1291 // whose client class the "input_protocol" and "output_protocol"
1292 // properties are defined
1293 t_service
* base_service
= tservice
;
1294 while (base_service
->get_extends()) {
1295 base_service
= base_service
->get_extends();
1298 string base_service_name
= base_service
->get_name();
1299 string base_service_name_lc
= to_lower_case(initial_caps_to_underscores(base_service_name
));
1300 string base_service_name_uc
= to_upper_case(base_service_name_lc
);
1302 // Generate the client interface dummy object in the header.
1303 f_header_
<< "/* " << service_name_
<< " service interface */" << endl
<< "typedef struct _"
1304 << this->nspace
<< service_name_
<< "If " << this->nspace
<< service_name_
<< "If; "
1305 << " /* dummy object */" << endl
<< endl
;
1307 // Generate the client interface object in the header.
1308 f_header_
<< "struct _" << this->nspace
<< service_name_
<< "IfInterface" << endl
<< "{" << endl
1309 << " GTypeInterface parent;" << endl
<< endl
;
1311 /* write out the functions for this interface */
1313 vector
<t_function
*> functions
= tservice
->get_functions();
1314 vector
<t_function
*>::const_iterator f_iter
;
1315 for (f_iter
= functions
.begin(); f_iter
!= functions
.end(); ++f_iter
) {
1316 /* make the function name C friendly */
1317 string funname
= initial_caps_to_underscores((*f_iter
)->get_name());
1318 t_type
* ttype
= (*f_iter
)->get_returntype();
1319 t_struct
* arglist
= (*f_iter
)->get_arglist();
1320 t_struct
* xlist
= (*f_iter
)->get_xceptions();
1321 bool has_return
= !ttype
->is_void();
1322 bool has_args
= arglist
->get_members().size() == 0;
1323 bool has_xceptions
= xlist
->get_members().size() == 0;
1325 string params
= "(" + this->nspace
+ service_name_
+ "If *iface"
1326 + (has_return
? ", " + type_name(ttype
) + "* _return" : "")
1327 + (has_args
? "" : (", " + argument_list(arglist
)))
1328 + (has_xceptions
? "" : (", " + xception_list(xlist
))) + ", GError **error)";
1330 indent(f_header_
) << "gboolean (*" << funname
<< ") " << params
<< ";" << endl
;
1334 f_header_
<< "};" << endl
<< "typedef struct _" << this->nspace
<< service_name_
<< "IfInterface "
1335 << this->nspace
<< service_name_
<< "IfInterface;" << endl
<< endl
;
1337 // generate all the interface boilerplate
1338 f_header_
<< "GType " << this->nspace_lc
<< service_name_lc
<< "_if_get_type (void);" << endl
1339 << "#define " << this->nspace_uc
<< "TYPE_" << service_name_uc
<< "_IF "
1340 << "(" << this->nspace_lc
<< service_name_lc
<< "_if_get_type())" << endl
<< "#define "
1341 << this->nspace_uc
<< service_name_uc
<< "_IF(obj) "
1342 << "(G_TYPE_CHECK_INSTANCE_CAST ((obj), " << this->nspace_uc
<< "TYPE_"
1343 << service_name_uc
<< "_IF, " << this->nspace
<< service_name_
<< "If))" << endl
1344 << "#define " << this->nspace_uc
<< "IS_" << service_name_uc
<< "_IF(obj) "
1345 << "(G_TYPE_CHECK_INSTANCE_TYPE ((obj), " << this->nspace_uc
<< "TYPE_"
1346 << service_name_uc
<< "_IF))" << endl
<< "#define " << this->nspace_uc
1347 << service_name_uc
<< "_IF_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), "
1348 << this->nspace_uc
<< "TYPE_" << service_name_uc
<< "_IF, " << this->nspace
1349 << service_name_
<< "IfInterface))" << endl
<< endl
;
1351 // write out all the interface function prototypes
1352 for (f_iter
= functions
.begin(); f_iter
!= functions
.end(); ++f_iter
) {
1353 /* make the function name C friendly */
1354 string funname
= initial_caps_to_underscores((*f_iter
)->get_name());
1355 t_type
* ttype
= (*f_iter
)->get_returntype();
1356 t_struct
* arglist
= (*f_iter
)->get_arglist();
1357 t_struct
* xlist
= (*f_iter
)->get_xceptions();
1358 bool has_return
= !ttype
->is_void();
1359 bool has_args
= arglist
->get_members().size() == 0;
1360 bool has_xceptions
= xlist
->get_members().size() == 0;
1362 string params
= "(" + this->nspace
+ service_name_
+ "If *iface"
1363 + (has_return
? ", " + type_name(ttype
) + "* _return" : "")
1364 + (has_args
? "" : (", " + argument_list(arglist
)))
1365 + (has_xceptions
? "" : (", " + xception_list(xlist
))) + ", GError **error)";
1367 f_header_
<< "gboolean " << this->nspace_lc
<< service_name_lc
<< "_if_" << funname
<< " "
1368 << params
<< ";" << endl
;
1372 // Generate the client object instance definition in the header.
1373 f_header_
<< "/* " << service_name_
<< " service client */" << endl
<< "struct _" << this->nspace
1374 << service_name_
<< "Client" << endl
<< "{" << endl
<< " " << parent_class_name
1375 << " parent;" << endl
;
1376 if (!extends_service
) {
1377 // Define "input_protocol" and "output_protocol" properties only
1378 // for base services; child service-client classes will inherit
1380 f_header_
<< endl
<< " ThriftProtocol *input_protocol;" << endl
1381 << " ThriftProtocol *output_protocol;" << endl
;
1383 f_header_
<< "};" << endl
<< "typedef struct _" << this->nspace
<< service_name_
<< "Client "
1384 << this->nspace
<< service_name_
<< "Client;" << endl
<< endl
;
1386 // Generate the class definition in the header.
1387 f_header_
<< "struct _" << this->nspace
<< service_name_
<< "ClientClass" << endl
<< "{" << endl
1388 << " " << parent_class_name
<< "Class parent;" << endl
<< "};" << endl
1389 << "typedef struct _" << this->nspace
<< service_name_
<< "ClientClass " << this->nspace
1390 << service_name_
<< "ClientClass;" << endl
<< endl
;
1392 // Create all the GObject boilerplate
1393 f_header_
<< "GType " << this->nspace_lc
<< service_name_lc
<< "_client_get_type (void);" << endl
1394 << "#define " << this->nspace_uc
<< "TYPE_" << service_name_uc
<< "_CLIENT "
1395 << "(" << this->nspace_lc
<< service_name_lc
<< "_client_get_type())" << endl
1396 << "#define " << this->nspace_uc
<< service_name_uc
<< "_CLIENT(obj) "
1397 << "(G_TYPE_CHECK_INSTANCE_CAST ((obj), " << this->nspace_uc
<< "TYPE_"
1398 << service_name_uc
<< "_CLIENT, " << this->nspace
<< service_name_
<< "Client))" << endl
1399 << "#define " << this->nspace_uc
<< service_name_uc
<< "_CLIENT_CLASS(c) "
1400 << "(G_TYPE_CHECK_CLASS_CAST ((c), " << this->nspace_uc
<< "TYPE_" << service_name_uc
1401 << "_CLIENT, " << this->nspace
<< service_name_
<< "ClientClass))" << endl
<< "#define "
1402 << this->nspace_uc
<< service_name_uc
<< "_IS_CLIENT(obj) "
1403 << "(G_TYPE_CHECK_INSTANCE_TYPE ((obj), " << this->nspace_uc
<< "TYPE_"
1404 << service_name_uc
<< "_CLIENT))" << endl
<< "#define " << this->nspace_uc
1405 << service_name_uc
<< "_IS_CLIENT_CLASS(c) "
1406 << "(G_TYPE_CHECK_CLASS_TYPE ((c), " << this->nspace_uc
<< "TYPE_" << service_name_uc
1407 << "_CLIENT))" << endl
<< "#define " << this->nspace_uc
<< service_name_uc
1408 << "_CLIENT_GET_CLASS(obj) "
1409 << "(G_TYPE_INSTANCE_GET_CLASS ((obj), " << this->nspace_uc
<< "TYPE_"
1410 << service_name_uc
<< "_CLIENT, " << this->nspace
<< service_name_
<< "ClientClass))"
1413 /* write out the function prototypes */
1414 for (f_iter
= functions
.begin(); f_iter
!= functions
.end(); ++f_iter
) {
1415 /* make the function name C friendly */
1416 string funname
= to_lower_case(initial_caps_to_underscores((*f_iter
)->get_name()));
1418 t_function
service_function((*f_iter
)->get_returntype(),
1419 service_name_lc
+ string("_client_") + funname
,
1420 (*f_iter
)->get_arglist(),
1421 (*f_iter
)->get_xceptions());
1422 indent(f_header_
) << function_signature(&service_function
) << ";" << endl
;
1424 t_function
send_function(g_type_void
,
1425 service_name_lc
+ string("_client_send_") + funname
,
1426 (*f_iter
)->get_arglist());
1427 indent(f_header_
) << function_signature(&send_function
) << ";" << endl
;
1429 // implement recv if not a oneway service
1430 if (!(*f_iter
)->is_oneway()) {
1431 t_struct
noargs(program_
);
1432 t_function
recv_function((*f_iter
)->get_returntype(),
1433 service_name_lc
+ string("_client_recv_") + funname
,
1435 (*f_iter
)->get_xceptions());
1436 indent(f_header_
) << function_signature(&recv_function
) << ";" << endl
;
1440 /* write out the get/set function prototypes */
1441 f_header_
<< "void " + service_name_lc
+ "_client_set_property (GObject *object, guint "
1442 "property_id, const GValue *value, GParamSpec *pspec);"
1444 f_header_
<< "void " + service_name_lc
+ "_client_get_property (GObject *object, guint "
1445 "property_id, GValue *value, GParamSpec *pspec);"
1449 // end of header code
1451 // Generate interface method implementations
1452 for (f_iter
= functions
.begin(); f_iter
!= functions
.end(); ++f_iter
) {
1453 /* make the function name C friendly */
1454 string funname
= initial_caps_to_underscores((*f_iter
)->get_name());
1455 t_type
* ttype
= (*f_iter
)->get_returntype();
1456 t_struct
* arglist
= (*f_iter
)->get_arglist();
1457 t_struct
* xlist
= (*f_iter
)->get_xceptions();
1458 bool has_return
= !ttype
->is_void();
1459 bool has_args
= arglist
->get_members().size() == 0;
1460 bool has_xceptions
= xlist
->get_members().size() == 0;
1462 string params
= "(" + this->nspace
+ service_name_
+ "If *iface"
1463 + (has_return
? ", " + type_name(ttype
) + "* _return" : "")
1464 + (has_args
? "" : (", " + argument_list(arglist
)))
1465 + (has_xceptions
? "" : (", " + xception_list(xlist
))) + ", GError **error)";
1467 string params_without_type
= string("iface, ") + (has_return
? "_return, " : "");
1469 const vector
<t_field
*>& fields
= arglist
->get_members();
1470 vector
<t_field
*>::const_iterator f_iter_field
;
1471 for (f_iter_field
= fields
.begin(); f_iter_field
!= fields
.end(); ++f_iter_field
) {
1472 params_without_type
+= (*f_iter_field
)->get_name();
1473 params_without_type
+= ", ";
1476 const vector
<t_field
*>& xceptions
= xlist
->get_members();
1477 vector
<t_field
*>::const_iterator x_iter
;
1478 for (x_iter
= xceptions
.begin(); x_iter
!= xceptions
.end(); ++x_iter
) {
1479 params_without_type
+= (*x_iter
)->get_name();
1480 params_without_type
+= ", ";
1483 f_service_
<< "gboolean" << endl
<< this->nspace_lc
<< service_name_lc
<< "_if_" << funname
1484 << " " << params
<< endl
<< "{" << endl
<< " return " << this->nspace_uc
1485 << service_name_uc
<< "_IF_GET_INTERFACE (iface)->" << funname
<< " ("
1486 << params_without_type
<< "error);" << endl
<< "}" << endl
<< endl
;
1489 // Generate interface boilerplate
1490 f_service_
<< "GType" << endl
<< this->nspace_lc
<< service_name_lc
<< "_if_get_type (void)"
1491 << endl
<< "{" << endl
<< " static GType type = 0;" << endl
<< " if (type == 0)"
1492 << endl
<< " {" << endl
<< " static const GTypeInfo type_info =" << endl
<< " {"
1493 << endl
<< " sizeof (" << this->nspace
<< service_name_
<< "IfInterface)," << endl
1494 << " NULL, /* base_init */" << endl
<< " NULL, /* base_finalize */" << endl
1495 << " NULL, /* class_init */" << endl
<< " NULL, /* class_finalize */"
1496 << endl
<< " NULL, /* class_data */" << endl
1497 << " 0, /* instance_size */" << endl
<< " 0, /* n_preallocs */"
1498 << endl
<< " NULL, /* instance_init */" << endl
1499 << " NULL /* value_table */" << endl
<< " };" << endl
1500 << " type = g_type_register_static (G_TYPE_INTERFACE," << endl
1501 << " \"" << this->nspace
<< service_name_
<< "If\","
1502 << endl
<< " &type_info, 0);" << endl
<< " }"
1503 << endl
<< " return type;" << endl
<< "}" << endl
<< endl
;
1505 // Generate client boilerplate
1506 f_service_
<< "static void " << endl
<< this->nspace_lc
<< service_name_lc
1507 << "_if_interface_init (" << this->nspace
<< service_name_
<< "IfInterface *iface);"
1508 << endl
<< endl
<< "G_DEFINE_TYPE_WITH_CODE (" << this->nspace
<< service_name_
1509 << "Client, " << this->nspace_lc
<< service_name_lc
<< "_client," << endl
1510 << " " << parent_type_name
<< ", " << endl
1511 << " G_IMPLEMENT_INTERFACE (" << this->nspace_uc
<< "TYPE_"
1512 << service_name_uc
<< "_IF," << endl
1513 << " " << this->nspace_lc
1514 << service_name_lc
<< "_if_interface_init))" << endl
<< endl
;
1516 // Generate property-related code only for base services---child
1517 // service-client classes have only properties inherited from their
1519 if (!extends_service
) {
1520 // Generate client properties
1521 f_service_
<< "enum _" << this->nspace
<< service_name_
<< "ClientProperties" << endl
<< "{"
1522 << endl
<< " PROP_0," << endl
<< " PROP_" << this->nspace_uc
<< service_name_uc
1523 << "_CLIENT_INPUT_PROTOCOL," << endl
<< " PROP_" << this->nspace_uc
1524 << service_name_uc
<< "_CLIENT_OUTPUT_PROTOCOL" << endl
<< "};" << endl
<< endl
;
1526 // generate property setter
1527 f_service_
<< "void" << endl
<< this->nspace_lc
<< service_name_lc
<< "_client_set_property ("
1528 << "GObject *object, guint property_id, const GValue *value, "
1529 << "GParamSpec *pspec)" << endl
<< "{" << endl
<< " " << this->nspace
1530 << service_name_
<< "Client *client = " << this->nspace_uc
<< service_name_uc
1531 << "_CLIENT (object);" << endl
<< endl
<< " THRIFT_UNUSED_VAR (pspec);" << endl
1532 << endl
<< " switch (property_id)" << endl
<< " {" << endl
<< " case PROP_"
1533 << this->nspace_uc
<< service_name_uc
<< "_CLIENT_INPUT_PROTOCOL:" << endl
1534 << " client->input_protocol = g_value_get_object (value);" << endl
1535 << " break;" << endl
<< " case PROP_" << this->nspace_uc
<< service_name_uc
1536 << "_CLIENT_OUTPUT_PROTOCOL:" << endl
1537 << " client->output_protocol = g_value_get_object (value);" << endl
1538 << " break;" << endl
<< " }" << endl
<< "}" << endl
<< endl
;
1540 // generate property getter
1541 f_service_
<< "void" << endl
<< this->nspace_lc
<< service_name_lc
<< "_client_get_property ("
1542 << "GObject *object, guint property_id, GValue *value, "
1543 << "GParamSpec *pspec)" << endl
<< "{" << endl
<< " " << this->nspace
1544 << service_name_
<< "Client *client = " << this->nspace_uc
<< service_name_uc
1545 << "_CLIENT (object);" << endl
<< endl
<< " THRIFT_UNUSED_VAR (pspec);" << endl
1546 << endl
<< " switch (property_id)" << endl
<< " {" << endl
<< " case PROP_"
1547 << this->nspace_uc
<< service_name_uc
<< "_CLIENT_INPUT_PROTOCOL:" << endl
1548 << " g_value_set_object (value, client->input_protocol);" << endl
1549 << " break;" << endl
<< " case PROP_" << this->nspace_uc
<< service_name_uc
1550 << "_CLIENT_OUTPUT_PROTOCOL:" << endl
1551 << " g_value_set_object (value, client->output_protocol);" << endl
1552 << " break;" << endl
<< " }" << endl
<< "}" << endl
<< endl
;
1555 // Generate client method implementations
1556 for (f_iter
= functions
.begin(); f_iter
!= functions
.end(); ++f_iter
) {
1557 string name
= (*f_iter
)->get_name();
1558 string funname
= initial_caps_to_underscores(name
);
1560 // Get the struct of function call params and exceptions
1561 t_struct
* arg_struct
= (*f_iter
)->get_arglist();
1563 // Function for sending
1564 t_function
send_function(g_type_void
,
1565 service_name_lc
+ string("_client_send_") + funname
,
1566 (*f_iter
)->get_arglist());
1568 // Open the send function
1569 indent(f_service_
) << function_signature(&send_function
) << endl
;
1570 scope_up(f_service_
);
1572 string reqType
= (*f_iter
)->is_oneway() ? "T_ONEWAY" : "T_CALL";
1574 // Serialize the request
1575 f_service_
<< indent() << "gint32 cseqid = 0;" << endl
<< indent()
1576 << "ThriftProtocol * protocol = " << this->nspace_uc
<< base_service_name_uc
1577 << "_CLIENT (iface)->output_protocol;" << endl
<< endl
<< indent()
1578 << "if (thrift_protocol_write_message_begin (protocol, \"" << name
<< "\", "
1579 << reqType
<< ", cseqid, error) < 0)" << endl
<< indent() << " return FALSE;"
1582 generate_struct_writer(f_service_
, arg_struct
, "", "", false);
1584 f_service_
<< indent() << "if (thrift_protocol_write_message_end (protocol, error) < 0)" << endl
1585 << indent() << " return FALSE;" << endl
<< indent()
1586 << "if (!thrift_transport_flush (protocol->transport, error))" << endl
<< indent()
1587 << " return FALSE;" << endl
<< indent()
1588 << "if (!thrift_transport_write_end (protocol->transport, error))" << endl
1589 << indent() << " return FALSE;" << endl
<< endl
<< indent() << "return TRUE;"
1592 scope_down(f_service_
);
1595 // Generate recv function only if not an async function
1596 if (!(*f_iter
)->is_oneway()) {
1597 t_struct
noargs(program_
);
1598 t_function
recv_function((*f_iter
)->get_returntype(),
1599 service_name_lc
+ string("_client_recv_") + funname
,
1601 (*f_iter
)->get_xceptions());
1603 indent(f_service_
) << function_signature(&recv_function
) << endl
;
1604 scope_up(f_service_
);
1606 f_service_
<< indent() << "gint32 rseqid;" << endl
1607 << indent() << "gchar * fname = NULL;" << endl
1608 << indent() << "ThriftMessageType mtype;" << endl
1609 << indent() << "ThriftProtocol * protocol = "
1610 << this->nspace_uc
<< base_service_name_uc
1611 << "_CLIENT (iface)->input_protocol;" << endl
1612 << indent() << "ThriftApplicationException *xception;" << endl
1614 << indent() << "if (thrift_protocol_read_message_begin "
1615 "(protocol, &fname, &mtype, &rseqid, error) < 0) {" << endl
;
1617 f_service_
<< indent() << "if (fname) g_free (fname);" << endl
1618 << indent() << "return FALSE;" << endl
;
1620 f_service_
<< indent() << "}" << endl
1622 << indent() << "if (mtype == T_EXCEPTION) {" << endl
;
1624 f_service_
<< indent() << "if (fname) g_free (fname);" << endl
1625 << indent() << "xception = g_object_new "
1626 "(THRIFT_TYPE_APPLICATION_EXCEPTION, NULL);" << endl
1627 << indent() << "thrift_struct_read (THRIFT_STRUCT (xception), "
1628 "protocol, NULL);" << endl
1629 << indent() << "thrift_protocol_read_message_end "
1630 "(protocol, NULL);" << endl
1631 << indent() << "thrift_transport_read_end "
1632 "(protocol->transport, NULL);" << endl
1633 << indent() << "g_set_error (error, "
1634 "THRIFT_APPLICATION_EXCEPTION_ERROR,xception->type, "
1635 "\"application error: %s\", xception->message);" << endl
1636 << indent() << "g_object_unref (xception);" << endl
1637 << indent() << "return FALSE;" << endl
;
1639 f_service_
<< indent() << "} else if (mtype != T_REPLY) {" << endl
;
1641 f_service_
<< indent() << "if (fname) g_free (fname);" << endl
1642 << indent() << "thrift_protocol_skip (protocol, T_STRUCT, "
1644 << indent() << "thrift_protocol_read_message_end (protocol, "
1646 << indent() << "thrift_transport_read_end ("
1647 "protocol->transport, NULL);" << endl
1648 << indent() << "g_set_error (error, "
1649 "THRIFT_APPLICATION_EXCEPTION_ERROR, "
1650 "THRIFT_APPLICATION_EXCEPTION_ERROR_INVALID_MESSAGE_TYPE, "
1651 "\"invalid message type %d, expected T_REPLY\", mtype);"
1653 << indent() << "return FALSE;" << endl
;
1655 f_service_
<< indent() << "} else if (strncmp (fname, \"" << name
1656 << "\", " << name
.length() << ") != 0) {" << endl
;
1658 f_service_
<< indent() << "thrift_protocol_skip (protocol, T_STRUCT, "
1660 << indent() << "thrift_protocol_read_message_end (protocol,"
1662 << indent() << "thrift_transport_read_end ("
1663 "protocol->transport, error);" << endl
1664 << indent() << "g_set_error (error, "
1665 "THRIFT_APPLICATION_EXCEPTION_ERROR, "
1666 "THRIFT_APPLICATION_EXCEPTION_ERROR_WRONG_METHOD_NAME, "
1667 "\"wrong method name %s, expected " << name
1668 << "\", fname);" << endl
1669 << indent() << "if (fname) g_free (fname);" << endl
1670 << indent() << "return FALSE;" << endl
;
1672 f_service_
<< indent() << "}" << endl
1673 << indent() << "if (fname) g_free (fname);" << endl
1676 t_struct
* xs
= (*f_iter
)->get_xceptions();
1677 const std::vector
<t_field
*>& xceptions
= xs
->get_members();
1678 vector
<t_field
*>::const_iterator x_iter
;
1681 t_struct
result(program_
, tservice
->get_name() + "_" + (*f_iter
)->get_name() + "_result");
1682 t_field
success((*f_iter
)->get_returntype(), "*_return", 0);
1683 if (!(*f_iter
)->get_returntype()->is_void()) {
1684 result
.append(&success
);
1687 // add readers for exceptions, dereferencing the pointer.
1688 for (x_iter
= xceptions
.begin(); x_iter
!= xceptions
.end(); x_iter
++) {
1689 t_field
* xception
= new t_field((*x_iter
)->get_type(),
1690 "*" + (*x_iter
)->get_name(),
1691 (*x_iter
)->get_key());
1692 result
.append(xception
);
1695 generate_struct_reader(f_service_
, &result
, "", "", false);
1698 f_service_
<< indent() << "if (thrift_protocol_read_message_end (protocol, error) < 0)"
1699 << endl
<< indent() << " return FALSE;" << endl
<< endl
<< indent()
1700 << "if (!thrift_transport_read_end (protocol->transport, error))" << endl
1701 << indent() << " return FALSE;" << endl
<< endl
;
1703 // copy over any throw exceptions and return failure
1704 for (x_iter
= xceptions
.begin(); x_iter
!= xceptions
.end(); x_iter
++) {
1705 f_service_
<< indent() << "if (*" << (*x_iter
)->get_name() << " != NULL)" << endl
1706 << indent() << "{" << endl
<< indent() << " g_set_error (error, "
1708 << to_upper_case(initial_caps_to_underscores((*x_iter
)->get_type()->get_name()))
1709 << "_ERROR, " << this->nspace_uc
1710 << to_upper_case(initial_caps_to_underscores((*x_iter
)->get_type()->get_name()))
1711 << "_ERROR_CODE, \"" << (*x_iter
)->get_type()->get_name() << "\");" << endl
1712 << indent() << " return FALSE;" << endl
<< indent() << "}" << endl
;
1715 indent(f_service_
) << "return TRUE;" << endl
;
1716 scope_down(f_service_
);
1721 t_function
service_function((*f_iter
)->get_returntype(),
1722 service_name_lc
+ string("_client_") + funname
,
1723 (*f_iter
)->get_arglist(),
1724 (*f_iter
)->get_xceptions());
1725 indent(f_service_
) << function_signature(&service_function
) << endl
;
1726 scope_up(f_service_
);
1728 // wrap each function
1729 f_service_
<< indent() << "if (!" << this->nspace_lc
<< service_name_lc
<< "_client_send_"
1730 << funname
<< " (iface";
1732 // Declare the function arguments
1733 const vector
<t_field
*>& fields
= arg_struct
->get_members();
1734 vector
<t_field
*>::const_iterator fld_iter
;
1735 for (fld_iter
= fields
.begin(); fld_iter
!= fields
.end(); ++fld_iter
) {
1736 f_service_
<< ", " << (*fld_iter
)->get_name();
1738 f_service_
<< ", error))" << endl
<< indent() << " return FALSE;" << endl
;
1740 // if not oneway, implement recv
1741 if (!(*f_iter
)->is_oneway()) {
1742 string ret
= (*f_iter
)->get_returntype()->is_void() ? "" : "_return, ";
1744 const vector
<t_field
*>& xceptions
= (*f_iter
)->get_xceptions()->get_members();
1745 vector
<t_field
*>::const_iterator x_iter
;
1746 for (x_iter
= xceptions
.begin(); x_iter
!= xceptions
.end(); ++x_iter
) {
1747 ret
+= (*x_iter
)->get_name();
1751 f_service_
<< indent() << "if (!" << this->nspace_lc
<< service_name_lc
<< "_client_recv_"
1752 << funname
<< " (iface, " << ret
<< "error))" << endl
<< indent()
1753 << " return FALSE;" << endl
;
1756 // return TRUE which means all functions were called OK
1757 indent(f_service_
) << "return TRUE;" << endl
;
1758 scope_down(f_service_
);
1762 // create the interface initializer
1763 f_service_
<< "static void" << endl
1764 << this->nspace_lc
<< service_name_lc
<< "_if_interface_init ("
1765 << this->nspace
<< service_name_
<< "IfInterface *iface)" << endl
;
1766 scope_up(f_service_
);
1767 if (functions
.size() > 0) {
1768 for (f_iter
= functions
.begin(); f_iter
!= functions
.end(); ++f_iter
) {
1769 /* make the function name C friendly */
1770 string funname
= initial_caps_to_underscores((*f_iter
)->get_name());
1772 f_service_
<< indent() << "iface->" << funname
<< " = " << this->nspace_lc
1773 << service_name_lc
<< "_client_" << funname
<< ";" << endl
;
1777 f_service_
<< indent() << "THRIFT_UNUSED_VAR (iface);" << endl
;
1779 scope_down(f_service_
);
1782 // create the client instance initializer
1783 f_service_
<< "static void" << endl
1784 << this->nspace_lc
<< service_name_lc
<< "_client_init ("
1785 << this->nspace
<< service_name_
<< "Client *client)" << endl
;
1786 scope_up(f_service_
);
1787 if (!extends_service
) {
1788 f_service_
<< indent() << "client->input_protocol = NULL;" << endl
1789 << indent() << "client->output_protocol = NULL;" << endl
;
1792 f_service_
<< indent() << "THRIFT_UNUSED_VAR (client);" << endl
;
1794 scope_down(f_service_
);
1797 // create the client class initializer
1798 f_service_
<< "static void" << endl
<< this->nspace_lc
<< service_name_lc
1799 << "_client_class_init (" << this->nspace
<< service_name_
<< "ClientClass *cls)"
1800 << endl
<< "{" << endl
;
1801 if (!extends_service
) {
1802 f_service_
<< " GObjectClass *gobject_class = G_OBJECT_CLASS (cls);" << endl
1803 << " GParamSpec *param_spec;" << endl
<< endl
1804 << " gobject_class->set_property = " << this->nspace_lc
<< service_name_lc
1805 << "_client_set_property;" << endl
1806 << " gobject_class->get_property = " << this->nspace_lc
<< service_name_lc
1807 << "_client_get_property;" << endl
<< endl
1808 << " param_spec = g_param_spec_object (\"input_protocol\"," << endl
1809 << " \"input protocol (construct)\"," << endl
1810 << " \"Set the client input protocol\"," << endl
1811 << " THRIFT_TYPE_PROTOCOL," << endl
1812 << " G_PARAM_READWRITE);" << endl
1813 << " g_object_class_install_property (gobject_class," << endl
1814 << " PROP_" << this->nspace_uc
<< service_name_uc
1815 << "_CLIENT_INPUT_PROTOCOL, param_spec);" << endl
<< endl
1816 << " param_spec = g_param_spec_object (\"output_protocol\"," << endl
1817 << " \"output protocol (construct)\"," << endl
1818 << " \"Set the client output protocol\"," << endl
1819 << " THRIFT_TYPE_PROTOCOL," << endl
1820 << " G_PARAM_READWRITE);" << endl
1821 << " g_object_class_install_property (gobject_class," << endl
1822 << " PROP_" << this->nspace_uc
<< service_name_uc
1823 << "_CLIENT_OUTPUT_PROTOCOL, param_spec);" << endl
;
1826 f_service_
<< " THRIFT_UNUSED_VAR (cls);" << endl
;
1828 f_service_
<< "}" << endl
<< endl
;
1832 * Generates C code that represents a Thrift service handler.
1834 * @param tservice The service for which to generate a handler.
1836 void t_c_glib_generator::generate_service_handler(t_service
* tservice
) {
1837 vector
<t_function
*> functions
= tservice
->get_functions();
1838 vector
<t_function
*>::const_iterator function_iter
;
1840 string service_name_lc
= to_lower_case(initial_caps_to_underscores(service_name_
));
1841 string service_name_uc
= to_upper_case(service_name_lc
);
1843 string service_handler_name
= service_name_
+ "Handler";
1845 string class_name
= this->nspace
+ service_handler_name
;
1846 string class_name_lc
= this->nspace_lc
+ initial_caps_to_underscores(service_handler_name
);
1847 string class_name_uc
= to_upper_case(class_name_lc
);
1849 string parent_class_name
;
1850 string parent_type_name
;
1854 // The service this service extends, or NULL if it extends no service
1855 t_service
* extends_service
= tservice
->get_extends();
1857 // Determine the name of our parent service (if any) and the handler class'
1858 // parent class name and type
1859 if (extends_service
) {
1860 string parent_service_name
= extends_service
->get_name();
1861 string parent_service_name_lc
= to_lower_case(initial_caps_to_underscores(parent_service_name
));
1862 string parent_service_name_uc
= to_upper_case(parent_service_name_lc
);
1864 parent_class_name
= this->nspace
+ parent_service_name
+ "Handler";
1865 parent_type_name
= this->nspace_uc
+ "TYPE_" + parent_service_name_uc
+ "_HANDLER";
1867 parent_class_name
= "GObject";
1868 parent_type_name
= "G_TYPE_OBJECT";
1871 // Generate the handler class' definition in the header file
1873 // Generate the handler instance definition
1874 f_header_
<< "/* " << service_name_
<< " handler (abstract base class) */" << endl
<< "struct _"
1875 << class_name
<< endl
<< "{" << endl
;
1877 f_header_
<< indent() << parent_class_name
<< " parent;" << endl
;
1879 f_header_
<< "};" << endl
<< "typedef struct _" << class_name
<< " " << class_name
<< ";" << endl
1882 // Generate the handler class definition, including its class members
1884 f_header_
<< "struct _" << class_name
<< "Class" << endl
<< "{" << endl
;
1886 f_header_
<< indent() << parent_class_name
<< "Class parent;" << endl
<< endl
;
1888 for (function_iter
= functions
.begin(); function_iter
!= functions
.end(); ++function_iter
) {
1889 string method_name
= initial_caps_to_underscores((*function_iter
)->get_name());
1890 t_type
* return_type
= (*function_iter
)->get_returntype();
1891 t_struct
* arg_list
= (*function_iter
)->get_arglist();
1892 t_struct
* x_list
= (*function_iter
)->get_xceptions();
1893 bool has_return
= !return_type
->is_void();
1894 bool has_args
= arg_list
->get_members().size() == 0;
1895 bool has_xceptions
= x_list
->get_members().size() == 0;
1897 string params
= "(" + this->nspace
+ service_name_
+ "If *iface"
1898 + (has_return
? ", " + type_name(return_type
) + "* _return" : "")
1899 + (has_args
? "" : (", " + argument_list(arg_list
)))
1900 + (has_xceptions
? "" : (", " + xception_list(x_list
))) + ", GError **error)";
1902 indent(f_header_
) << "gboolean (*" << method_name
<< ") " << params
<< ";" << endl
;
1906 f_header_
<< "};" << endl
<< "typedef struct _" << class_name
<< "Class " << class_name
1907 << "Class;" << endl
<< endl
;
1909 // Generate the remaining header boilerplate
1910 f_header_
<< "GType " << class_name_lc
<< "_get_type (void);" << endl
<< "#define "
1911 << this->nspace_uc
<< "TYPE_" << service_name_uc
<< "_HANDLER "
1912 << "(" << class_name_lc
<< "_get_type())" << endl
<< "#define " << class_name_uc
1914 << "(G_TYPE_CHECK_INSTANCE_CAST ((obj), " << this->nspace_uc
<< "TYPE_"
1915 << service_name_uc
<< "_HANDLER, " << class_name
<< "))" << endl
<< "#define "
1916 << this->nspace_uc
<< "IS_" << service_name_uc
<< "_HANDLER(obj) "
1917 << "(G_TYPE_CHECK_INSTANCE_TYPE ((obj), " << this->nspace_uc
<< "TYPE_"
1918 << service_name_uc
<< "_HANDLER))" << endl
<< "#define " << class_name_uc
1919 << "_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), " << this->nspace_uc
<< "TYPE_"
1920 << service_name_uc
<< "_HANDLER, " << class_name
<< "Class))" << endl
<< "#define "
1921 << this->nspace_uc
<< "IS_" << service_name_uc
<< "_HANDLER_CLASS(c) "
1922 << "(G_TYPE_CHECK_CLASS_TYPE ((c), " << this->nspace_uc
<< "TYPE_" << service_name_uc
1923 << "_HANDLER))" << endl
<< "#define " << this->nspace_uc
<< service_name_uc
1924 << "_HANDLER_GET_CLASS(obj) "
1925 << "(G_TYPE_INSTANCE_GET_CLASS ((obj), " << this->nspace_uc
<< "TYPE_"
1926 << service_name_uc
<< "_HANDLER, " << class_name
<< "Class))" << endl
<< endl
;
1928 // Generate the handler class' method definitions
1929 for (function_iter
= functions
.begin(); function_iter
!= functions
.end(); ++function_iter
) {
1930 string method_name
= initial_caps_to_underscores((*function_iter
)->get_name());
1931 t_type
* return_type
= (*function_iter
)->get_returntype();
1932 t_struct
* arg_list
= (*function_iter
)->get_arglist();
1933 t_struct
* x_list
= (*function_iter
)->get_xceptions();
1934 bool has_return
= !return_type
->is_void();
1935 bool has_args
= arg_list
->get_members().size() == 0;
1936 bool has_xceptions
= x_list
->get_members().size() == 0;
1938 string params
= "(" + this->nspace
+ service_name_
+ "If *iface"
1939 + (has_return
? ", " + type_name(return_type
) + "* _return" : "")
1940 + (has_args
? "" : (", " + argument_list(arg_list
)))
1941 + (has_xceptions
? "" : (", " + xception_list(x_list
))) + ", GError **error)";
1943 f_header_
<< "gboolean " << class_name_lc
<< "_" << method_name
<< " " << params
<< ";" << endl
;
1947 // Generate the handler's implementation in the implementation file
1949 // Generate the implementation boilerplate
1950 f_service_
<< "static void" << endl
<< class_name_lc
<< "_" << service_name_lc
1951 << "_if_interface_init (" << this->nspace
<< service_name_
<< "IfInterface *iface);"
1954 args_indent
= string(25, ' ');
1955 f_service_
<< "G_DEFINE_TYPE_WITH_CODE (" << class_name
<< ", " << endl
<< args_indent
1956 << class_name_lc
<< "," << endl
<< args_indent
<< parent_type_name
<< "," << endl
1957 << args_indent
<< "G_IMPLEMENT_INTERFACE (" << this->nspace_uc
<< "TYPE_"
1958 << service_name_uc
<< "_IF," << endl
;
1959 args_indent
+= string(23, ' ');
1960 f_service_
<< args_indent
<< class_name_lc
<< "_" << service_name_lc
<< "_if_interface_init))"
1963 // Generate the handler method implementations
1964 for (function_iter
= functions
.begin(); function_iter
!= functions
.end(); ++function_iter
) {
1965 string function_name
= (*function_iter
)->get_name();
1966 string method_name
= initial_caps_to_underscores(function_name
);
1967 t_type
* return_type
= (*function_iter
)->get_returntype();
1968 t_struct
* arg_list
= (*function_iter
)->get_arglist();
1969 t_struct
* x_list
= (*function_iter
)->get_xceptions();
1971 const vector
<t_field
*>& args
= arg_list
->get_members();
1972 const vector
<t_field
*>& xceptions
= x_list
->get_members();
1974 vector
<t_field
*>::const_iterator field_iter
;
1976 t_function
implementing_function(return_type
,
1977 service_name_lc
+ "_handler_" + method_name
,
1980 (*function_iter
)->is_oneway());
1982 indent(f_service_
) << function_signature(&implementing_function
) << endl
;
1983 scope_up(f_service_
);
1984 f_service_
<< indent() << "g_return_val_if_fail (" << this->nspace_uc
<< "IS_"
1985 << service_name_uc
<< "_HANDLER (iface), FALSE);" << endl
<< endl
<< indent()
1986 << "return " << class_name_uc
<< "_GET_CLASS (iface)"
1987 << "->" << method_name
<< " (iface, ";
1989 if (!return_type
->is_void()) {
1990 f_service_
<< "_return, ";
1992 for (field_iter
= args
.begin(); field_iter
!= args
.end(); ++field_iter
) {
1993 f_service_
<< (*field_iter
)->get_name() << ", ";
1995 for (field_iter
= xceptions
.begin(); field_iter
!= xceptions
.end(); ++field_iter
) {
1996 f_service_
<< (*field_iter
)->get_name() << ", ";
1998 f_service_
<< "error);" << endl
;
1999 scope_down(f_service_
);
2003 // Generate the handler interface initializer
2004 f_service_
<< "static void" << endl
<< class_name_lc
<< "_" << service_name_lc
2005 << "_if_interface_init (" << this->nspace
<< service_name_
<< "IfInterface *iface)"
2007 scope_up(f_service_
);
2008 if (functions
.size() > 0) {
2009 for (function_iter
= functions
.begin(); function_iter
!= functions
.end(); ++function_iter
) {
2010 string method_name
= initial_caps_to_underscores((*function_iter
)->get_name());
2012 f_service_
<< indent() << "iface->" << method_name
<< " = " << class_name_lc
<< "_"
2013 << method_name
<< ";" << endl
;
2017 f_service_
<< "THRIFT_UNUSED_VAR (iface);" << endl
;
2019 scope_down(f_service_
);
2022 // Generate the handler instance initializer
2023 f_service_
<< "static void" << endl
<< class_name_lc
<< "_init (" << class_name
<< " *self)"
2025 scope_up(f_service_
);
2026 f_service_
<< indent() << "THRIFT_UNUSED_VAR (self);" << endl
;
2027 scope_down(f_service_
);
2030 // Generate the handler class initializer
2031 f_service_
<< "static void" << endl
2032 << class_name_lc
<< "_class_init (" << class_name
<< "Class *cls)"
2034 scope_up(f_service_
);
2035 if (functions
.size() > 0) {
2036 for (function_iter
= functions
.begin();
2037 function_iter
!= functions
.end();
2039 string function_name
= (*function_iter
)->get_name();
2040 string method_name
= initial_caps_to_underscores(function_name
);
2042 // All methods are pure virtual and must be implemented by subclasses
2043 f_service_
<< indent() << "cls->" << method_name
<< " = NULL;" << endl
;
2047 f_service_
<< indent() << "THRIFT_UNUSED_VAR (cls);" << endl
;
2049 scope_down(f_service_
);
2054 * Generates C code that represents a Thrift service processor.
2056 * @param tservice The service for which to generate a processor
2058 void t_c_glib_generator::generate_service_processor(t_service
* tservice
) {
2059 vector
<t_function
*> functions
= tservice
->get_functions();
2060 vector
<t_function
*>::const_iterator function_iter
;
2062 string service_name_lc
= to_lower_case(initial_caps_to_underscores(service_name_
));
2063 string service_name_uc
= to_upper_case(service_name_lc
);
2065 string service_processor_name
= service_name_
+ "Processor";
2067 string class_name
= this->nspace
+ service_processor_name
;
2068 string class_name_lc
= this->nspace_lc
+ initial_caps_to_underscores(service_processor_name
);
2069 string class_name_uc
= to_upper_case(class_name_lc
);
2071 string parent_class_name
;
2072 string parent_type_name
;
2074 string handler_class_name
= this->nspace
+ service_name_
+ "Handler";
2075 string handler_class_name_lc
= initial_caps_to_underscores(handler_class_name
);
2077 string process_function_type_name
= class_name
+ "ProcessFunction";
2078 string process_function_def_type_name
=
2079 class_name_lc
+ "_process_function_def";
2081 string function_name
;
2084 // The service this service extends, or NULL if it extends no service
2085 t_service
* extends_service
= tservice
->get_extends();
2087 // Determine the name of our parent service (if any) and the
2088 // processor class' parent class name and type
2089 if (extends_service
) {
2090 string parent_service_name
= extends_service
->get_name();
2091 string parent_service_name_lc
= to_lower_case(initial_caps_to_underscores(parent_service_name
));
2092 string parent_service_name_uc
= to_upper_case(parent_service_name_lc
);
2094 parent_class_name
= this->nspace
+ parent_service_name
+ "Processor";
2095 parent_type_name
= this->nspace_uc
+ "TYPE_" + parent_service_name_uc
+ "_PROCESSOR";
2097 parent_class_name
= "ThriftDispatchProcessor";
2098 parent_type_name
= "THRIFT_TYPE_DISPATCH_PROCESSOR";
2101 // Generate the processor class' definition in the header file
2103 // Generate the processor instance definition
2104 f_header_
<< "/* " << service_name_
<< " processor */" << endl
<< "struct _" << class_name
<< endl
2107 f_header_
<< indent() << parent_class_name
<< " parent;" << endl
<< endl
<< indent()
2108 << "/* protected */" << endl
<< indent()
2109 << this->nspace
+ service_name_
+ "Handler *handler;" << endl
<< indent()
2110 << "GHashTable *process_map;" << endl
;
2112 f_header_
<< "};" << endl
<< "typedef struct _" << class_name
<< " " << class_name
<< ";" << endl
2115 // Generate the processor class definition
2116 f_header_
<< "struct _" << class_name
<< "Class" << endl
<< "{" << endl
;
2118 f_header_
<< indent() << parent_class_name
<< "Class parent;" << endl
<< endl
<< indent()
2119 << "/* protected */" << endl
<< indent()
2120 << "gboolean (*dispatch_call) (ThriftDispatchProcessor *processor," << endl
;
2121 args_indent
= indent() + string(27, ' ');
2122 f_header_
<< args_indent
<< "ThriftProtocol *in," << endl
<< args_indent
<< "ThriftProtocol *out,"
2123 << endl
<< args_indent
<< "gchar *fname," << endl
<< args_indent
<< "gint32 seqid,"
2124 << endl
<< args_indent
<< "GError **error);" << endl
;
2126 f_header_
<< "};" << endl
<< "typedef struct _" << class_name
<< "Class " << class_name
2127 << "Class;" << endl
<< endl
;
2129 // Generate the remaining header boilerplate
2130 f_header_
<< "GType " << class_name_lc
<< "_get_type (void);" << endl
<< "#define "
2131 << this->nspace_uc
<< "TYPE_" << service_name_uc
<< "_PROCESSOR "
2132 << "(" << class_name_lc
<< "_get_type())" << endl
<< "#define " << class_name_uc
2134 << "(G_TYPE_CHECK_INSTANCE_CAST ((obj), " << this->nspace_uc
<< "TYPE_"
2135 << service_name_uc
<< "_PROCESSOR, " << class_name
<< "))" << endl
<< "#define "
2136 << this->nspace_uc
<< "IS_" << service_name_uc
<< "_PROCESSOR(obj) "
2137 << "(G_TYPE_CHECK_INSTANCE_TYPE ((obj), " << this->nspace_uc
<< "TYPE_"
2138 << service_name_uc
<< "_PROCESSOR))" << endl
<< "#define " << class_name_uc
2139 << "_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), " << this->nspace_uc
<< "TYPE_"
2140 << service_name_uc
<< "_PROCESSOR, " << class_name
<< "Class))" << endl
<< "#define "
2141 << this->nspace_uc
<< "IS_" << service_name_uc
<< "_PROCESSOR_CLASS(c) "
2142 << "(G_TYPE_CHECK_CLASS_TYPE ((c), " << this->nspace_uc
<< "TYPE_" << service_name_uc
2143 << "_PROCESSOR))" << endl
<< "#define " << this->nspace_uc
<< service_name_uc
2144 << "_PROCESSOR_GET_CLASS(obj) "
2145 << "(G_TYPE_INSTANCE_GET_CLASS ((obj), " << this->nspace_uc
<< "TYPE_"
2146 << service_name_uc
<< "_PROCESSOR, " << class_name
<< "Class))" << endl
<< endl
;
2148 // Generate the processor's implementation in the implementation file
2150 // Generate the processor's properties enum
2151 f_service_
<< "enum _" << class_name
<< "Properties" << endl
<< "{" << endl
;
2153 f_service_
<< indent() << "PROP_" << class_name_uc
<< "_0," << endl
<< indent() << "PROP_"
2154 << class_name_uc
<< "_HANDLER" << endl
;
2156 f_service_
<< "};" << endl
<< endl
;
2158 // Generate the implementation boilerplate
2159 args_indent
= string(15, ' ');
2160 f_service_
<< "G_DEFINE_TYPE (" << class_name
<< "," << endl
<< args_indent
<< class_name_lc
2161 << "," << endl
<< args_indent
<< parent_type_name
<< ")" << endl
<< endl
;
2163 // Generate the processor's processing-function type
2164 args_indent
= string(process_function_type_name
.length() + 23, ' ');
2165 f_service_
<< "typedef gboolean (* " << process_function_type_name
<< ") ("
2166 << class_name
<< " *, " << endl
2167 << args_indent
<< "gint32," << endl
2168 << args_indent
<< "ThriftProtocol *," << endl
2169 << args_indent
<< "ThriftProtocol *," << endl
2170 << args_indent
<< "GError **);" << endl
2173 // Generate the processor's processing-function-definition type
2174 f_service_
<< "typedef struct" << endl
2177 f_service_
<< indent() << "gchar *name;" << endl
2178 << indent() << process_function_type_name
<< " function;" << endl
;
2180 f_service_
<< "} " << process_function_def_type_name
<< ";" << endl
2183 // Generate forward declarations of the processor's processing functions so we
2184 // can refer to them in the processing-function-definition struct below and
2185 // keep all of the processor's declarations in one place
2186 for (function_iter
= functions
.begin();
2187 function_iter
!= functions
.end();
2189 function_name
= class_name_lc
+ "_process_"
2190 + initial_caps_to_underscores((*function_iter
)->get_name());
2192 args_indent
= string(function_name
.length() + 2, ' ');
2193 f_service_
<< "static gboolean" << endl
2194 << function_name
<< " ("
2195 << class_name
<< " *," << endl
2196 << args_indent
<< "gint32," << endl
2197 << args_indent
<< "ThriftProtocol *," << endl
2198 << args_indent
<< "ThriftProtocol *," << endl
2199 << args_indent
<< "GError **);" << endl
;
2203 // Generate the processor's processing-function definitions, if the service
2204 // defines any methods
2205 if (functions
.size() > 0) {
2206 f_service_
<< indent() << "static " << process_function_def_type_name
2208 << indent() << class_name_lc
<< "_process_function_defs["
2209 << functions
.size() << "] = {" << endl
;
2211 for (function_iter
= functions
.begin();
2212 function_iter
!= functions
.end();
2214 string service_function_name
= (*function_iter
)->get_name();
2215 string process_function_name
= class_name_lc
+ "_process_"
2216 + initial_caps_to_underscores(service_function_name
);
2218 f_service_
<< indent() << "{" << endl
;
2220 f_service_
<< indent() << "\"" << service_function_name
<< "\"," << endl
2221 << indent() << process_function_name
<< endl
;
2223 f_service_
<< indent() << "}"
2224 << (function_iter
== --functions
.end() ? "" : ",") << endl
;
2227 f_service_
<< indent() << "};" << endl
2231 // Generate the processor's processing functions
2232 for (function_iter
= functions
.begin(); function_iter
!= functions
.end(); ++function_iter
) {
2233 string service_function_name
= (*function_iter
)->get_name();
2234 string service_function_name_ic
= underscores_to_initial_caps(service_function_name
);
2235 string service_function_name_lc
= initial_caps_to_underscores(service_function_name
);
2236 string service_function_name_uc
= to_upper_case(service_function_name_lc
);
2238 t_type
* return_type
= (*function_iter
)->get_returntype();
2239 bool has_return_value
= !return_type
->is_void();
2241 t_struct
* arg_list
= (*function_iter
)->get_arglist();
2242 const vector
<t_field
*>& args
= arg_list
->get_members();
2243 vector
<t_field
*>::const_iterator arg_iter
;
2245 const vector
<t_field
*>& xceptions
= (*function_iter
)->get_xceptions()->get_members();
2246 vector
<t_field
*>::const_iterator xception_iter
;
2248 string args_class_name
= this->nspace
+ service_name_
+ service_function_name_ic
+ "Args";
2249 string args_class_type
= this->nspace_uc
+ "TYPE_" + service_name_uc
+ "_"
2250 + service_function_name_uc
+ "_ARGS";
2252 string result_class_name
= this->nspace
+ service_name_
+ service_function_name_ic
+ "Result";
2253 string result_class_type
= this->nspace_uc
+ "TYPE_" + service_name_uc
+ "_"
2254 + service_function_name_uc
+ "_RESULT";
2256 string handler_function_name
= handler_class_name_lc
+ "_" + service_function_name_lc
;
2258 function_name
= class_name_lc
+ "_process_"
2259 + initial_caps_to_underscores(service_function_name
);
2261 args_indent
= string(function_name
.length() + 2, ' ');
2262 f_service_
<< "static gboolean" << endl
<< function_name
<< " (" << class_name
<< " *self,"
2263 << endl
<< args_indent
<< "gint32 sequence_id," << endl
<< args_indent
2264 << "ThriftProtocol *input_protocol," << endl
<< args_indent
2265 << "ThriftProtocol *output_protocol," << endl
<< args_indent
<< "GError **error)"
2267 scope_up(f_service_
);
2268 f_service_
<< indent() << "gboolean result = TRUE;" << endl
2269 << indent() << "ThriftTransport * transport;" << endl
2270 << indent() << "ThriftApplicationException *xception;" << endl
2271 << indent() << args_class_name
+ " * args =" << endl
;
2273 f_service_
<< indent() << "g_object_new (" << args_class_type
<< ", NULL);" << endl
<< endl
;
2275 if ((*function_iter
)->is_oneway()) {
2276 f_service_
<< indent() << "THRIFT_UNUSED_VAR (sequence_id);" << endl
<< indent()
2277 << "THRIFT_UNUSED_VAR (output_protocol);" << endl
<< endl
;
2279 f_service_
<< indent() << "g_object_get (input_protocol, \"transport\", "
2280 << "&transport, NULL);" << endl
<< endl
;
2282 // Read the method's arguments from the caller
2283 f_service_
<< indent() << "if ((thrift_struct_read (THRIFT_STRUCT (args), "
2284 << "input_protocol, error) != -1) &&" << endl
<< indent()
2285 << " (thrift_protocol_read_message_end (input_protocol, "
2286 << "error) != -1) &&" << endl
<< indent()
2287 << " (thrift_transport_read_end (transport, error) != FALSE))" << endl
;
2288 scope_up(f_service_
);
2290 for (arg_iter
= args
.begin(); arg_iter
!= args
.end(); ++arg_iter
) {
2291 f_service_
<< indent() << property_type_name((*arg_iter
)->get_type()) << " "
2292 << (*arg_iter
)->get_name() << ";" << endl
;
2294 for (xception_iter
= xceptions
.begin(); xception_iter
!= xceptions
.end(); ++xception_iter
) {
2295 f_service_
<< indent() << type_name((*xception_iter
)->get_type()) << " "
2296 << initial_caps_to_underscores((*xception_iter
)->get_name()) << " = NULL;" << endl
;
2298 if (has_return_value
) {
2299 f_service_
<< indent() << property_type_name(return_type
) << " return_value;" << endl
;
2301 if (!(*function_iter
)->is_oneway()) {
2302 f_service_
<< indent() << result_class_name
<< " * result_struct;" << endl
;
2306 if (args
.size() > 0) {
2307 f_service_
<< indent() << "g_object_get (args," << endl
;
2308 args_indent
= indent() + string(14, ' ');
2309 for (arg_iter
= args
.begin(); arg_iter
!= args
.end(); ++arg_iter
) {
2310 string arg_name
= (*arg_iter
)->get_name();
2312 f_service_
<< args_indent
<< "\"" << arg_name
<< "\", &" << arg_name
<< "," << endl
;
2314 f_service_
<< args_indent
<< "NULL);" << endl
<< endl
;
2317 if (!(*function_iter
)->is_oneway()) {
2318 f_service_
<< indent() << "g_object_unref (transport);" << endl
<< indent()
2319 << "g_object_get (output_protocol, \"transport\", "
2320 << "&transport, NULL);" << endl
<< endl
<< indent()
2321 << "result_struct = g_object_new (" << result_class_type
<< ", NULL);" << endl
;
2322 if (has_return_value
) {
2323 f_service_
<< indent() << "g_object_get (result_struct, "
2324 "\"success\", &return_value, NULL);" << endl
;
2329 // Pass the arguments to the corresponding method in the handler
2330 f_service_
<< indent() << "if (" << handler_function_name
<< " (" << this->nspace_uc
2331 << service_name_uc
<< "_IF (self->handler)," << endl
;
2332 args_indent
= indent() + string(handler_function_name
.length() + 6, ' ');
2333 if (has_return_value
) {
2334 string return_type_name
= type_name(return_type
);
2336 f_service_
<< args_indent
;
2338 // Cast return_value if it was declared as a type other than the return
2339 // value's actual type---this is true for integer values 32 bits or fewer
2340 // in width, for which GLib requires a plain gint type be used when
2341 // storing or retrieving as an object property
2342 if (return_type_name
!= property_type_name(return_type
)) {
2343 if (return_type_name
[return_type_name
.length() - 1] != '*') {
2344 return_type_name
+= ' ';
2346 return_type_name
+= '*';
2348 f_service_
<< "(" << return_type_name
<< ")";
2351 f_service_
<< "&return_value," << endl
;
2353 for (arg_iter
= args
.begin(); arg_iter
!= args
.end(); ++arg_iter
) {
2354 f_service_
<< args_indent
<< (*arg_iter
)->get_name() << "," << endl
;
2356 for (xception_iter
= xceptions
.begin(); xception_iter
!= xceptions
.end(); ++xception_iter
) {
2357 f_service_
<< args_indent
<< "&" << initial_caps_to_underscores((*xception_iter
)->get_name())
2360 f_service_
<< args_indent
<< "error) == TRUE)" << endl
;
2361 scope_up(f_service_
);
2363 // The handler reported success; return the result, if any, to the caller
2364 if (!(*function_iter
)->is_oneway()) {
2365 if (has_return_value
) {
2366 f_service_
<< indent() << "g_object_set (result_struct, \"success\", ";
2367 if (type_name(return_type
) != property_type_name(return_type
)) {
2368 // Roundtrip cast to fix the position of sign bit.
2369 f_service_
<< "(" << property_type_name(return_type
) << ")"
2370 << "(" << type_name(return_type
) << ")";
2372 f_service_
<< "return_value, "
2373 << "NULL);" << endl
;
2375 // Deallocate (or unref) return_value
2376 return_type
= get_true_type(return_type
);
2377 if (return_type
->is_base_type()) {
2378 t_base_type
* base_type
= ((t_base_type
*)return_type
);
2380 if (base_type
->get_base() == t_base_type::TYPE_STRING
) {
2381 f_service_
<< indent() << "if (return_value != NULL)" << endl
;
2383 if (base_type
->is_binary()) {
2384 f_service_
<< indent() << "g_byte_array_unref (return_value);" << endl
;
2386 f_service_
<< indent() << "g_free (return_value);" << endl
;
2390 } else if (return_type
->is_container()) {
2391 f_service_
<< indent() << "if (return_value != NULL)" << endl
;
2394 if (return_type
->is_list()) {
2395 t_type
* elem_type
= ((t_list
*)return_type
)->get_elem_type();
2397 f_service_
<< indent();
2398 if (is_numeric(elem_type
)) {
2399 f_service_
<< "g_array_unref";
2401 f_service_
<< "g_ptr_array_unref";
2403 f_service_
<< " (return_value);" << endl
;
2404 } else if (return_type
->is_map() || return_type
->is_set()) {
2405 f_service_
<< indent() << "g_hash_table_unref (return_value);" << endl
;
2409 } else if (return_type
->is_struct()) {
2410 f_service_
<< indent() << "if (return_value != NULL)" << endl
;
2412 f_service_
<< indent() << "g_object_unref (return_value);" << endl
;
2418 f_service_
<< indent() << "result =" << endl
;
2420 f_service_
<< indent() << "((thrift_protocol_write_message_begin (output_protocol," << endl
;
2421 args_indent
= indent() + string(39, ' ');
2422 f_service_
<< args_indent
<< "\"" << service_function_name
<< "\"," << endl
<< args_indent
2423 << "T_REPLY," << endl
<< args_indent
<< "sequence_id," << endl
<< args_indent
2424 << "error) != -1) &&" << endl
<< indent()
2425 << " (thrift_struct_write (THRIFT_STRUCT (result_struct)," << endl
;
2426 args_indent
= indent() + string(23, ' ');
2427 f_service_
<< args_indent
<< "output_protocol," << endl
<< args_indent
<< "error) != -1));"
2431 scope_down(f_service_
);
2432 f_service_
<< indent() << "else" << endl
;
2433 scope_up(f_service_
);
2435 // The handler reported failure; check to see if an application-defined
2436 // exception was raised and if so, return it to the caller
2437 f_service_
<< indent();
2438 if (xceptions
.size() > 0) {
2439 for (xception_iter
= xceptions
.begin(); xception_iter
!= xceptions
.end(); ++xception_iter
) {
2440 f_service_
<< "if (" << initial_caps_to_underscores((*xception_iter
)->get_name())
2441 << " != NULL)" << endl
;
2442 scope_up(f_service_
);
2443 f_service_
<< indent() << "g_object_set (result_struct," << endl
;
2444 args_indent
= indent() + string(14, ' ');
2445 f_service_
<< args_indent
<< "\"" << (*xception_iter
)->get_name() << "\", "
2446 << (*xception_iter
)->get_name() << "," << endl
<< args_indent
<< "NULL);" << endl
2448 f_service_
<< indent() << "result =" << endl
;
2450 f_service_
<< indent() << "((thrift_protocol_write_message_begin (output_protocol," << endl
;
2451 args_indent
= indent() + string(39, ' ');
2452 f_service_
<< args_indent
<< "\"" << service_function_name
<< "\"," << endl
<< args_indent
2453 << "T_REPLY," << endl
<< args_indent
<< "sequence_id," << endl
<< args_indent
2454 << "error) != -1) &&" << endl
<< indent()
2455 << " (thrift_struct_write (THRIFT_STRUCT (result_struct)," << endl
;
2456 args_indent
= indent() + string(23, ' ');
2457 f_service_
<< args_indent
<< "output_protocol," << endl
<< args_indent
<< "error) != -1));"
2460 scope_down(f_service_
);
2461 f_service_
<< indent() << "else" << endl
;
2464 scope_up(f_service_
);
2465 f_service_
<< indent();
2468 // If the handler reported failure but raised no application-defined
2469 // exception, return a Thrift application exception with the information
2470 // returned via GLib's own error-reporting mechanism
2471 f_service_
<< "if (*error == NULL)" << endl
;
2473 f_service_
<< indent() << "g_warning (\"" << service_name_
<< "."
2474 << (*function_iter
)->get_name() << " implementation returned FALSE \"" << endl
2475 << indent() << string(11, ' ') << "\"but did not set an error\");" << endl
<< endl
;
2477 f_service_
<< indent() << "xception =" << endl
;
2479 f_service_
<< indent() << "g_object_new (THRIFT_TYPE_APPLICATION_EXCEPTION," << endl
;
2480 args_indent
= indent() + string(14, ' ');
2481 f_service_
<< args_indent
<< "\"type\", *error != NULL ? (*error)->code :" << endl
2482 << args_indent
<< string(11, ' ') << "THRIFT_APPLICATION_EXCEPTION_ERROR_UNKNOWN,"
2483 << endl
<< args_indent
<< "\"message\", *error != NULL ? (*error)->message : NULL,"
2484 << endl
<< args_indent
<< "NULL);" << endl
;
2486 f_service_
<< indent() << "g_clear_error (error);" << endl
<< endl
<< indent()
2487 << "result =" << endl
;
2489 f_service_
<< indent() << "((thrift_protocol_write_message_begin (output_protocol," << endl
;
2490 args_indent
= indent() + string(39, ' ');
2491 f_service_
<< args_indent
<< "\"" << service_function_name
<< "\"," << endl
<< args_indent
2492 << "T_EXCEPTION," << endl
<< args_indent
<< "sequence_id," << endl
<< args_indent
2493 << "error) != -1) &&" << endl
<< indent()
2494 << " (thrift_struct_write (THRIFT_STRUCT (xception)," << endl
;
2495 args_indent
= indent() + string(23, ' ');
2496 f_service_
<< args_indent
<< "output_protocol," << endl
<< args_indent
<< "error) != -1));"
2499 f_service_
<< endl
<< indent() << "g_object_unref (xception);" << endl
;
2501 if (xceptions
.size() > 0) {
2502 scope_down(f_service_
);
2504 scope_down(f_service_
);
2507 // Dellocate or unref retrieved argument values as necessary
2508 for (arg_iter
= args
.begin(); arg_iter
!= args
.end(); ++arg_iter
) {
2509 string arg_name
= (*arg_iter
)->get_name();
2510 t_type
* arg_type
= get_true_type((*arg_iter
)->get_type());
2512 if (arg_type
->is_base_type()) {
2513 t_base_type
* base_type
= ((t_base_type
*)arg_type
);
2515 if (base_type
->get_base() == t_base_type::TYPE_STRING
) {
2516 f_service_
<< indent() << "if (" << arg_name
<< " != NULL)" << endl
;
2518 if (base_type
->is_binary()) {
2519 f_service_
<< indent() << "g_byte_array_unref (" << arg_name
<< ");" << endl
;
2521 f_service_
<< indent() << "g_free (" << arg_name
<< ");" << endl
;
2525 } else if (arg_type
->is_container()) {
2526 f_service_
<< indent() << "if (" << arg_name
<< " != NULL)" << endl
;
2529 if (arg_type
->is_list()) {
2530 t_type
* elem_type
= ((t_list
*)arg_type
)->get_elem_type();
2532 f_service_
<< indent();
2533 if (is_numeric(elem_type
)) {
2534 f_service_
<< "g_array_unref";
2536 f_service_
<< "g_ptr_array_unref";
2538 f_service_
<< " (" << arg_name
<< ");" << endl
;
2539 } else if (arg_type
->is_map() || arg_type
->is_set()) {
2540 f_service_
<< indent() << "g_hash_table_unref (" << arg_name
<< ");" << endl
;
2544 } else if (arg_type
->is_struct()) {
2545 f_service_
<< indent() << "if (" << arg_name
<< " != NULL)" << endl
;
2547 f_service_
<< indent() << "g_object_unref (" << arg_name
<< ");" << endl
;
2552 if (!(*function_iter
)->is_oneway()) {
2553 f_service_
<< indent() << "g_object_unref (result_struct);" << endl
<< endl
<< indent()
2554 << "if (result == TRUE)" << endl
;
2556 f_service_
<< indent() << "result =" << endl
;
2558 f_service_
<< indent() << "((thrift_protocol_write_message_end "
2559 << "(output_protocol, error) != -1) &&" << endl
<< indent()
2560 << " (thrift_transport_write_end (transport, error) "
2561 << "!= FALSE) &&" << endl
<< indent()
2562 << " (thrift_transport_flush (transport, error) "
2563 << "!= FALSE));" << endl
;
2567 scope_down(f_service_
);
2568 f_service_
<< indent() << "else" << endl
;
2570 f_service_
<< indent() << "result = FALSE;" << endl
;
2573 f_service_
<< endl
<< indent() << "g_object_unref (transport);" << endl
<< indent()
2574 << "g_object_unref (args);" << endl
<< endl
<< indent() << "return result;" << endl
;
2575 scope_down(f_service_
);
2580 // Generate the processor's dispatch_call implementation
2581 function_name
= class_name_lc
+ "_dispatch_call";
2582 args_indent
= indent() + string(function_name
.length() + 2, ' ');
2583 f_service_
<< "static gboolean" << endl
<< function_name
2584 << " (ThriftDispatchProcessor *dispatch_processor," << endl
<< args_indent
2585 << "ThriftProtocol *input_protocol," << endl
<< args_indent
2586 << "ThriftProtocol *output_protocol," << endl
<< args_indent
<< "gchar *method_name,"
2587 << endl
<< args_indent
<< "gint32 sequence_id," << endl
<< args_indent
2588 << "GError **error)" << endl
;
2589 scope_up(f_service_
);
2590 f_service_
<< indent() << class_name_lc
<< "_process_function_def *"
2591 << "process_function_def;" << endl
;
2592 f_service_
<< indent() << "gboolean dispatch_result = FALSE;" << endl
<< endl
<< indent()
2593 << class_name
<< " *self = " << class_name_uc
<< " (dispatch_processor);" << endl
;
2594 f_service_
<< indent() << parent_class_name
<< "Class "
2595 "*parent_class =" << endl
;
2597 f_service_
<< indent() << "g_type_class_peek_parent (" << class_name_uc
<< "_GET_CLASS (self));"
2601 << indent() << "process_function_def = "
2602 << "g_hash_table_lookup (self->process_map, method_name);" << endl
2603 << indent() << "if (process_function_def != NULL)" << endl
;
2604 scope_up(f_service_
);
2605 args_indent
= indent() + string(53, ' ');
2606 f_service_
<< indent() << "g_free (method_name);" << endl
2607 << indent() << "dispatch_result = "
2608 << "(*process_function_def->function) (self," << endl
2609 << args_indent
<< "sequence_id," << endl
2610 << args_indent
<< "input_protocol," << endl
2611 << args_indent
<< "output_protocol," << endl
2612 << args_indent
<< "error);" << endl
;
2613 scope_down(f_service_
);
2614 f_service_
<< indent() << "else" << endl
;
2615 scope_up(f_service_
);
2617 // Method name not recognized; chain up to our parent processor---note the
2618 // top-most implementation of this method, in ThriftDispatchProcessor itself,
2619 // will return an application exception to the caller if no class in the
2620 // hierarchy recognizes the method name
2621 f_service_
<< indent() << "dispatch_result = parent_class->dispatch_call "
2622 "(dispatch_processor," << endl
;
2623 args_indent
= indent() + string(47, ' ');
2624 f_service_
<< args_indent
<< "input_protocol," << endl
<< args_indent
<< "output_protocol,"
2625 << endl
<< args_indent
<< "method_name," << endl
<< args_indent
<< "sequence_id,"
2626 << endl
<< args_indent
<< "error);" << endl
;
2627 scope_down(f_service_
);
2628 f_service_
<< endl
<< indent() << "return dispatch_result;" << endl
;
2629 scope_down(f_service_
);
2632 // Generate the processor's property setter
2633 function_name
= class_name_lc
+ "_set_property";
2634 args_indent
= string(function_name
.length() + 2, ' ');
2635 f_service_
<< "static void" << endl
<< function_name
<< " (GObject *object," << endl
2636 << args_indent
<< "guint property_id," << endl
<< args_indent
<< "const GValue *value,"
2637 << endl
<< args_indent
<< "GParamSpec *pspec)" << endl
;
2638 scope_up(f_service_
);
2639 f_service_
<< indent() << class_name
<< " *self = " << class_name_uc
<< " (object);" << endl
2640 << endl
<< indent() << "switch (property_id)" << endl
;
2641 scope_up(f_service_
);
2642 f_service_
<< indent() << "case PROP_" << class_name_uc
<< "_HANDLER:" << endl
;
2644 f_service_
<< indent() << "if (self->handler != NULL)" << endl
;
2646 f_service_
<< indent() << "g_object_unref (self->handler);" << endl
;
2648 f_service_
<< indent() << "self->handler = g_value_get_object (value);" << endl
<< indent()
2649 << "g_object_ref (self->handler);" << endl
;
2650 if (extends_service
) {
2651 // Chain up to set the handler in every superclass as well
2652 f_service_
<< endl
<< indent() << "G_OBJECT_CLASS (" << class_name_lc
<< "_parent_class)->"
2655 f_service_
<< indent() << "set_property (object, property_id, value, pspec);" << endl
;
2658 f_service_
<< indent() << "break;" << endl
;
2660 f_service_
<< indent() << "default:" << endl
;
2662 f_service_
<< indent() << "G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);"
2663 << endl
<< indent() << "break;" << endl
;
2665 scope_down(f_service_
);
2666 scope_down(f_service_
);
2669 // Generate processor's property getter
2670 function_name
= class_name_lc
+ "_get_property";
2671 args_indent
= string(function_name
.length() + 2, ' ');
2672 f_service_
<< "static void" << endl
<< function_name
<< " (GObject *object," << endl
2673 << args_indent
<< "guint property_id," << endl
<< args_indent
<< "GValue *value,"
2674 << endl
<< args_indent
<< "GParamSpec *pspec)" << endl
;
2675 scope_up(f_service_
);
2676 f_service_
<< indent() << class_name
<< " *self = " << class_name_uc
<< " (object);" << endl
2677 << endl
<< indent() << "switch (property_id)" << endl
;
2678 scope_up(f_service_
);
2679 f_service_
<< indent() << "case PROP_" << class_name_uc
<< "_HANDLER:" << endl
;
2681 f_service_
<< indent() << "g_value_set_object (value, self->handler);" << endl
<< indent()
2682 << "break;" << endl
;
2684 f_service_
<< indent() << "default:" << endl
;
2686 f_service_
<< indent() << "G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);"
2687 << endl
<< indent() << "break;" << endl
;
2689 scope_down(f_service_
);
2690 scope_down(f_service_
);
2693 // Generator the processor's dispose function
2694 f_service_
<< "static void" << endl
<< class_name_lc
<< "_dispose (GObject *gobject)" << endl
;
2695 scope_up(f_service_
);
2696 f_service_
<< indent() << class_name
<< " *self = " << class_name_uc
<< " (gobject);" << endl
2697 << endl
<< indent() << "if (self->handler != NULL)" << endl
;
2698 scope_up(f_service_
);
2699 f_service_
<< indent() << "g_object_unref (self->handler);" << endl
<< indent()
2700 << "self->handler = NULL;" << endl
;
2701 scope_down(f_service_
);
2702 f_service_
<< endl
<< indent() << "G_OBJECT_CLASS (" << class_name_lc
<< "_parent_class)"
2703 "->dispose (gobject);"
2705 scope_down(f_service_
);
2708 // Generate processor finalize function
2709 f_service_
<< "static void" << endl
<< class_name_lc
<< "_finalize (GObject *gobject)" << endl
;
2710 scope_up(f_service_
);
2711 f_service_
<< indent() << this->nspace
<< service_name_
<< "Processor *self = " << this->nspace_uc
2712 << service_name_uc
<< "_PROCESSOR (gobject);" << endl
<< endl
<< indent()
2713 << "thrift_safe_hash_table_destroy (self->process_map);" << endl
<< endl
<< indent()
2714 << "G_OBJECT_CLASS (" << class_name_lc
<< "_parent_class)"
2715 "->finalize (gobject);" << endl
;
2716 scope_down(f_service_
);
2719 // Generate processor instance initializer
2720 f_service_
<< "static void" << endl
<< class_name_lc
<< "_init (" << class_name
<< " *self)"
2722 scope_up(f_service_
);
2723 if (functions
.size() > 0) {
2724 f_service_
<< indent() << "guint index;" << endl
2727 f_service_
<< indent() << "self->handler = NULL;" << endl
<< indent()
2728 << "self->process_map = "
2729 "g_hash_table_new (g_str_hash, g_str_equal);" << endl
;
2730 if (functions
.size() > 0) {
2731 args_indent
= string(21, ' ');
2733 << indent() << "for (index = 0; index < "
2734 << functions
.size() << "; index += 1)" << endl
;
2736 f_service_
<< indent() << "g_hash_table_insert (self->process_map," << endl
2737 << indent() << args_indent
2738 << class_name_lc
<< "_process_function_defs[index].name," << endl
2739 << indent() << args_indent
2740 << "&" << class_name_lc
<< "_process_function_defs[index]" << ");"
2744 scope_down(f_service_
);
2747 // Generate processor class initializer
2748 f_service_
<< "static void" << endl
<< class_name_lc
<< "_class_init (" << class_name
2749 << "Class *cls)" << endl
;
2750 scope_up(f_service_
);
2751 f_service_
<< indent() << "GObjectClass *gobject_class = G_OBJECT_CLASS (cls);" << endl
2752 << indent() << "ThriftDispatchProcessorClass *dispatch_processor_class =" << endl
;
2754 f_service_
<< indent() << "THRIFT_DISPATCH_PROCESSOR_CLASS (cls);" << endl
;
2756 f_service_
<< indent() << "GParamSpec *param_spec;" << endl
<< endl
<< indent()
2757 << "gobject_class->dispose = " << class_name_lc
<< "_dispose;" << endl
<< indent()
2758 << "gobject_class->finalize = " << class_name_lc
<< "_finalize;" << endl
<< indent()
2759 << "gobject_class->set_property = " << class_name_lc
<< "_set_property;" << endl
2760 << indent() << "gobject_class->get_property = " << class_name_lc
<< "_get_property;"
2761 << endl
<< endl
<< indent()
2762 << "dispatch_processor_class->dispatch_call = " << class_name_lc
<< "_dispatch_call;"
2763 << endl
<< indent() << "cls->dispatch_call = " << class_name_lc
<< "_dispatch_call;"
2764 << endl
<< endl
<< indent() << "param_spec = g_param_spec_object (\"handler\","
2766 args_indent
= indent() + string(34, ' ');
2767 f_service_
<< args_indent
<< "\"Service handler implementation\"," << endl
<< args_indent
2768 << "\"The service handler implementation \"" << endl
<< args_indent
2769 << "\"to which method calls are dispatched.\"," << endl
<< args_indent
2770 << this->nspace_uc
+ "TYPE_" + service_name_uc
+ "_HANDLER," << endl
<< args_indent
2771 << "G_PARAM_READWRITE);" << endl
;
2772 f_service_
<< indent() << "g_object_class_install_property (gobject_class," << endl
;
2773 args_indent
= indent() + string(33, ' ');
2774 f_service_
<< args_indent
<< "PROP_" << class_name_uc
<< "_HANDLER," << endl
<< args_indent
2775 << "param_spec);" << endl
;
2776 scope_down(f_service_
);
2780 * Generates C code that represents a Thrift service server.
2782 void t_c_glib_generator::generate_service_server(t_service
* tservice
) {
2784 // Generate the service's handler class
2785 generate_service_handler(tservice
);
2787 // Generate the service's processor class
2788 generate_service_processor(tservice
);
2792 * Generates C code to represent a THrift structure as a GObject.
2794 void t_c_glib_generator::generate_object(t_struct
* tstruct
) {
2795 string name
= tstruct
->get_name();
2796 string name_u
= initial_caps_to_underscores(name
);
2797 string name_uc
= to_upper_case(name_u
);
2799 string class_name
= this->nspace
+ name
;
2800 string class_name_lc
= this->nspace_lc
+ initial_caps_to_underscores(name
);
2801 string class_name_uc
= to_upper_case(class_name_lc
);
2803 string function_name
;
2806 // write the instance definition
2807 f_types_
<< "struct _" << this->nspace
<< name
<< endl
<< "{ " << endl
2808 << " ThriftStruct parent; " << endl
<< endl
<< " /* public */" << endl
;
2810 // for each field, add a member variable
2811 vector
<t_field
*>::const_iterator m_iter
;
2812 const vector
<t_field
*>& members
= tstruct
->get_members();
2813 for (m_iter
= members
.begin(); m_iter
!= members
.end(); ++m_iter
) {
2814 t_type
* t
= get_true_type((*m_iter
)->get_type());
2815 f_types_
<< " " << type_name(t
) << " " << (*m_iter
)->get_name() << ";" << endl
;
2816 if ((*m_iter
)->get_req() != t_field::T_REQUIRED
) {
2817 f_types_
<< " gboolean __isset_" << (*m_iter
)->get_name() << ";" << endl
;
2821 // close the structure definition and create a typedef
2822 f_types_
<< "};" << endl
<< "typedef struct _" << this->nspace
<< name
<< " " << this->nspace
2823 << name
<< ";" << endl
<< endl
;
2825 // write the class definition
2826 f_types_
<< "struct _" << this->nspace
<< name
<< "Class" << endl
<< "{" << endl
2827 << " ThriftStructClass parent;" << endl
<< "};" << endl
<< "typedef struct _"
2828 << this->nspace
<< name
<< "Class " << this->nspace
<< name
<< "Class;" << endl
<< endl
;
2830 // write the standard GObject boilerplate
2831 f_types_
<< "GType " << this->nspace_lc
<< name_u
<< "_get_type (void);" << endl
<< "#define "
2832 << this->nspace_uc
<< "TYPE_" << name_uc
<< " (" << this->nspace_lc
<< name_u
2833 << "_get_type())" << endl
<< "#define " << this->nspace_uc
<< name_uc
2834 << "(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), " << this->nspace_uc
<< "TYPE_" << name_uc
2835 << ", " << this->nspace
<< name
<< "))" << endl
<< "#define " << this->nspace_uc
2836 << name_uc
<< "_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), " << this->nspace_uc
<< "_TYPE_"
2837 << name_uc
<< ", " << this->nspace
<< name
<< "Class))" << endl
<< "#define "
2838 << this->nspace_uc
<< "IS_" << name_uc
<< "(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), "
2839 << this->nspace_uc
<< "TYPE_" << name_uc
<< "))" << endl
<< "#define " << this->nspace_uc
2840 << "IS_" << name_uc
<< "_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), " << this->nspace_uc
2841 << "TYPE_" << name_uc
<< "))" << endl
<< "#define " << this->nspace_uc
<< name_uc
2842 << "_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), " << this->nspace_uc
<< "TYPE_"
2843 << name_uc
<< ", " << this->nspace
<< name
<< "Class))" << endl
<< endl
;
2845 // start writing the object implementation .c file
2847 // generate properties enum
2848 if (members
.size() > 0) {
2849 f_types_impl_
<< "enum _" << class_name
<< "Properties" << endl
<< "{" << endl
;
2851 f_types_impl_
<< indent() << "PROP_" << class_name_uc
<< "_0";
2852 for (m_iter
= members
.begin(); m_iter
!= members
.end(); ++m_iter
) {
2853 string member_name_uc
2854 = to_upper_case(to_lower_case(initial_caps_to_underscores((*m_iter
)->get_name())));
2856 f_types_impl_
<< "," << endl
<< indent() << "PROP_" << class_name_uc
<< "_" << member_name_uc
;
2858 f_types_impl_
<< endl
;
2860 f_types_impl_
<< "};" << endl
<< endl
;
2863 // generate struct I/O methods
2864 string this_get
= this->nspace
+ name
+ " * this_object = " + this->nspace_uc
+ name_uc
2866 generate_struct_reader(f_types_impl_
, tstruct
, "this_object->", this_get
);
2867 generate_struct_writer(f_types_impl_
, tstruct
, "this_object->", this_get
);
2869 // generate property setter and getter
2870 if (members
.size() > 0) {
2871 // generate property setter
2872 function_name
= class_name_lc
+ "_set_property";
2873 args_indent
= string(function_name
.length() + 2, ' ');
2874 f_types_impl_
<< "static void" << endl
<< function_name
<< " (GObject *object," << endl
2875 << args_indent
<< "guint property_id," << endl
<< args_indent
2876 << "const GValue *value," << endl
<< args_indent
<< "GParamSpec *pspec)" << endl
;
2877 scope_up(f_types_impl_
);
2878 f_types_impl_
<< indent() << class_name
<< " *self = " << class_name_uc
<< " (object);" << endl
2879 << endl
<< indent() << "switch (property_id)" << endl
;
2880 scope_up(f_types_impl_
);
2881 for (m_iter
= members
.begin(); m_iter
!= members
.end(); ++m_iter
) {
2882 t_field
* member
= (*m_iter
);
2883 string member_name
= member
->get_name();
2884 string member_name_uc
2885 = to_upper_case(to_lower_case(initial_caps_to_underscores(member_name
)));
2886 t_type
* member_type
= get_true_type(member
->get_type());
2888 string property_identifier
= "PROP_" + class_name_uc
+ "_" + member_name_uc
;
2890 f_types_impl_
<< indent() << "case " << property_identifier
+ ":" << endl
;
2893 if (member_type
->is_base_type()) {
2894 t_base_type
* base_type
= ((t_base_type
*)member_type
);
2895 string assign_function_name
;
2897 if (base_type
->get_base() == t_base_type::TYPE_STRING
) {
2898 string release_function_name
;
2900 f_types_impl_
<< indent() << "if (self->" << member_name
<< " != NULL)" << endl
;
2903 if (base_type
->is_binary()) {
2904 release_function_name
= "g_byte_array_unref";
2905 assign_function_name
= "g_value_dup_boxed";
2907 release_function_name
= "g_free";
2908 assign_function_name
= "g_value_dup_string";
2911 f_types_impl_
<< indent() << release_function_name
<< " (self->" << member_name
<< ");"
2915 switch (base_type
->get_base()) {
2916 case t_base_type::TYPE_BOOL
:
2917 assign_function_name
= "g_value_get_boolean";
2920 case t_base_type::TYPE_I8
:
2921 case t_base_type::TYPE_I16
:
2922 case t_base_type::TYPE_I32
:
2923 assign_function_name
= "g_value_get_int";
2926 case t_base_type::TYPE_I64
:
2927 assign_function_name
= "g_value_get_int64";
2930 case t_base_type::TYPE_DOUBLE
:
2931 assign_function_name
= "g_value_get_double";
2935 throw "compiler error: "
2936 "unrecognized base type \"" + base_type
->get_name() + "\" "
2937 "for struct member \""
2938 + member_name
+ "\"";
2943 f_types_impl_
<< indent() << "self->" << member_name
<< " = " << assign_function_name
2944 << " (value);" << endl
;
2945 } else if (member_type
->is_enum()) {
2946 f_types_impl_
<< indent() << "self->" << member_name
<< " = g_value_get_int (value);"
2948 } else if (member_type
->is_container()) {
2949 string release_function_name
;
2950 string assign_function_name
;
2952 if (member_type
->is_list()) {
2953 t_type
* elem_type
= ((t_list
*)member_type
)->get_elem_type();
2955 // Lists of base types other than strings are represented as GArrays;
2956 // all others as GPtrArrays
2957 if (is_numeric(elem_type
)) {
2958 release_function_name
= "g_array_unref";
2960 release_function_name
= "g_ptr_array_unref";
2963 assign_function_name
= "g_value_dup_boxed";
2964 } else if (member_type
->is_set() || member_type
->is_map()) {
2965 release_function_name
= "g_hash_table_unref";
2966 assign_function_name
= "g_value_dup_boxed";
2969 f_types_impl_
<< indent() << "if (self->" << member_name
<< " != NULL)" << endl
;
2971 f_types_impl_
<< indent() << release_function_name
<< " (self->" << member_name
<< ");"
2974 f_types_impl_
<< indent() << "self->" << member_name
<< " = " << assign_function_name
2975 << " (value);" << endl
;
2976 } else if (member_type
->is_struct() || member_type
->is_xception()) {
2977 f_types_impl_
<< indent() << "if (self->" << member_name
<< " != NULL)" << endl
;
2979 f_types_impl_
<< indent() << "g_object_unref (self->" << member_name
<< ");" << endl
;
2981 f_types_impl_
<< indent() << "self->" << member_name
<< " = g_value_dup_object (value);"
2985 if (member
->get_req() != t_field::T_REQUIRED
) {
2986 f_types_impl_
<< indent() << "self->__isset_" << member_name
<< " = TRUE;" << endl
;
2989 f_types_impl_
<< indent() << "break;" << endl
<< endl
;
2992 f_types_impl_
<< indent() << "default:" << endl
;
2994 f_types_impl_
<< indent() << "G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);"
2995 << endl
<< indent() << "break;" << endl
;
2997 scope_down(f_types_impl_
);
2998 scope_down(f_types_impl_
);
2999 f_types_impl_
<< endl
;
3001 // generate property getter
3002 function_name
= class_name_lc
+ "_get_property";
3003 args_indent
= string(function_name
.length() + 2, ' ');
3004 f_types_impl_
<< "static void" << endl
<< function_name
<< " (GObject *object," << endl
3005 << args_indent
<< "guint property_id," << endl
<< args_indent
<< "GValue *value,"
3006 << endl
<< args_indent
<< "GParamSpec *pspec)" << endl
;
3007 scope_up(f_types_impl_
);
3008 f_types_impl_
<< indent() << class_name
<< " *self = " << class_name_uc
<< " (object);" << endl
3009 << endl
<< indent() << "switch (property_id)" << endl
;
3010 scope_up(f_types_impl_
);
3011 for (m_iter
= members
.begin(); m_iter
!= members
.end(); ++m_iter
) {
3012 t_field
* member
= (*m_iter
);
3013 string member_name
= (*m_iter
)->get_name();
3014 string member_name_uc
3015 = to_upper_case(to_lower_case(initial_caps_to_underscores(member_name
)));
3016 t_type
* member_type
= get_true_type(member
->get_type());
3018 string property_identifier
= "PROP_" + class_name_uc
+ "_" + member_name_uc
;
3020 string setter_function_name
;
3022 if (member_type
->is_base_type()) {
3023 t_base_type
* base_type
= ((t_base_type
*)member_type
);
3025 switch (base_type
->get_base()) {
3026 case t_base_type::TYPE_BOOL
:
3027 setter_function_name
= "g_value_set_boolean";
3030 case t_base_type::TYPE_I8
:
3031 case t_base_type::TYPE_I16
:
3032 case t_base_type::TYPE_I32
:
3033 setter_function_name
= "g_value_set_int";
3036 case t_base_type::TYPE_I64
:
3037 setter_function_name
= "g_value_set_int64";
3040 case t_base_type::TYPE_DOUBLE
:
3041 setter_function_name
= "g_value_set_double";
3044 case t_base_type::TYPE_STRING
:
3045 if (base_type
->is_binary()) {
3046 setter_function_name
= "g_value_set_boxed";
3048 setter_function_name
= "g_value_set_string";
3053 throw "compiler error: "
3054 "unrecognized base type \"" + base_type
->get_name() + "\" "
3055 "for struct member \""
3056 + member_name
+ "\"";
3059 } else if (member_type
->is_enum()) {
3060 setter_function_name
= "g_value_set_int";
3061 } else if (member_type
->is_struct() || member_type
->is_xception()) {
3062 setter_function_name
= "g_value_set_object";
3063 } else if (member_type
->is_container()) {
3064 setter_function_name
= "g_value_set_boxed";
3066 throw "compiler error: "
3067 "unrecognized type for struct member \"" + member_name
+ "\"";
3070 f_types_impl_
<< indent() << "case " << property_identifier
+ ":" << endl
;
3072 f_types_impl_
<< indent() << setter_function_name
<< " (value, self->" << member_name
<< ");"
3073 << endl
<< indent() << "break;" << endl
<< endl
;
3076 f_types_impl_
<< indent() << "default:" << endl
;
3078 f_types_impl_
<< indent() << "G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);"
3079 << endl
<< indent() << "break;" << endl
;
3081 scope_down(f_types_impl_
);
3082 scope_down(f_types_impl_
);
3083 f_types_impl_
<< endl
;
3086 // generate the instance init function
3088 f_types_impl_
<< "static void " << endl
<< this->nspace_lc
<< name_u
<< "_instance_init ("
3089 << this->nspace
<< name
<< " * object)" << endl
<< "{" << endl
;
3092 // generate default-value structures for container-type members
3093 bool constant_declaration_output
= false;
3094 bool string_list_constant_output
= false;
3095 for (m_iter
= members
.begin(); m_iter
!= members
.end(); ++m_iter
) {
3096 t_field
* member
= *m_iter
;
3097 t_const_value
* member_value
= member
->get_value();
3099 if (member_value
!= NULL
) {
3100 string member_name
= member
->get_name();
3101 t_type
* member_type
= get_true_type(member
->get_type());
3103 if (member_type
->is_list()) {
3104 const vector
<t_const_value
*>& list
= member_value
->get_list();
3105 t_type
* elem_type
= ((t_list
*)member_type
)->get_elem_type();
3107 // Generate an array with the list literal
3108 indent(f_types_impl_
) << "static " << type_name(elem_type
, false, true) << " __default_"
3109 << member_name
<< "[" << list
.size() << "] = " << endl
;
3111 f_types_impl_
<< indent() << constant_literal(member_type
, member_value
) << ";" << endl
;
3114 constant_declaration_output
= true;
3116 // If we are generating values for a pointer array (i.e. a list of
3117 // strings), set a flag so we know to also declare an index variable to
3118 // use in pre-populating the array
3119 if (elem_type
->is_string()) {
3120 string_list_constant_output
= true;
3124 // TODO: Handle container types other than list
3127 if (constant_declaration_output
) {
3128 if (string_list_constant_output
) {
3129 indent(f_types_impl_
) << "unsigned int list_index;" << endl
;
3132 f_types_impl_
<< endl
;
3135 // satisfy compilers with -Wall turned on
3136 indent(f_types_impl_
) << "/* satisfy -Wall */" << endl
<< indent()
3137 << "THRIFT_UNUSED_VAR (object);" << endl
;
3139 for (m_iter
= members
.begin(); m_iter
!= members
.end(); ++m_iter
) {
3140 t_type
* member_type
= (*m_iter
)->get_type();
3141 t_type
* t
= get_true_type(member_type
);
3142 if (t
->is_base_type()) {
3143 string dval
= " = ";
3145 dval
+= "(" + type_name(t
) + ")";
3147 t_const_value
* cv
= (*m_iter
)->get_value();
3149 dval
+= constant_value("", t
, cv
);
3151 dval
+= t
->is_string() ? "NULL" : "0";
3153 indent(f_types_impl_
) << "object->" << (*m_iter
)->get_name() << dval
<< ";" << endl
;
3154 } else if (t
->is_struct()) {
3155 string name
= (*m_iter
)->get_name();
3156 t_program
* type_program
= member_type
->get_program();
3157 string type_nspace
= type_program
? type_program
->get_namespace("c_glib") : "";
3158 string type_nspace_prefix
=
3159 type_nspace
.empty() ? "" : initial_caps_to_underscores(type_nspace
) + "_";
3160 string type_name_uc
= to_upper_case(initial_caps_to_underscores(member_type
->get_name()));
3161 indent(f_types_impl_
) << "object->" << name
<< " = g_object_new ("
3162 << to_upper_case(type_nspace_prefix
) << "TYPE_" << type_name_uc
3163 << ", NULL);" << endl
;
3164 } else if (t
->is_xception()) {
3165 string name
= (*m_iter
)->get_name();
3166 indent(f_types_impl_
) << "object->" << name
<< " = NULL;" << endl
;
3167 } else if (t
->is_container()) {
3168 string name
= (*m_iter
)->get_name();
3169 string init_function
;
3170 t_type
* etype
= NULL
;
3173 t_type
* key
= ((t_map
*)t
)->get_key_type();
3174 t_type
* value
= ((t_map
*)t
)->get_val_type();
3175 init_function
= generate_new_hash_from_type(key
, value
);
3176 } else if (t
->is_set()) {
3177 etype
= ((t_set
*)t
)->get_elem_type();
3178 init_function
= generate_new_hash_from_type(etype
, NULL
);
3179 } else if (t
->is_list()) {
3180 etype
= ((t_list
*)t
)->get_elem_type();
3181 init_function
= generate_new_array_from_type(etype
);
3184 indent(f_types_impl_
) << "object->" << name
<< " = " << init_function
<< endl
;
3186 // Pre-populate the container with the specified default values, if any
3187 if ((*m_iter
)->get_value()) {
3188 t_const_value
* member_value
= (*m_iter
)->get_value();
3191 const vector
<t_const_value
*>& list
= member_value
->get_list();
3193 if (is_numeric(etype
)) {
3194 indent(f_types_impl_
) <<
3195 "g_array_append_vals (object->" << name
<< ", &__default_" <<
3196 name
<< ", " << list
.size() << ");" << endl
;
3199 indent(f_types_impl_
) <<
3200 "for (list_index = 0; list_index < " << list
.size() << "; " <<
3201 "list_index += 1)" << endl
;
3203 indent(f_types_impl_
) <<
3204 "g_ptr_array_add (object->" << name
<< "," << endl
<<
3205 indent() << string(17, ' ') << "g_strdup (__default_" <<
3206 name
<< "[list_index]));" << endl
;
3211 // TODO: Handle container types other than list
3215 /* if not required, initialize the __isset variable */
3216 if ((*m_iter
)->get_req() != t_field::T_REQUIRED
) {
3217 indent(f_types_impl_
) << "object->__isset_" << (*m_iter
)->get_name() << " = FALSE;" << endl
;
3222 f_types_impl_
<< "}" << endl
<< endl
;
3224 /* create the destructor */
3225 f_types_impl_
<< "static void " << endl
<< this->nspace_lc
<< name_u
3226 << "_finalize (GObject *object)" << endl
<< "{" << endl
;
3229 f_types_impl_
<< indent() << this->nspace
<< name
<< " *tobject = " << this->nspace_uc
<< name_uc
3230 << " (object);" << endl
<< endl
;
3232 f_types_impl_
<< indent() << "/* satisfy -Wall in case we don't use tobject */" << endl
3233 << indent() << "THRIFT_UNUSED_VAR (tobject);" << endl
;
3235 for (m_iter
= members
.begin(); m_iter
!= members
.end(); ++m_iter
) {
3236 t_type
* t
= get_true_type((*m_iter
)->get_type());
3237 if (t
->is_container()) {
3238 string name
= (*m_iter
)->get_name();
3239 if (t
->is_map() || t
->is_set()) {
3240 f_types_impl_
<< indent() << "if (tobject->" << name
<< " != NULL)" << endl
;
3241 f_types_impl_
<< indent() << "{" << endl
;
3243 f_types_impl_
<< indent() << "g_hash_table_destroy (tobject->" << name
<< ");" << endl
;
3244 f_types_impl_
<< indent() << "tobject->" << name
<< " = NULL;" << endl
;
3246 f_types_impl_
<< indent() << "}" << endl
;
3247 } else if (t
->is_list()) {
3248 t_type
* etype
= ((t_list
*)t
)->get_elem_type();
3249 string destructor_function
= "g_ptr_array_unref";
3251 if (etype
->is_base_type()) {
3252 t_base_type::t_base tbase
= ((t_base_type
*)etype
)->get_base();
3254 case t_base_type::TYPE_VOID
:
3255 throw "compiler error: cannot determine array type";
3256 case t_base_type::TYPE_BOOL
:
3257 case t_base_type::TYPE_I8
:
3258 case t_base_type::TYPE_I16
:
3259 case t_base_type::TYPE_I32
:
3260 case t_base_type::TYPE_I64
:
3261 case t_base_type::TYPE_DOUBLE
:
3262 destructor_function
= "g_array_unref";
3264 case t_base_type::TYPE_STRING
:
3267 throw "compiler error: no array info for type";
3269 } else if (etype
->is_enum()) {
3270 destructor_function
= "g_array_unref";
3273 f_types_impl_
<< indent() << "if (tobject->" << name
<< " != NULL)" << endl
;
3274 f_types_impl_
<< indent() << "{" << endl
;
3276 f_types_impl_
<< indent() << destructor_function
<< " (tobject->" << name
<< ");" << endl
;
3277 f_types_impl_
<< indent() << "tobject->" << name
<< " = NULL;" << endl
;
3279 f_types_impl_
<< indent() << "}" << endl
;
3281 } else if (t
->is_struct() || t
->is_xception()) {
3282 string name
= (*m_iter
)->get_name();
3283 // TODO: g_clear_object needs glib >= 2.28
3284 // f_types_impl_ << indent() << "g_clear_object (&(tobject->" << name << "));" << endl;
3285 // does g_object_unref the trick?
3286 f_types_impl_
<< indent() << "if (tobject->" << name
<< " != NULL)" << endl
;
3287 f_types_impl_
<< indent() << "{" << endl
;
3289 f_types_impl_
<< indent() << "g_object_unref(tobject->" << name
<< ");" << endl
;
3290 f_types_impl_
<< indent() << "tobject->" << name
<< " = NULL;" << endl
;
3292 f_types_impl_
<< indent() << "}" << endl
;
3293 } else if (t
->is_string()) {
3294 string name
= (*m_iter
)->get_name();
3295 f_types_impl_
<< indent() << "if (tobject->" << name
<< " != NULL)" << endl
;
3296 f_types_impl_
<< indent() << "{" << endl
;
3298 f_types_impl_
<< indent() << generate_free_func_from_type(t
) << "(tobject->" << name
<< ");"
3300 f_types_impl_
<< indent() << "tobject->" << name
<< " = NULL;" << endl
;
3302 f_types_impl_
<< indent() << "}" << endl
;
3307 f_types_impl_
<< "}" << endl
<< endl
;
3309 // generate the class init function
3311 f_types_impl_
<< "static void" << endl
<< class_name_lc
<< "_class_init (" << class_name
3312 << "Class * cls)" << endl
;
3313 scope_up(f_types_impl_
);
3315 f_types_impl_
<< indent() << "GObjectClass *gobject_class = G_OBJECT_CLASS (cls);" << endl
3316 << indent() << "ThriftStructClass *struct_class = "
3317 << "THRIFT_STRUCT_CLASS (cls);" << endl
<< endl
<< indent()
3318 << "struct_class->read = " << class_name_lc
<< "_read;" << endl
<< indent()
3319 << "struct_class->write = " << class_name_lc
<< "_write;" << endl
<< endl
3320 << indent() << "gobject_class->finalize = " << class_name_lc
<< "_finalize;"
3322 if (members
.size() > 0) {
3323 f_types_impl_
<< indent() << "gobject_class->get_property = " << class_name_lc
3324 << "_get_property;" << endl
<< indent()
3325 << "gobject_class->set_property = " << class_name_lc
<< "_set_property;" << endl
;
3327 // install a property for each member
3328 for (m_iter
= members
.begin(); m_iter
!= members
.end(); ++m_iter
) {
3329 t_field
* member
= (*m_iter
);
3330 string member_name
= member
->get_name();
3331 string member_name_uc
3332 = to_upper_case(to_lower_case(initial_caps_to_underscores(member_name
)));
3333 t_type
* member_type
= get_true_type(member
->get_type());
3334 t_const_value
* member_value
= member
->get_value();
3336 string property_identifier
= "PROP_" + class_name_uc
+ "_" + member_name_uc
;
3338 f_types_impl_
<< endl
<< indent() << "g_object_class_install_property" << endl
;
3340 args_indent
= indent() + ' ';
3341 f_types_impl_
<< indent() << "(gobject_class," << endl
<< args_indent
<< property_identifier
3342 << "," << endl
<< args_indent
;
3344 if (member_type
->is_base_type()) {
3345 t_base_type::t_base base_type
= ((t_base_type
*)member_type
)->get_base();
3347 if (base_type
== t_base_type::TYPE_STRING
) {
3348 if (((t_base_type
*)member_type
)->is_binary()) {
3349 args_indent
+= string(20, ' ');
3350 f_types_impl_
<< "g_param_spec_boxed (\"" << member_name
<< "\"," << endl
<< args_indent
3351 << "NULL," << endl
<< args_indent
<< "NULL," << endl
<< args_indent
3352 << "G_TYPE_BYTE_ARRAY," << endl
<< args_indent
<< "G_PARAM_READWRITE));"
3355 args_indent
+= string(21, ' ');
3356 f_types_impl_
<< "g_param_spec_string (\"" << member_name
<< "\"," << endl
3357 << args_indent
<< "NULL," << endl
<< args_indent
<< "NULL," << endl
3359 << ((member_value
!= NULL
) ? "\"" + member_value
->get_string() + "\""
3360 : "NULL") << "," << endl
<< args_indent
3361 << "G_PARAM_READWRITE));" << endl
;
3363 } else if (base_type
== t_base_type::TYPE_BOOL
) {
3364 args_indent
+= string(22, ' ');
3365 f_types_impl_
<< "g_param_spec_boolean (\"" << member_name
<< "\"," << endl
<< args_indent
3366 << "NULL," << endl
<< args_indent
<< "NULL," << endl
<< args_indent
3367 << (((member_value
!= NULL
) && (member_value
->get_integer() != 0))
3369 : "FALSE") << "," << endl
<< args_indent
<< "G_PARAM_READWRITE));"
3371 } else if ((base_type
== t_base_type::TYPE_I8
) || (base_type
== t_base_type::TYPE_I16
)
3372 || (base_type
== t_base_type::TYPE_I32
) || (base_type
== t_base_type::TYPE_I64
)
3373 || (base_type
== t_base_type::TYPE_DOUBLE
)) {
3374 string param_spec_function_name
= "g_param_spec_int";
3377 ostringstream default_value
;
3379 switch (base_type
) {
3380 case t_base_type::TYPE_I8
:
3381 min_value
= "G_MININT8";
3382 max_value
= "G_MAXINT8";
3385 case t_base_type::TYPE_I16
:
3386 min_value
= "G_MININT16";
3387 max_value
= "G_MAXINT16";
3390 case t_base_type::TYPE_I32
:
3391 min_value
= "G_MININT32";
3392 max_value
= "G_MAXINT32";
3395 case t_base_type::TYPE_I64
:
3396 param_spec_function_name
= "g_param_spec_int64";
3397 min_value
= "G_MININT64";
3398 max_value
= "G_MAXINT64";
3401 case t_base_type::TYPE_DOUBLE
:
3402 param_spec_function_name
= "g_param_spec_double";
3403 min_value
= "-INFINITY";
3404 max_value
= "INFINITY";
3408 throw "compiler error: "
3409 "unrecognized base type \"" + member_type
->get_name() + "\" "
3410 "for struct member \""
3411 + member_name
+ "\"";
3415 if (member_value
!= NULL
) {
3416 default_value
<< (base_type
== t_base_type::TYPE_DOUBLE
? member_value
->get_double()
3417 : member_value
->get_integer());
3419 default_value
<< "0";
3422 args_indent
+= string(param_spec_function_name
.length() + 2, ' ');
3423 f_types_impl_
<< param_spec_function_name
<< " (\"" << member_name
<< "\"," << endl
3424 << args_indent
<< "NULL," << endl
<< args_indent
<< "NULL," << endl
3425 << args_indent
<< min_value
<< "," << endl
<< args_indent
<< max_value
3426 << "," << endl
<< args_indent
<< default_value
.str() << "," << endl
3427 << args_indent
<< "G_PARAM_READWRITE));" << endl
;
3431 } else if (member_type
->is_enum()) {
3432 t_enum_value
* enum_min_value
= ((t_enum
*)member_type
)->get_min_value();
3433 t_enum_value
* enum_max_value
= ((t_enum
*)member_type
)->get_max_value();
3434 int min_value
= (enum_min_value
!= NULL
) ? enum_min_value
->get_value() : 0;
3435 int max_value
= (enum_max_value
!= NULL
) ? enum_max_value
->get_value() : 0;
3437 args_indent
+= string(18, ' ');
3438 f_types_impl_
<< "g_param_spec_int (\"" << member_name
<< "\"," << endl
<< args_indent
3439 << "NULL," << endl
<< args_indent
<< "NULL," << endl
<< args_indent
3440 << min_value
<< "," << endl
<< args_indent
<< max_value
<< "," << endl
3441 << args_indent
<< min_value
<< "," << endl
<< args_indent
3442 << "G_PARAM_READWRITE));" << endl
;
3444 } else if (member_type
->is_struct() || member_type
->is_xception()) {
3445 t_program
* type_program
= member_type
->get_program();
3446 string type_nspace
= type_program
? type_program
->get_namespace("c_glib") : "";
3447 string type_nspace_prefix
=
3448 type_nspace
.empty() ? "" : initial_caps_to_underscores(type_nspace
) + "_";
3450 string param_type
= to_upper_case(type_nspace_prefix
) + "TYPE_"
3451 + to_upper_case(initial_caps_to_underscores(member_type
->get_name()));
3453 args_indent
+= string(20, ' ');
3454 f_types_impl_
<< "g_param_spec_object (\"" << member_name
<< "\"," << endl
<< args_indent
3455 << "NULL," << endl
<< args_indent
<< "NULL," << endl
<< args_indent
3456 << param_type
<< "," << endl
<< args_indent
<< "G_PARAM_READWRITE));" << endl
;
3458 } else if (member_type
->is_list()) {
3459 t_type
* elem_type
= ((t_list
*)member_type
)->get_elem_type();
3462 if (elem_type
->is_base_type() && !elem_type
->is_string()) {
3463 param_type
= "G_TYPE_ARRAY";
3465 param_type
= "G_TYPE_PTR_ARRAY";
3468 args_indent
+= string(20, ' ');
3469 f_types_impl_
<< "g_param_spec_boxed (\"" << member_name
<< "\"," << endl
<< args_indent
3470 << "NULL," << endl
<< args_indent
<< "NULL," << endl
<< args_indent
3471 << param_type
<< "," << endl
<< args_indent
<< "G_PARAM_READWRITE));" << endl
;
3473 } else if (member_type
->is_set() || member_type
->is_map()) {
3474 args_indent
+= string(20, ' ');
3475 f_types_impl_
<< "g_param_spec_boxed (\"" << member_name
<< "\"," << endl
<< args_indent
3476 << "NULL," << endl
<< args_indent
<< "NULL," << endl
<< args_indent
3477 << "G_TYPE_HASH_TABLE," << endl
<< args_indent
<< "G_PARAM_READWRITE));"
3483 scope_down(f_types_impl_
);
3484 f_types_impl_
<< endl
;
3486 f_types_impl_
<< "GType" << endl
<< this->nspace_lc
<< name_u
<< "_get_type (void)" << endl
<< "{"
3487 << endl
<< " static GType type = 0;" << endl
<< endl
<< " if (type == 0) " << endl
3488 << " {" << endl
<< " static const GTypeInfo type_info = " << endl
<< " {"
3489 << endl
<< " sizeof (" << this->nspace
<< name
<< "Class)," << endl
3490 << " NULL, /* base_init */" << endl
<< " NULL, /* base_finalize */"
3491 << endl
<< " (GClassInitFunc) " << this->nspace_lc
<< name_u
<< "_class_init,"
3492 << endl
<< " NULL, /* class_finalize */" << endl
3493 << " NULL, /* class_data */" << endl
<< " sizeof (" << this->nspace
3494 << name
<< ")," << endl
<< " 0, /* n_preallocs */" << endl
3495 << " (GInstanceInitFunc) " << this->nspace_lc
<< name_u
<< "_instance_init,"
3496 << endl
<< " NULL, /* value_table */" << endl
<< " };" << endl
<< endl
3497 << " type = g_type_register_static (THRIFT_TYPE_STRUCT, " << endl
3498 << " \"" << this->nspace
<< name
<< "Type\","
3499 << endl
<< " &type_info, 0);" << endl
<< " }"
3500 << endl
<< endl
<< " return type;" << endl
<< "}" << endl
<< endl
;
3504 * Generates functions to write Thrift structures to a stream.
3506 void t_c_glib_generator::generate_struct_writer(ostream
& out
,
3511 string name
= tstruct
->get_name();
3512 string name_u
= initial_caps_to_underscores(name
);
3513 string name_uc
= to_upper_case(name_u
);
3515 const vector
<t_field
*>& fields
= tstruct
->get_members();
3516 vector
<t_field
*>::const_iterator f_iter
;
3521 indent(out
) << "static gint32" << endl
<< this->nspace_lc
<< name_u
3522 << "_write (ThriftStruct *object, ThriftProtocol *protocol, GError **error)"
3525 indent(out
) << "{" << endl
;
3528 out
<< indent() << "gint32 ret;" << endl
<< indent() << "gint32 xfer = 0;" << endl
<< endl
;
3530 indent(out
) << this_get
<< endl
;
3531 // satisfy -Wall in the case of an empty struct
3532 if (!this_get
.empty()) {
3533 indent(out
) << "THRIFT_UNUSED_VAR (this_object);" << endl
;
3536 out
<< indent() << "if ((ret = thrift_protocol_write_struct_begin (protocol, \"" << name
3537 << "\", error)) < 0)" << endl
<< indent() << " return " << error_ret
<< ";" << endl
3538 << indent() << "xfer += ret;" << endl
;
3540 for (f_iter
= fields
.begin(); f_iter
!= fields
.end(); ++f_iter
) {
3541 if ((*f_iter
)->get_req() == t_field::T_OPTIONAL
) {
3542 indent(out
) << "if (this_object->__isset_" << (*f_iter
)->get_name() << " == TRUE) {" << endl
;
3546 out
<< indent() << "if ((ret = thrift_protocol_write_field_begin (protocol, "
3547 << "\"" << (*f_iter
)->get_name() << "\", " << type_to_enum((*f_iter
)->get_type()) << ", "
3548 << (*f_iter
)->get_key() << ", error)) < 0)" << endl
<< indent() << " return " << error_ret
3549 << ";" << endl
<< indent() << "xfer += ret;" << endl
;
3550 generate_serialize_field(out
, *f_iter
, this_name
, "", error_ret
);
3551 out
<< indent() << "if ((ret = thrift_protocol_write_field_end (protocol, error)) < 0)" << endl
3552 << indent() << " return " << error_ret
<< ";" << endl
<< indent() << "xfer += ret;"
3555 if ((*f_iter
)->get_req() == t_field::T_OPTIONAL
) {
3557 indent(out
) << "}" << endl
;
3561 // write the struct map
3562 out
<< indent() << "if ((ret = thrift_protocol_write_field_stop (protocol, error)) < 0)" << endl
3563 << indent() << " return " << error_ret
<< ";" << endl
<< indent() << "xfer += ret;" << endl
3564 << indent() << "if ((ret = thrift_protocol_write_struct_end (protocol, error)) < 0)" << endl
3565 << indent() << " return " << error_ret
<< ";" << endl
<< indent() << "xfer += ret;" << endl
3569 indent(out
) << "return xfer;" << endl
;
3573 indent(out
) << "}" << endl
<< endl
;
3577 * Generates code to read Thrift structures from a stream.
3579 void t_c_glib_generator::generate_struct_reader(ostream
& out
,
3584 string name
= tstruct
->get_name();
3585 string name_u
= initial_caps_to_underscores(name
);
3586 string name_uc
= to_upper_case(name_u
);
3588 const vector
<t_field
*>& fields
= tstruct
->get_members();
3589 vector
<t_field
*>::const_iterator f_iter
;
3593 indent(out
) << "/* reads a " << name_u
<< " object */" << endl
<< "static gint32" << endl
3594 << this->nspace_lc
<< name_u
3595 << "_read (ThriftStruct *object, ThriftProtocol *protocol, GError **error)" << endl
;
3598 indent(out
) << "{" << endl
;
3601 // declare stack temp variables
3602 out
<< indent() << "gint32 ret;" << endl
<< indent() << "gint32 xfer = 0;" << endl
<< indent()
3603 << "gchar *name = NULL;" << endl
<< indent() << "ThriftType ftype;" << endl
<< indent()
3604 << "gint16 fid;" << endl
<< indent() << "guint32 len = 0;" << endl
<< indent()
3605 << "gpointer data = NULL;" << endl
<< indent() << this_get
<< endl
;
3607 for (f_iter
= fields
.begin(); f_iter
!= fields
.end(); ++f_iter
) {
3608 if ((*f_iter
)->get_req() == t_field::T_REQUIRED
) {
3609 indent(out
) << "gboolean isset_" << (*f_iter
)->get_name() << " = FALSE;" << endl
;
3615 // satisfy -Wall in case we don't use some variables
3616 out
<< indent() << "/* satisfy -Wall in case these aren't used */" << endl
<< indent()
3617 << "THRIFT_UNUSED_VAR (len);" << endl
<< indent() << "THRIFT_UNUSED_VAR (data);" << endl
;
3619 if (!this_get
.empty()) {
3620 out
<< indent() << "THRIFT_UNUSED_VAR (this_object);" << endl
;
3624 // read the beginning of the structure marker
3625 out
<< indent() << "/* read the struct begin marker */" << endl
<< indent()
3626 << "if ((ret = thrift_protocol_read_struct_begin (protocol, &name, error)) < 0)" << endl
3627 << indent() << "{" << endl
<< indent() << " if (name) g_free (name);" << endl
<< indent()
3628 << " return " << error_ret
<< ";" << endl
<< indent() << "}" << endl
<< indent()
3629 << "xfer += ret;" << endl
<< indent() << "if (name) g_free (name);" << endl
<< indent()
3630 << "name = NULL;" << endl
<< endl
;
3632 // read the struct fields
3633 out
<< indent() << "/* read the struct fields */" << endl
<< indent() << "while (1)" << endl
;
3636 // read beginning field marker
3637 out
<< indent() << "/* read the beginning of a field */" << endl
<< indent()
3638 << "if ((ret = thrift_protocol_read_field_begin (protocol, &name, &ftype, &fid, error)) < 0)"
3639 << endl
<< indent() << "{" << endl
<< indent() << " if (name) g_free (name);" << endl
3640 << indent() << " return " << error_ret
<< ";" << endl
<< indent() << "}" << endl
<< indent()
3641 << "xfer += ret;" << endl
<< indent() << "if (name) g_free (name);" << endl
<< indent()
3642 << "name = NULL;" << endl
<< endl
;
3644 // check for field STOP marker
3645 out
<< indent() << "/* break if we get a STOP field */" << endl
<< indent()
3646 << "if (ftype == T_STOP)" << endl
<< indent() << "{" << endl
<< indent() << " break;" << endl
3647 << indent() << "}" << endl
<< endl
;
3649 // switch depending on the field type
3650 indent(out
) << "switch (fid)" << endl
;
3655 // generate deserialization code for known types
3656 for (f_iter
= fields
.begin(); f_iter
!= fields
.end(); ++f_iter
) {
3657 indent(out
) << "case " << (*f_iter
)->get_key() << ":" << endl
;
3659 indent(out
) << "if (ftype == " << type_to_enum((*f_iter
)->get_type()) << ")" << endl
;
3660 indent(out
) << "{" << endl
;
3663 // generate deserialize field
3664 generate_deserialize_field(out
, *f_iter
, this_name
, "", error_ret
, false);
3667 out
<< indent() << "} else {" << endl
<< indent()
3668 << " if ((ret = thrift_protocol_skip (protocol, ftype, error)) < 0)" << endl
<< indent()
3669 << " return " << error_ret
<< ";" << endl
<< indent() << " xfer += ret;" << endl
3670 << indent() << "}" << endl
<< indent() << "break;" << endl
;
3674 // create the default case
3675 out
<< indent() << "default:" << endl
<< indent()
3676 << " if ((ret = thrift_protocol_skip (protocol, ftype, error)) < 0)" << endl
<< indent()
3677 << " return " << error_ret
<< ";" << endl
<< indent() << " xfer += ret;" << endl
3678 << indent() << " break;" << endl
;
3683 // read field end marker
3684 out
<< indent() << "if ((ret = thrift_protocol_read_field_end (protocol, error)) < 0)" << endl
3685 << indent() << " return " << error_ret
<< ";" << endl
<< indent() << "xfer += ret;" << endl
;
3691 // read the end of the structure
3692 out
<< indent() << "if ((ret = thrift_protocol_read_struct_end (protocol, error)) < 0)" << endl
3693 << indent() << " return " << error_ret
<< ";" << endl
<< indent() << "xfer += ret;" << endl
3696 // if a required field is missing, throw an error
3697 for (f_iter
= fields
.begin(); f_iter
!= fields
.end(); ++f_iter
) {
3698 if ((*f_iter
)->get_req() == t_field::T_REQUIRED
) {
3699 out
<< indent() << "if (!isset_" << (*f_iter
)->get_name() << ")" << endl
<< indent() << "{"
3700 << endl
<< indent() << " g_set_error (error, THRIFT_PROTOCOL_ERROR," << endl
<< indent()
3701 << " THRIFT_PROTOCOL_ERROR_INVALID_DATA," << endl
<< indent()
3702 << " \"missing field\");" << endl
<< indent() << " return -1;" << endl
3703 << indent() << "}" << endl
<< endl
;
3708 indent(out
) << "return xfer;" << endl
;
3711 // end the function/structure
3713 indent(out
) << "}" << endl
<< endl
;
3716 void t_c_glib_generator::generate_serialize_field(ostream
& out
,
3721 t_type
* type
= get_true_type(tfield
->get_type());
3722 string name
= prefix
+ tfield
->get_name() + suffix
;
3724 if (type
->is_void()) {
3725 throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + name
;
3728 if (type
->is_struct() || type
->is_xception()) {
3729 generate_serialize_struct(out
, (t_struct
*)type
, name
, error_ret
);
3730 } else if (type
->is_container()) {
3731 generate_serialize_container(out
, type
, name
, error_ret
);
3732 } else if (type
->is_base_type() || type
->is_enum()) {
3733 indent(out
) << "if ((ret = thrift_protocol_write_";
3735 if (type
->is_base_type()) {
3736 t_base_type::t_base tbase
= ((t_base_type
*)type
)->get_base();
3738 case t_base_type::TYPE_VOID
:
3739 throw "compiler error: cannot serialize void field in a struct: " + name
;
3741 case t_base_type::TYPE_BOOL
:
3742 out
<< "bool (protocol, " << name
;
3744 case t_base_type::TYPE_I8
:
3745 out
<< "byte (protocol, " << name
;
3747 case t_base_type::TYPE_I16
:
3748 out
<< "i16 (protocol, " << name
;
3750 case t_base_type::TYPE_I32
:
3751 out
<< "i32 (protocol, " << name
;
3753 case t_base_type::TYPE_I64
:
3754 out
<< "i64 (protocol, " << name
;
3756 case t_base_type::TYPE_DOUBLE
:
3757 out
<< "double (protocol, " << name
;
3759 case t_base_type::TYPE_STRING
:
3760 if (type
->is_binary()) {
3761 out
<< "binary (protocol, " << name
<< " ? ((GByteArray *) " << name
<< ")->data : NULL, "
3762 << name
<< " ? ((GByteArray *) " << name
<< ")->len : 0";
3764 out
<< "string (protocol, " << name
;
3768 throw "compiler error: no C writer for base type " + t_base_type::t_base_name(tbase
) + name
;
3771 out
<< "i32 (protocol, (gint32) " << name
;
3773 out
<< ", error)) < 0)" << endl
3774 << indent() << " return " << error_ret
<< ";" << endl
3775 << indent() << "xfer += ret;" << endl
<< endl
;
3777 throw std::logic_error("DO NOT KNOW HOW TO SERIALIZE FIELD '" + name
+ "' TYPE '"
3782 void t_c_glib_generator::generate_serialize_struct(ostream
& out
,
3787 out
<< indent() << "if ((ret = thrift_struct_write (THRIFT_STRUCT (" << prefix
3788 << "), protocol, error)) < 0)" << endl
<< indent() << " return " << error_ret
<< ";" << endl
3789 << indent() << "xfer += ret;" << endl
<< endl
;
3792 void t_c_glib_generator::generate_serialize_container(ostream
& out
,
3798 if (ttype
->is_map()) {
3799 t_type
* tkey
= ((t_map
*)ttype
)->get_key_type();
3800 t_type
* tval
= ((t_map
*)ttype
)->get_val_type();
3801 string tkey_name
= type_name(tkey
);
3802 string tval_name
= type_name(tval
);
3805 string keyname
= tmp("key");
3806 string valname
= tmp("val");
3808 declore_local_variable_for_write(out
, tkey
, keyname
);
3809 declore_local_variable_for_write(out
, tval
, valname
);
3811 /* If either the key or value type is a typedef, find its underlying type so
3812 we can correctly determine how to generate a pointer to it */
3813 tkey
= get_true_type(tkey
);
3814 tval
= get_true_type(tval
);
3816 tkey_ptr
= tkey
->is_string() || !tkey
->is_base_type() ? "" : "*";
3817 tval_ptr
= tval
->is_string() || !tval
->is_base_type() ? "" : "*";
3820 * Some ugliness here. To maximize backwards compatibility, we
3821 * avoid using GHashTableIter and instead get a GList of all keys,
3822 * then copy it into a array on the stack, and free it.
3823 * This is because we may exit early before we get a chance to free the
3826 out
<< indent() << "GList *key_list = NULL, *iter = NULL;" << endl
3827 << indent() << tkey_name
<< tkey_ptr
<< "* keys;" << endl
3828 << indent() << "int i = 0, key_count;" << endl
3830 << indent() << "if ((ret = thrift_protocol_write_map_begin (protocol, "
3831 << type_to_enum(tkey
) << ", " << type_to_enum(tval
) << ", " << prefix
<< " ? "
3832 << "(gint32) g_hash_table_size ((GHashTable *) " << prefix
<< ") : 0"
3833 << ", error)) < 0)" << endl
;
3835 out
<< indent() << "return " << error_ret
<< ";" << endl
;
3837 out
<< indent() << "xfer += ret;" << endl
3838 << indent() << "if (" << prefix
<< ")" << endl
3839 << indent() << " g_hash_table_foreach ((GHashTable *) " << prefix
3840 << ", thrift_hash_table_get_keys, &key_list);" << endl
3841 << indent() << "key_count = g_list_length (key_list);" << endl
3842 << indent() << "keys = g_newa (" << tkey_name
<< tkey_ptr
3843 << ", key_count);" << endl
3844 << indent() << "for (iter = g_list_first (key_list); iter; "
3845 "iter = iter->next)" << endl
;
3847 out
<< indent() << "keys[i++] = (" << tkey_name
<< tkey_ptr
3848 << ") iter->data;" << endl
;
3850 out
<< indent() << "g_list_free (key_list);" << endl
3852 << indent() << "for (i = 0; i < key_count; ++i)" << endl
;
3854 out
<< indent() << keyname
<< " = keys[i];" << endl
3855 << indent() << valname
<< " = (" << tval_name
<< tval_ptr
3856 << ") g_hash_table_lookup (((GHashTable *) " << prefix
3857 << "), (gpointer) " << keyname
<< ");" << endl
3859 generate_serialize_map_element(out
,
3861 tkey_ptr
+ " " + keyname
,
3862 tval_ptr
+ " " + valname
,
3865 out
<< indent() << "if ((ret = thrift_protocol_write_map_end (protocol, "
3866 "error)) < 0)" << endl
;
3868 out
<< indent() << "return " << error_ret
<< ";" << endl
;
3870 out
<< indent() << "xfer += ret;" << endl
;
3871 } else if (ttype
->is_set()) {
3872 t_type
* telem
= ((t_set
*)ttype
)->get_elem_type();
3873 string telem_name
= type_name(telem
);
3874 string telem_ptr
= telem
->is_string() || !telem
->is_base_type() ? "" : "*";
3875 out
<< indent() << "GList *key_list = NULL, *iter = NULL;" << endl
3876 << indent() << telem_name
<< telem_ptr
<< "* keys;" << endl
3877 << indent() << "int i = 0, key_count;" << endl
3878 << indent() << telem_name
<< telem_ptr
<< " elem;" << endl
3879 << indent() << "gpointer value;" << endl
3880 << indent() << "THRIFT_UNUSED_VAR (value);" << endl
3882 << indent() << "if ((ret = thrift_protocol_write_set_begin (protocol, "
3883 << type_to_enum(telem
) << ", " << prefix
<< " ? "
3884 << "(gint32) g_hash_table_size ((GHashTable *) " << prefix
<< ") : 0"
3885 << ", error)) < 0)" << endl
;
3887 out
<< indent() << "return " << error_ret
<< ";" << endl
;
3889 out
<< indent() << "xfer += ret;" << endl
3890 << indent() << "if (" << prefix
<< ")" << endl
3891 << indent() << " g_hash_table_foreach ((GHashTable *) " << prefix
3892 << ", thrift_hash_table_get_keys, &key_list);" << endl
3893 << indent() << "key_count = g_list_length (key_list);" << endl
3894 << indent() << "keys = g_newa (" << telem_name
<< telem_ptr
3895 << ", key_count);" << endl
3896 << indent() << "for (iter = g_list_first (key_list); iter; "
3897 "iter = iter->next)" << endl
;
3899 out
<< indent() << "keys[i++] = (" << telem_name
<< telem_ptr
3900 << ") iter->data;" << endl
;
3902 out
<< indent() << "g_list_free (key_list);" << endl
3904 << indent() << "for (i = 0; i < key_count; ++i)" << endl
;
3906 out
<< indent() << "elem = keys[i];" << endl
3907 << indent() << "value = (gpointer) g_hash_table_lookup "
3908 "(((GHashTable *) " << prefix
<< "), (gpointer) elem);" << endl
3910 generate_serialize_set_element(out
,
3915 out
<< indent() << "if ((ret = thrift_protocol_write_set_end (protocol, "
3916 "error)) < 0)" << endl
;
3918 out
<< indent() << "return " << error_ret
<< ";" << endl
;
3920 out
<< indent() << "xfer += ret;" << endl
;
3921 } else if (ttype
->is_list()) {
3922 string length
= "(" + prefix
+ " ? " + prefix
+ "->len : 0)";
3923 string i
= tmp("i");
3924 out
<< indent() << "guint " << i
<< ";" << endl
3926 << indent() << "if ((ret = thrift_protocol_write_list_begin (protocol, "
3927 << type_to_enum(((t_list
*)ttype
)->get_elem_type()) << ", (gint32) "
3928 << length
<< ", error)) < 0)" << endl
;
3930 out
<< indent() << "return " << error_ret
<< ";" << endl
;
3932 out
<< indent() << "xfer += ret;" << endl
3933 << indent() << "for (" << i
<< " = 0; " << i
<< " < " << length
<< "; "
3934 << i
<< "++)" << endl
;
3936 generate_serialize_list_element(out
, (t_list
*)ttype
, prefix
, i
, error_ret
);
3938 out
<< indent() << "if ((ret = thrift_protocol_write_list_end (protocol, "
3939 "error)) < 0)" << endl
;
3941 out
<< indent() << "return " << error_ret
<< ";" << endl
;
3943 out
<< indent() << "xfer += ret;" << endl
;
3949 void t_c_glib_generator::generate_serialize_map_element(ostream
& out
,
3954 t_field
kfield(tmap
->get_key_type(), key
);
3955 generate_serialize_field(out
, &kfield
, "", "", error_ret
);
3957 t_field
vfield(tmap
->get_val_type(), value
);
3958 generate_serialize_field(out
, &vfield
, "", "", error_ret
);
3961 void t_c_glib_generator::generate_serialize_set_element(ostream
& out
,
3965 t_field
efield(tset
->get_elem_type(), element
);
3966 generate_serialize_field(out
, &efield
, "", "", error_ret
);
3969 void t_c_glib_generator::generate_serialize_list_element(ostream
& out
,
3974 t_type
* ttype
= get_true_type(tlist
->get_elem_type());
3976 // cast to non-const
3978 string name
= "g_ptr_array_index ((GPtrArray *) " + list
+ ", " + index
+ ")";
3980 if (ttype
->is_void()) {
3981 throw std::runtime_error("compiler error: list element type cannot be void");
3982 } else if (is_numeric(ttype
)) {
3983 name
= "g_array_index (" + list
+ ", " + base_type_name(ttype
) + ", " + index
+ ")";
3984 } else if (ttype
->is_string()) {
3986 } else if (ttype
->is_map() || ttype
->is_set()) {
3987 cast
= "(GHashTable*)";
3988 } else if (ttype
->is_list()) {
3989 t_type
* etype
= ((t_list
*)ttype
)->get_elem_type();
3990 if (etype
->is_void()) {
3991 throw std::runtime_error("compiler error: list element type cannot be void");
3993 cast
= is_numeric(etype
) ? "(GArray*)" : "(GPtrArray*)";
3996 t_field
efield(ttype
, "(" + cast
+ name
+ ")");
3997 generate_serialize_field(out
, &efield
, "", "", error_ret
);
4000 /* deserializes a field of any type. */
4001 void t_c_glib_generator::generate_deserialize_field(ostream
& out
,
4007 t_type
* type
= get_true_type(tfield
->get_type());
4009 if (type
->is_void()) {
4010 throw std::runtime_error("CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix
4011 + tfield
->get_name());
4014 string name
= prefix
+ tfield
->get_name() + suffix
;
4016 if (type
->is_struct() || type
->is_xception()) {
4017 generate_deserialize_struct(out
, (t_struct
*)type
, name
, error_ret
, allocate
);
4018 } else if (type
->is_container()) {
4019 generate_deserialize_container(out
, type
, name
, error_ret
);
4020 } else if (type
->is_base_type()) {
4021 t_base_type::t_base tbase
= ((t_base_type
*)type
)->get_base();
4022 if (tbase
== t_base_type::TYPE_STRING
) {
4023 indent(out
) << "if (" << name
<< " != NULL)" << endl
<< indent() << "{" << endl
;
4025 indent(out
) << "g_free(" << name
<< ");" << endl
<< indent() << name
<< " = NULL;" << endl
;
4027 indent(out
) << "}" << endl
<< endl
;
4029 indent(out
) << "if ((ret = thrift_protocol_read_";
4032 case t_base_type::TYPE_VOID
:
4033 throw "compiler error: cannot serialize void field in a struct: " + name
;
4035 case t_base_type::TYPE_STRING
:
4036 if (type
->is_binary()) {
4037 out
<< "binary (protocol, &data, &len";
4039 out
<< "string (protocol, &" << name
;
4042 case t_base_type::TYPE_BOOL
:
4043 out
<< "bool (protocol, &" << name
;
4045 case t_base_type::TYPE_I8
:
4046 out
<< "byte (protocol, &" << name
;
4048 case t_base_type::TYPE_I16
:
4049 out
<< "i16 (protocol, &" << name
;
4051 case t_base_type::TYPE_I32
:
4052 out
<< "i32 (protocol, &" << name
;
4054 case t_base_type::TYPE_I64
:
4055 out
<< "i64 (protocol, &" << name
;
4057 case t_base_type::TYPE_DOUBLE
:
4058 out
<< "double (protocol, &" << name
;
4061 throw "compiler error: no C reader for base type " + t_base_type::t_base_name(tbase
) + name
;
4063 out
<< ", error)) < 0)" << endl
;
4064 out
<< indent() << " return " << error_ret
<< ";" << endl
<< indent() << "xfer += ret;"
4067 // load the byte array with the data
4068 if (tbase
== t_base_type::TYPE_STRING
&& type
->is_binary()) {
4069 indent(out
) << name
<< " = g_byte_array_new();" << endl
;
4070 indent(out
) << "g_byte_array_append (" << name
<< ", (guint8 *) data, (guint) len);" << endl
;
4071 indent(out
) << "g_free (data);" << endl
;
4073 } else if (type
->is_enum()) {
4074 string t
= tmp("ecast");
4075 out
<< indent() << "gint32 " << t
<< ";" << endl
<< indent()
4076 << "if ((ret = thrift_protocol_read_i32 (protocol, &" << t
<< ", error)) < 0)" << endl
4077 << indent() << " return " << error_ret
<< ";" << endl
<< indent() << "xfer += ret;" << endl
4078 << indent() << name
<< " = (" << type_name(type
) << ")" << t
<< ";" << endl
;
4080 throw std::logic_error("DO NOT KNOW HOW TO SERIALIZE FIELD '" + tfield
->get_name() + "' TYPE '"
4084 // if the type is not required and this is a thrift struct (no prefix),
4085 // set the isset variable. if the type is required, then set the
4086 // local variable indicating the value was set, so that we can do // validation later.
4087 if (prefix
!= "" && tfield
->get_req() != t_field::T_REQUIRED
) {
4088 indent(out
) << prefix
<< "__isset_" << tfield
->get_name() << suffix
<< " = TRUE;" << endl
;
4089 } else if (prefix
!= "" && tfield
->get_req() == t_field::T_REQUIRED
) {
4090 indent(out
) << "isset_" << tfield
->get_name() << " = TRUE;" << endl
;
4094 void t_c_glib_generator::generate_deserialize_struct(ostream
& out
,
4099 string name_uc
= to_upper_case(initial_caps_to_underscores(tstruct
->get_name()));
4100 if (tstruct
->is_xception()) {
4101 out
<< indent() << "/* This struct is an exception */" << endl
;
4106 out
<< indent() << "if ( " << prefix
<< " != NULL)" << endl
<< indent() << "{" << endl
;
4108 out
<< indent() << "g_object_unref (" << prefix
<< ");" << endl
;
4110 out
<< indent() << "}" << endl
<< indent() << prefix
<< " = g_object_new (" << this->nspace_uc
4111 << "TYPE_" << name_uc
<< ", NULL);" << endl
;
4113 out
<< indent() << "if ((ret = thrift_struct_read (THRIFT_STRUCT (" << prefix
4114 << "), protocol, error)) < 0)" << endl
<< indent() << "{" << endl
;
4117 indent(out
) << "g_object_unref (" << prefix
<< ");" << endl
;
4118 if (tstruct
->is_xception()) {
4119 indent(out
) << prefix
<< " = NULL;" << endl
;
4122 out
<< indent() << "return " << error_ret
<< ";" << endl
;
4124 out
<< indent() << "}" << endl
<< indent() << "xfer += ret;" << endl
;
4127 void t_c_glib_generator::generate_deserialize_container(ostream
& out
,
4133 if (ttype
->is_map()) {
4134 out
<< indent() << "guint32 size;" << endl
4135 << indent() << "guint32 i;" << endl
4136 << indent() << "ThriftType key_type;" << endl
4137 << indent() << "ThriftType value_type;" << endl
4139 << indent() << "/* read the map begin marker */" << endl
4140 << indent() << "if ((ret = thrift_protocol_read_map_begin (protocol, "
4141 "&key_type, &value_type, &size, error)) < 0)" << endl
;
4143 out
<< indent() << "return " << error_ret
<< ";" << endl
;
4145 out
<< indent() << "xfer += ret;" << endl
4148 // iterate over map elements
4149 out
<< indent() << "/* iterate through each of the map's fields */" << endl
4150 << indent() << "for (i = 0; i < size; i++)" << endl
;
4152 generate_deserialize_map_element(out
, (t_map
*)ttype
, prefix
, error_ret
);
4157 out
<< indent() << "/* read the map end marker */" << endl
4158 << indent() << "if ((ret = thrift_protocol_read_map_end (protocol, "
4159 "error)) < 0)" << endl
;
4161 out
<< indent() << "return " << error_ret
<< ";" << endl
;
4163 out
<< indent() << "xfer += ret;" << endl
;
4164 } else if (ttype
->is_set()) {
4165 out
<< indent() << "guint32 size;" << endl
4166 << indent() << "guint32 i;" << endl
4167 << indent() << "ThriftType element_type;" << endl
4169 << indent() << "if ((ret = thrift_protocol_read_set_begin (protocol, "
4170 "&element_type, &size, error)) < 0)" << endl
;
4172 out
<< indent() << "return " << error_ret
<< ";" << endl
;
4174 out
<< indent() << "xfer += ret;" << endl
4177 // iterate over the elements
4178 out
<< indent() << "/* iterate through the set elements */" << endl
4179 << indent() << "for (i = 0; i < size; ++i)" << endl
;
4181 generate_deserialize_set_element(out
, (t_set
*)ttype
, prefix
, error_ret
);
4185 out
<< indent() << "if ((ret = thrift_protocol_read_set_end (protocol, "
4186 "error)) < 0)" << endl
;
4188 out
<< indent() << "return " << error_ret
<< ";" << endl
;
4190 out
<< indent() << "xfer += ret;" << endl
4192 } else if (ttype
->is_list()) {
4193 out
<< indent() << "guint32 size;" << endl
4194 << indent() << "guint32 i;" << endl
4195 << indent() << "ThriftType element_type;" << endl
4197 << indent() << "if ((ret = thrift_protocol_read_list_begin (protocol, "
4198 "&element_type,&size, error)) < 0)" << endl
;
4200 out
<< indent() << "return " << error_ret
<< ";" << endl
;
4202 out
<< indent() << "xfer += ret;" << endl
4205 // iterate over the elements
4206 out
<< indent() << "/* iterate through list elements */" << endl
4207 << indent() << "for (i = 0; i < size; i++)" << endl
;
4209 generate_deserialize_list_element(out
,
4217 out
<< indent() << "if ((ret = thrift_protocol_read_list_end (protocol, "
4218 "error)) < 0)" << endl
;
4220 out
<< indent() << "return " << error_ret
<< ";" << endl
;
4222 out
<< indent() << "xfer += ret;" << endl
;
4228 void t_c_glib_generator::declare_local_variable(ostream
& out
, t_type
* ttype
, string
& name
, bool for_hash_table
) {
4229 string tname
= type_name(ttype
);
4231 /* If the given type is a typedef, find its underlying type so we
4232 can correctly determine how to generate a pointer to it */
4233 ttype
= get_true_type(ttype
);
4234 string ptr
= !is_numeric(ttype
) ? "" : "*";
4236 if (ttype
->is_map()) {
4237 t_map
* tmap
= (t_map
*)ttype
;
4238 out
<< indent() << tname
<< ptr
<< " " << name
<< " = "
4239 << generate_new_hash_from_type(tmap
->get_key_type(), tmap
->get_val_type()) << endl
;
4240 } else if (ttype
->is_list()) {
4241 t_list
* tlist
= (t_list
*)ttype
;
4242 out
<< indent() << tname
<< ptr
<< " " << name
<< " = "
4243 << generate_new_array_from_type(tlist
->get_elem_type()) << endl
;
4244 } else if (for_hash_table
&& ttype
->is_enum()) {
4245 out
<< indent() << tname
<< " " << name
<< ";" << endl
;
4247 out
<< indent() << tname
<< ptr
<< " " << name
4248 << (ptr
!= "" ? " = g_new (" + tname
+ ", 1)" : " = NULL") << ";" << endl
;
4252 void t_c_glib_generator::declore_local_variable_for_write(ostream
& out
,
4255 string tname
= type_name(ttype
);
4256 ttype
= get_true_type(ttype
);
4257 string ptr
= ttype
->is_string() || !ttype
->is_base_type() ? " " : "* ";
4258 string init_val
= ttype
->is_enum() ? "" : " = NULL";
4259 out
<< indent() << tname
<< ptr
<< name
<< init_val
<< ";" << endl
;
4262 void t_c_glib_generator::generate_deserialize_map_element(ostream
& out
,
4266 t_type
* tkey
= tmap
->get_key_type();
4267 t_type
* tval
= tmap
->get_val_type();
4268 string keyname
= tmp("key");
4269 string valname
= tmp("val");
4271 declare_local_variable(out
, tkey
, keyname
, true);
4272 declare_local_variable(out
, tval
, valname
, true);
4274 /* If either the key or value type is a typedef, find its underlying
4275 type so we can correctly determine how to generate a pointer to
4277 tkey
= get_true_type(tkey
);
4278 tval
= get_true_type(tval
);
4280 string tkey_ptr
= tkey
->is_string() || !tkey
->is_base_type() ? "" : "*";
4281 string tval_ptr
= tval
->is_string() || !tval
->is_base_type() ? "" : "*";
4283 // deserialize the fields of the map element
4284 t_field
fkey(tkey
, tkey_ptr
+ keyname
);
4285 generate_deserialize_field(out
, &fkey
, "", "", error_ret
);
4286 t_field
fval(tval
, tval_ptr
+ valname
);
4287 generate_deserialize_field(out
, &fval
, "", "", error_ret
);
4289 indent(out
) << "if (" << prefix
<< " && " << keyname
<< ")" << endl
;
4291 indent(out
) << "g_hash_table_insert ((GHashTable *)" << prefix
<< ", (gpointer) " << keyname
4292 << ", (gpointer) " << valname
<< ");" << endl
;
4296 void t_c_glib_generator::generate_deserialize_set_element(ostream
& out
,
4300 t_type
* telem
= tset
->get_elem_type();
4301 string elem
= tmp("_elem");
4302 string telem_ptr
= telem
->is_string() || !telem
->is_base_type() ? "" : "*";
4304 declare_local_variable(out
, telem
, elem
, true);
4306 t_field
felem(telem
, telem_ptr
+ elem
);
4307 generate_deserialize_field(out
, &felem
, "", "", error_ret
);
4309 indent(out
) << "if (" << prefix
<< " && " << elem
<< ")" << endl
;
4311 indent(out
) << "g_hash_table_insert ((GHashTable *) " << prefix
<< ", (gpointer) " << elem
4312 << ", (gpointer) " << elem
<< ");" << endl
;
4316 void t_c_glib_generator::generate_deserialize_list_element(ostream
& out
,
4322 t_type
* ttype
= get_true_type(tlist
->get_elem_type());
4323 string elem
= tmp("_elem");
4324 string telem_ptr
= !is_numeric(ttype
) ? "" : "*";
4326 declare_local_variable(out
, ttype
, elem
, false);
4328 t_field
felem(ttype
, telem_ptr
+ elem
);
4329 generate_deserialize_field(out
, &felem
, "", "", error_ret
);
4331 if (ttype
->is_void()) {
4332 throw std::runtime_error("compiler error: list element type cannot be void");
4333 } else if (is_numeric(ttype
)) {
4334 indent(out
) << "g_array_append_vals (" << prefix
<< ", " << elem
<< ", 1);" << endl
;
4336 indent(out
) << "g_ptr_array_add (" << prefix
<< ", " << elem
<< ");" << endl
;
4340 string
t_c_glib_generator::generate_free_func_from_type(t_type
* ttype
) {
4344 if (ttype
->is_base_type()) {
4345 t_base_type::t_base tbase
= ((t_base_type
*)ttype
)->get_base();
4347 case t_base_type::TYPE_VOID
:
4348 throw "compiler error: cannot determine hash type";
4350 case t_base_type::TYPE_BOOL
:
4351 case t_base_type::TYPE_I8
:
4352 case t_base_type::TYPE_I16
:
4353 case t_base_type::TYPE_I32
:
4354 case t_base_type::TYPE_I64
:
4355 case t_base_type::TYPE_DOUBLE
:
4357 case t_base_type::TYPE_STRING
:
4358 if (((t_base_type
*)ttype
)->is_binary()) {
4359 return "thrift_string_free";
4363 throw "compiler error: no hash table info for type";
4365 } else if (ttype
->is_enum()) {
4367 } else if (ttype
->is_map() || ttype
->is_set()) {
4368 return "(GDestroyNotify) thrift_safe_hash_table_destroy";
4369 } else if (ttype
->is_struct()) {
4370 return "g_object_unref";
4371 } else if (ttype
->is_list()) {
4372 t_type
* etype
= ((t_list
*)ttype
)->get_elem_type();
4373 if (etype
->is_base_type()) {
4374 t_base_type::t_base tbase
= ((t_base_type
*)etype
)->get_base();
4376 case t_base_type::TYPE_VOID
:
4377 throw "compiler error: cannot determine array type";
4379 case t_base_type::TYPE_BOOL
:
4380 case t_base_type::TYPE_I8
:
4381 case t_base_type::TYPE_I16
:
4382 case t_base_type::TYPE_I32
:
4383 case t_base_type::TYPE_I64
:
4384 case t_base_type::TYPE_DOUBLE
:
4385 return "(GDestroyNotify) g_array_unref";
4386 case t_base_type::TYPE_STRING
:
4387 return "(GDestroyNotify) g_ptr_array_unref";
4389 throw "compiler error: no array info for type";
4391 } else if (etype
->is_container() || etype
->is_struct()) {
4392 return "(GDestroyNotify) g_ptr_array_unref";
4394 } else if (etype
->is_enum()) {
4395 return "(GDestroyNotify) g_array_unref";
4397 printf("Type not expected inside the array: %s\n", etype
->get_name().c_str());
4398 throw "Type not expected inside array";
4399 } else if (ttype
->is_typedef()) {
4400 return generate_free_func_from_type(((t_typedef
*)ttype
)->get_type());
4402 printf("Type not expected: %s\n", ttype
->get_name().c_str());
4403 throw "Type not expected";
4406 string
t_c_glib_generator::generate_hash_func_from_type(t_type
* ttype
) {
4410 if (ttype
->is_base_type()) {
4411 t_base_type::t_base tbase
= ((t_base_type
*)ttype
)->get_base();
4413 case t_base_type::TYPE_VOID
:
4414 throw "compiler error: cannot determine hash type";
4416 case t_base_type::TYPE_BOOL
:
4417 return "thrift_boolean_hash";
4418 case t_base_type::TYPE_I8
:
4419 return "thrift_int8_hash";
4420 case t_base_type::TYPE_I16
:
4421 return "thrift_int16_hash";
4422 case t_base_type::TYPE_I32
:
4423 return "g_int_hash";
4424 case t_base_type::TYPE_I64
:
4425 return "g_int64_hash";
4426 case t_base_type::TYPE_DOUBLE
:
4427 return "g_double_hash";
4428 case t_base_type::TYPE_STRING
:
4429 return "g_str_hash";
4431 throw "compiler error: no hash table info for type";
4433 } else if (ttype
->is_enum()) {
4434 return "g_direct_hash";
4435 } else if (ttype
->is_container() || ttype
->is_struct()) {
4436 return "g_direct_hash";
4437 } else if (ttype
->is_typedef()) {
4438 return generate_hash_func_from_type(((t_typedef
*)ttype
)->get_type());
4440 printf("Type not expected: %s\n", ttype
->get_name().c_str());
4441 throw "Type not expected";
4444 string
t_c_glib_generator::generate_cmp_func_from_type(t_type
* ttype
) {
4448 if (ttype
->is_base_type()) {
4449 t_base_type::t_base tbase
= ((t_base_type
*)ttype
)->get_base();
4451 case t_base_type::TYPE_VOID
:
4452 throw "compiler error: cannot determine hash type";
4454 case t_base_type::TYPE_BOOL
:
4455 return "thrift_boolean_equal";
4456 case t_base_type::TYPE_I8
:
4457 return "thrift_int8_equal";
4458 case t_base_type::TYPE_I16
:
4459 return "thrift_int16_equal";
4460 case t_base_type::TYPE_I32
:
4461 return "g_int_equal";
4462 case t_base_type::TYPE_I64
:
4463 return "g_int64_equal";
4464 case t_base_type::TYPE_DOUBLE
:
4465 return "g_double_equal";
4466 case t_base_type::TYPE_STRING
:
4467 return "g_str_equal";
4469 throw "compiler error: no hash table info for type";
4471 } else if (ttype
->is_enum()) {
4472 return "g_direct_equal";
4473 } else if (ttype
->is_container() || ttype
->is_struct()) {
4474 return "g_direct_equal";
4475 } else if (ttype
->is_typedef()) {
4476 return generate_cmp_func_from_type(((t_typedef
*)ttype
)->get_type());
4478 printf("Type not expected: %s\n", ttype
->get_name().c_str());
4479 throw "Type not expected";
4482 string
t_c_glib_generator::generate_new_hash_from_type(t_type
* key
, t_type
* value
) {
4483 string hash_func
= generate_hash_func_from_type(key
);
4484 string cmp_func
= generate_cmp_func_from_type(key
);
4485 string key_free_func
= generate_free_func_from_type(key
);
4486 string value_free_func
= generate_free_func_from_type(value
);
4488 return "g_hash_table_new_full (" + hash_func
+ ", " + cmp_func
+ ", " + key_free_func
+ ", "
4489 + value_free_func
+ ");";
4492 string
t_c_glib_generator::generate_new_array_from_type(t_type
* ttype
) {
4493 if (ttype
->is_void()) {
4494 throw std::runtime_error("compiler error: cannot determine array type");
4495 } else if (is_numeric(ttype
)) {
4496 return "g_array_new (0, 1, sizeof (" + base_type_name(ttype
) + "));";
4498 string free_func
= generate_free_func_from_type(ttype
);
4499 return "g_ptr_array_new_with_free_func (" + free_func
+ ");";
4503 /***************************************
4504 * UTILITY FUNCTIONS *
4505 ***************************************/
4508 * Upper case a string.
4510 string
to_upper_case(string name
) {
4512 std::transform(s
.begin(), s
.end(), s
.begin(), ::toupper
);
4517 * Lower case a string.
4519 string
to_lower_case(string name
) {
4521 std::transform(s
.begin(), s
.end(), s
.begin(), ::tolower
);
4526 * Makes a string friendly to C code standards by lowercasing and adding
4527 * underscores, with the exception of the first character. For example:
4529 * Input: "ZomgCamelCase"
4530 * Output: "zomg_camel_case"
4532 string
initial_caps_to_underscores(string name
) {
4534 const char* tmp
= name
.c_str();
4537 /* the first character isn't underscored if uppercase, just lowercased */
4538 ret
+= tolower(tmp
[pos
]);
4540 for (unsigned int i
= pos
; i
< name
.length(); i
++) {
4541 char lc
= tolower(tmp
[i
]);
4552 * Performs the reverse operation of initial_caps_to_underscores: The first
4553 * character of the string is made uppercase, along with each character that
4554 * follows an underscore (which is removed). Useful for converting Thrift
4555 * service-method names into GObject-style class names.
4557 * Input: "zomg_camel_case"
4558 * Output: "ZomgCamelCase"
4560 string
underscores_to_initial_caps(string name
) {
4562 const char* tmp
= name
.c_str();
4563 bool uppercase_next
= true;
4565 for (unsigned int i
= 0; i
< name
.length(); i
++) {
4568 uppercase_next
= true;
4570 if (uppercase_next
) {
4572 uppercase_next
= false;
4582 /* register this generator with the main program */
4583 THRIFT_REGISTER_GENERATOR(c_glib
, "C, using GLib", "")