Repository: thrift Updated Branches: refs/heads/master a6ab1f5e6 -> 9caf6d63c
THRIFT-3464 Fix several defects in c_glib code generator Client: c_glib compiler Patch: Nobuaki Sukegawa This closes #724 Project: http://git-wip-us.apache.org/repos/asf/thrift/repo Commit: http://git-wip-us.apache.org/repos/asf/thrift/commit/ba3fe86b Tree: http://git-wip-us.apache.org/repos/asf/thrift/tree/ba3fe86b Diff: http://git-wip-us.apache.org/repos/asf/thrift/diff/ba3fe86b Branch: refs/heads/master Commit: ba3fe86b0ab50fa5e934debe9c3bca185ca9b704 Parents: a6ab1f5 Author: Nobuaki Sukegawa <[email protected]> Authored: Tue Dec 1 22:42:55 2015 +0900 Committer: Nobuaki Sukegawa <[email protected]> Committed: Sun Dec 6 10:11:16 2015 +0900 ---------------------------------------------------------------------- compiler/cpp/src/generate/t_c_glib_generator.cc | 395 +++++++++---------- lib/c_glib/src/thrift/c_glib/thrift.c | 61 +++ lib/c_glib/src/thrift/c_glib/thrift.h | 11 + lib/c_glib/test/CMakeLists.txt | 12 + lib/c_glib/test/Makefile.am | 7 + lib/c_glib/test/testoptionalrequired.c | 21 + lib/c_glib/test/testserialization.c | 49 +++ test/EnumTest.thrift | 37 ++ test/OptionalRequiredTest.thrift | 6 + test/c_glib/src/thrift_test_handler.c | 1 + 10 files changed, 391 insertions(+), 209 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/thrift/blob/ba3fe86b/compiler/cpp/src/generate/t_c_glib_generator.cc ---------------------------------------------------------------------- diff --git a/compiler/cpp/src/generate/t_c_glib_generator.cc b/compiler/cpp/src/generate/t_c_glib_generator.cc index e6b48a4..22d7914 100644 --- a/compiler/cpp/src/generate/t_c_glib_generator.cc +++ b/compiler/cpp/src/generate/t_c_glib_generator.cc @@ -23,6 +23,7 @@ #include <fstream> #include <iostream> +#include <stdexcept> #include <string> #include <vector> @@ -122,12 +123,14 @@ private: /* helper functions */ bool is_complex_type(t_type* ttype); + bool is_numeric(t_type* ttype); string type_name(t_type* ttype, bool in_typedef = false, bool is_const = false); string property_type_name(t_type* ttype, bool in_typedef = false, bool is_const = false); - string base_type_name(t_base_type* type); + string base_type_name(t_type* type); string type_to_enum(t_type* type); string constant_literal(t_type* type, t_const_value* value); string constant_value(string name, t_type* type, t_const_value* value); + string constant_value_with_storage(string name, t_type* type, t_const_value* value); string function_signature(t_function* tfunction); string argument_list(t_struct* tstruct); string xception_list(t_struct* tstruct); @@ -136,10 +139,14 @@ private: bool pointer = false, bool constant = false, bool reference = false); - void declare_local_variable(ofstream& out, t_type* ttype, string& base_name); + void declare_local_variable(ofstream& out, t_type* ttype, string& base_name, bool for_hash_table); + void declore_local_variable_for_write(ofstream& out, t_type* ttype, string& base_name); /* generation functions */ - void generate_const_initializer(string name, t_type* type, t_const_value* value); + void generate_const_initializer(string name, + t_type* type, + t_const_value* value, + bool top_level = false); void generate_service_helpers(t_service* tservice); void generate_service_client(t_service* tservice); void generate_service_handler(t_service* tservice); @@ -348,10 +355,17 @@ void t_c_glib_generator::generate_enum(t_enum* tenum) { f_types_impl_ << "{" << endl; f_types_impl_ << " static __thread char buf[16] = {0};" << endl; f_types_impl_ << " switch(value) {" << endl; + std::set<int> done; for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { - f_types_impl_ << " case " << this->nspace_uc << name_uc << "_" << (*c_iter)->get_name() << ":" - << "return \"" << this->nspace_uc << name_uc << "_" << (*c_iter)->get_name() - << "\";" << endl; + int value = (*c_iter)->get_value(); + // Skipping duplicate value + if (done.find(value) == done.end()) { + done.insert(value); + f_types_impl_ << " case " << this->nspace_uc << name_uc << "_" << (*c_iter)->get_name() + << ":" + << "return \"" << this->nspace_uc << name_uc << "_" << (*c_iter)->get_name() + << "\";" << endl; + } } f_types_impl_ << " default: g_snprintf(buf, 16, \"%d\", value); return buf;" << endl; f_types_impl_ << " }" << endl; @@ -373,10 +387,15 @@ void t_c_glib_generator::generate_consts(vector<t_const*> consts) { t_type* type = (*c_iter)->get_type(); t_const_value* value = (*c_iter)->get_value(); + if (is_complex_type(type)) { + f_types_ << type_name(type) << indent() << this->nspace_lc << name_lc + << "_constant();" << endl; + } + f_types_ << indent() << "#define " << this->nspace_uc << name_uc << " " << constant_value(name_lc, type, value) << endl; - generate_const_initializer(name_lc, type, value); + generate_const_initializer(name_lc, type, value, true); } f_types_ << endl; @@ -521,12 +540,16 @@ bool t_c_glib_generator::is_complex_type(t_type* ttype) { return ttype->is_container() || ttype->is_struct() || ttype->is_xception(); } +bool t_c_glib_generator::is_numeric(t_type* ttype) { + return ttype->is_enum() || (ttype->is_base_type() && !ttype->is_string()); +} + /** * Maps a Thrift t_type to a C type. */ string t_c_glib_generator::type_name(t_type* ttype, bool in_typedef, bool is_const) { if (ttype->is_base_type()) { - string bname = base_type_name((t_base_type*)ttype); + string bname = base_type_name(ttype); if (is_const) { return "const " + bname; @@ -550,28 +573,12 @@ string t_c_glib_generator::type_name(t_type* ttype, bool in_typedef, bool is_con // TODO: discuss whether or not to implement TSet, THashSet or GHashSet cname = "GHashTable"; } else if (ttype->is_list()) { - // TODO: investigate other implementations besides GPtrArray - cname = "GPtrArray"; t_type* etype = ((t_list*)ttype)->get_elem_type(); - if (etype->is_base_type()) { - t_base_type::t_base tbase = ((t_base_type*)etype)->get_base(); - switch (tbase) { - case t_base_type::TYPE_VOID: - throw "compiler error: cannot determine array type"; - case t_base_type::TYPE_BOOL: - case t_base_type::TYPE_I8: - case t_base_type::TYPE_I16: - case t_base_type::TYPE_I32: - case t_base_type::TYPE_I64: - case t_base_type::TYPE_DOUBLE: - cname = "GArray"; - break; - case t_base_type::TYPE_STRING: - break; - default: - throw "compiler error: no array info for type"; - } + if (etype->is_void()) { + throw std::runtime_error("compiler error: list element type cannot be void"); } + // TODO: investigate other implementations besides GPtrArray + cname = is_numeric(etype) ? "GArray" : "GPtrArray"; } /* Omit the dereference operator if we are aliasing this type within a @@ -638,14 +645,20 @@ string t_c_glib_generator::property_type_name(t_type* ttype, bool in_typedef, bo /** * Maps a Thrift primitive to a C primitive. */ -string t_c_glib_generator::base_type_name(t_base_type* type) { - t_base_type::t_base tbase = type->get_base(); - +string t_c_glib_generator::base_type_name(t_type* type) { + if (type->is_enum()) { + return type_name(type); + } + if (!type->is_base_type()) { + throw std::invalid_argument("Only base types are suppported."); + } + t_base_type* base_type = reinterpret_cast<t_base_type*>(type); + t_base_type::t_base tbase = base_type->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: return "void"; case t_base_type::TYPE_STRING: - if (type->is_binary()) { + if (base_type->is_binary()) { return "GByteArray *"; } else { return "gchar *"; @@ -663,7 +676,8 @@ string t_c_glib_generator::base_type_name(t_base_type* type) { case t_base_type::TYPE_DOUBLE: return "gdouble"; default: - throw "compiler error: no C base type name for base type " + t_base_type::t_base_name(tbase); + throw std::logic_error("compiler error: no C base type name for base type " + + t_base_type::t_base_name(tbase)); } } @@ -809,8 +823,7 @@ string t_c_glib_generator::constant_value(string name, t_type* type, t_const_val } } else if (type->is_enum()) { render << "(" << type_name(type) << ")" << value->get_integer(); - } else if (type->is_struct() || type->is_xception() || type->is_list() || type->is_set() - || type->is_map()) { + } else if (is_complex_type(type)) { render << "(" << this->nspace_lc << to_lower_case(name) << "_constant())"; } else { render << "NULL /* not supported */"; @@ -944,16 +957,34 @@ string t_c_glib_generator::declare_field(t_field* tfield, return result; } +string t_c_glib_generator::constant_value_with_storage(string fname, + t_type* etype, + t_const_value* value) { + ostringstream render; + if (is_numeric(etype)) { + render << " " << type_name(etype) << " *" << fname << " = " + << "g_new (" << base_type_name(etype) << ", 1);" << endl + << " *" << fname << " = " << constant_value(fname, (t_type*)etype, value) << ";" + << endl; + } else { + render << " " << type_name(etype) << " " << fname << " = " + << constant_value(fname, (t_type*)etype, value) << ";" << endl; + } + return render.str(); +} + /** * Generates C code that initializes complex constants. */ void t_c_glib_generator::generate_const_initializer(string name, t_type* type, - t_const_value* value) { + t_const_value* value, + bool top_level) { string name_u = initial_caps_to_underscores(name); string name_lc = to_lower_case(name_u); string type_u = initial_caps_to_underscores(type->get_name()); string type_uc = to_upper_case(type_u); + string maybe_static = top_level ? "" : "static "; if (type->is_struct() || type->is_xception()) { const vector<t_field*>& fields = ((t_struct*)type)->get_members(); @@ -971,6 +1002,7 @@ void t_c_glib_generator::generate_const_initializer(string name, if ((*f_iter)->get_name() == v_iter->first->get_string()) { field_type = (*f_iter)->get_type(); field_name = (*f_iter)->get_name(); + break; } } if (field_type == NULL) { @@ -991,7 +1023,7 @@ void t_c_glib_generator::generate_const_initializer(string name, } // implement the initializer - f_types_impl_ << "static " << this->nspace << type->get_name() << " *" + f_types_impl_ << maybe_static << this->nspace << type->get_name() << " *" << endl << this->nspace_lc << name_lc << "_constant (void)" << endl; scope_up(f_types_impl_); @@ -1003,13 +1035,33 @@ void t_c_glib_generator::generate_const_initializer(string name, << "TYPE_" << type_uc << ", NULL);" << endl << initializers.str(); scope_down(f_types_impl_); + + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + t_type* field_type = NULL; + string field_name = ""; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_name() == v_iter->first->get_string()) { + field_type = (*f_iter)->get_type(); + field_name = (*f_iter)->get_name(); + break; + } + } + if (field_type == NULL) { + throw "type error: " + type->get_name() + " has no field " + + v_iter->first->get_string(); + } + field_name = tmp(field_name); + } + f_types_impl_ << indent() << "return constant;" << endl; scope_down(f_types_impl_); f_types_impl_ << endl; } else if (type->is_list()) { string list_type = "GPtrArray *"; - // TODO: This initialization should contain a free function for container - string list_initializer = "g_ptr_array_new();"; + string free_func + = generate_free_func_from_type(reinterpret_cast<t_list*>(type)->get_elem_type()); + string list_initializer = "g_ptr_array_new_with_free_func (" + free_func + ");"; string list_appender = "g_ptr_array_add"; bool list_variable = false; @@ -1040,6 +1092,10 @@ void t_c_glib_generator::generate_const_initializer(string name, default: throw "compiler error: no array info for type"; } + } else if (etype->is_enum()) { + list_type = "GArray *"; + list_appender = "g_array_append_val"; + list_variable = true; } for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { @@ -1059,7 +1115,7 @@ void t_c_glib_generator::generate_const_initializer(string name, } } - f_types_impl_ << "static " << list_type << endl + f_types_impl_ << maybe_static << list_type << endl << this->nspace_lc << name_lc << "_constant (void)" << endl; scope_up(f_types_impl_); f_types_impl_ << indent() << "static " << list_type << " constant = NULL;" @@ -1085,26 +1141,20 @@ void t_c_glib_generator::generate_const_initializer(string name, for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { string fname = tmp(name); + string ptr = is_numeric(etype) ? "*" : ""; generate_const_initializer(fname, etype, (*v_iter)); - initializers << " " << type_name(etype) << " " << fname << " = " - << constant_value(fname, (t_type*)etype, (*v_iter)) << ";" - << endl; - appenders << " g_hash_table_insert (constant, &" << fname << ", &" - << fname << ");" << endl; + initializers << constant_value_with_storage(fname, (t_type*)etype, *v_iter); + appenders << " g_hash_table_insert (constant, " << fname << ", 0);" << endl; } - f_types_impl_ << "static GHashTable *" << endl + f_types_impl_ << maybe_static << "GHashTable *" << endl << this->nspace_lc << name_lc << "_constant (void)" << endl; scope_up(f_types_impl_); f_types_impl_ << indent() << "static GHashTable *constant = NULL;" << endl << indent() << "if (constant == NULL)" << endl; scope_up(f_types_impl_); - f_types_impl_ << initializers.str() - << endl - // TODO: This initialization should contain a free function - // for elements - << indent() << "constant = g_hash_table_new (NULL, NULL);" - << endl + f_types_impl_ << initializers.str() << endl + << indent() << "constant = " << generate_new_hash_from_type(etype, NULL) << endl << appenders.str(); scope_down(f_types_impl_); f_types_impl_ << indent() << "return constant;" << endl; @@ -1113,8 +1163,8 @@ void t_c_glib_generator::generate_const_initializer(string name, } else if (type->is_map()) { t_type* ktype = ((t_map*)type)->get_key_type(); t_type* vtype = ((t_map*)type)->get_val_type(); - const vector<t_const_value*>& val = value->get_list(); - vector<t_const_value*>::const_iterator v_iter; + const map<t_const_value*, t_const_value*>& val = value->get_map(); + map<t_const_value*, t_const_value*>::const_iterator v_iter; ostringstream initializers; ostringstream appenders; @@ -1122,32 +1172,22 @@ void t_c_glib_generator::generate_const_initializer(string name, string fname = tmp(name); string kname = fname + "key"; string vname = fname + "val"; - generate_const_initializer(kname, ktype, (*v_iter)); - generate_const_initializer(vname, vtype, (*v_iter)); - - initializers << " " << type_name(ktype) << " " << kname << " = " - << constant_value(kname, (t_type*)ktype, (*v_iter)) << ";" - << endl - << " " << type_name(vtype) << " " << vname << " = " - << constant_value(vname, (t_type*)vtype, (*v_iter)) << ";" - << endl; - appenders << " g_hash_table_insert (constant, &" << fname << ", &" - << fname << ");" - << endl; + generate_const_initializer(kname, ktype, v_iter->first); + generate_const_initializer(vname, vtype, v_iter->second); + + initializers << constant_value_with_storage(kname, (t_type*)ktype, v_iter->first); + initializers << constant_value_with_storage(vname, (t_type*)vtype, v_iter->second); + appenders << " g_hash_table_insert (constant, " << kname << ", " << vname << ");" << endl; } - f_types_impl_ << "static GHashTable *" << endl + f_types_impl_ << maybe_static << "GHashTable *" << endl << this->nspace_lc << name_lc << "_constant (void)" << endl; scope_up(f_types_impl_); f_types_impl_ << indent() << "static GHashTable *constant = NULL;" << endl << indent() << "if (constant == NULL)" << endl; scope_up(f_types_impl_); - f_types_impl_ << initializers.str() - << endl - // TODO: This initialization should contain a free function - // for elements - << indent() << "constant = g_hash_table_new (NULL, NULL);" - << endl + f_types_impl_ << initializers.str() << endl + << indent() << "constant = " << generate_new_hash_from_type(ktype, vtype) << endl << appenders.str(); scope_down(f_types_impl_); f_types_impl_ << indent() << "return constant;" << endl; @@ -2334,8 +2374,7 @@ void t_c_glib_generator::generate_service_processor(t_service* tservice) { t_type* elem_type = ((t_list*)return_type)->get_elem_type(); f_service_ << indent(); - if ((elem_type->is_base_type() && !elem_type->is_string()) - || elem_type->is_enum()) { + if (is_numeric(elem_type)) { f_service_ << "g_array_unref"; } else { f_service_ << "g_ptr_array_unref"; @@ -2470,8 +2509,7 @@ void t_c_glib_generator::generate_service_processor(t_service* tservice) { t_type* elem_type = ((t_list*)arg_type)->get_elem_type(); f_service_ << indent(); - if ((elem_type->is_base_type() && !elem_type->is_string()) - || elem_type->is_enum()) { + if (is_numeric(elem_type)) { f_service_ << "g_array_unref"; } else { f_service_ << "g_ptr_array_unref"; @@ -2650,7 +2688,7 @@ void t_c_glib_generator::generate_service_processor(t_service* tservice) { scope_up(f_service_); f_service_ << indent() << this->nspace << service_name_ << "Processor *self = " << this->nspace_uc << service_name_uc << "_PROCESSOR (gobject);" << endl << endl << indent() - << "g_hash_table_destroy (self->process_map);" << endl << endl << indent() + << "thrift_safe_hash_table_destroy (self->process_map);" << endl << endl << indent() << "G_OBJECT_CLASS (" << class_name_lc << "_parent_class)" "->finalize (gobject);" << endl; scope_down(f_service_); @@ -2894,7 +2932,7 @@ void t_c_glib_generator::generate_object(t_struct* tstruct) { // Lists of base types other than strings are represented as GArrays; // all others as GPtrArrays - if (elem_type->is_base_type() && !elem_type->is_string()) { + if (is_numeric(elem_type)) { release_function_name = "g_array_unref"; } else { release_function_name = "g_ptr_array_unref"; @@ -3125,8 +3163,7 @@ void t_c_glib_generator::generate_object(t_struct* tstruct) { if (t->is_list()) { const vector<t_const_value*>& list = member_value->get_list(); - if ((etype->is_base_type() && !etype->is_string()) - || etype->is_enum()) { + if (is_numeric(etype)) { indent(f_types_impl_) << "g_array_append_vals (object->" << name << ", &__default_" << name << ", " << list.size() << ");" << endl; @@ -3202,6 +3239,8 @@ void t_c_glib_generator::generate_object(t_struct* tstruct) { default: throw "compiler error: no array info for type"; } + } else if (etype->is_enum()) { + destructor_function = "g_array_unref"; } f_types_impl_ << indent() << "if (tobject->" << name << " != NULL)" << endl; @@ -3687,8 +3726,8 @@ void t_c_glib_generator::generate_serialize_field(ofstream& out, break; case t_base_type::TYPE_STRING: if (((t_base_type*)type)->is_binary()) { - out << "binary (protocol, ((GByteArray *) " << name << ")->data, ((GByteArray *) " << name - << ")->len"; + out << "binary (protocol, " << name << " ? ((GByteArray *) " << name << ")->data : NULL, " + << name << " ? ((GByteArray *) " << name << ")->len : 0"; } else { out << "string (protocol, " << name; } @@ -3696,17 +3735,15 @@ void t_c_glib_generator::generate_serialize_field(ofstream& out, default: throw "compiler error: no C writer for base type " + t_base_type::t_base_name(tbase) + name; } - } else if (type->is_enum()) { + } else { out << "i32 (protocol, (gint32) " << name; } out << ", error)) < 0)" << endl << indent() << " return " << error_ret << ";" << endl - << indent() << "xfer += ret;" << endl - << endl; + << indent() << "xfer += ret;" << endl << endl; } else { - printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s' TYPE '%s'\n", - name.c_str(), - type_name(type).c_str()); + throw std::logic_error("DO NOT KNOW HOW TO SERIALIZE FIELD '" + name + "' TYPE '" + + type_name(type)); } } @@ -3737,8 +3774,8 @@ void t_c_glib_generator::generate_serialize_container(ofstream& out, string keyname = tmp("key"); string valname = tmp("val"); - declare_local_variable(out, tkey, keyname); - declare_local_variable(out, tval, valname); + declore_local_variable_for_write(out, tkey, keyname); + declore_local_variable_for_write(out, tval, valname); /* If either the key or value type is a typedef, find its underlying type so we can correctly determine how to generate a pointer to it */ @@ -3906,62 +3943,20 @@ void t_c_glib_generator::generate_serialize_list_element(ofstream& out, string cast = ""; string name = "g_ptr_array_index ((GPtrArray *) " + list + ", " + index + ")"; - if (ttype->is_base_type()) { - t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base(); - switch (tbase) { - case t_base_type::TYPE_VOID: - throw "compiler error: cannot determine array type"; - break; - case t_base_type::TYPE_BOOL: - name = "g_array_index (" + list + ", gboolean, " + index + ")"; - break; - case t_base_type::TYPE_I8: - name = "g_array_index (" + list + ", gint8, " + index + ")"; - break; - case t_base_type::TYPE_I16: - name = "g_array_index (" + list + ", gint16, " + index + ")"; - break; - case t_base_type::TYPE_I32: - name = "g_array_index (" + list + ", gint32, " + index + ")"; - break; - case t_base_type::TYPE_I64: - name = "g_array_index (" + list + ", gint64, " + index + ")"; - break; - case t_base_type::TYPE_DOUBLE: - name = "g_array_index (" + list + ", gdouble, " + index + ")"; - break; - case t_base_type::TYPE_STRING: - cast = "(gchar*)"; - break; - default: - throw "compiler error: no array info for type"; - } + if (ttype->is_void()) { + throw std::runtime_error("compiler error: list element type cannot be void"); + } else if (is_numeric(ttype)) { + name = "g_array_index (" + list + ", " + base_type_name(ttype) + ", " + index + ")"; + } else if (ttype->is_string()) { + cast = "(gchar*)"; } else if (ttype->is_map() || ttype->is_set()) { cast = "(GHashTable*)"; } else if (ttype->is_list()) { - t_type* base = ((t_list*)ttype)->get_elem_type(); - if (base->is_base_type()) { - switch (((t_base_type*)base)->get_base()) { - case t_base_type::TYPE_VOID: - throw "compiler error: cannot determine array type"; - break; - case t_base_type::TYPE_BOOL: - case t_base_type::TYPE_I8: - case t_base_type::TYPE_I16: - case t_base_type::TYPE_I32: - case t_base_type::TYPE_I64: - case t_base_type::TYPE_DOUBLE: - cast = "(GArray*)"; - break; - case t_base_type::TYPE_STRING: - cast = "(GPtrArray*)"; - break; - default: - throw "Compiler error: no array info for type"; - } - } else { - cast = "(GPtrArray*)"; + t_type* etype = ((t_list*)ttype)->get_elem_type(); + if (etype->is_void()) { + throw std::runtime_error("compiler error: list element type cannot be void"); } + cast = is_numeric(etype) ? "(GArray*)" : "(GPtrArray*)"; } t_field efield(ttype, "(" + cast + name + ")"); @@ -3978,7 +3973,8 @@ void t_c_glib_generator::generate_deserialize_field(ofstream& out, t_type* type = get_true_type(tfield->get_type()); if (type->is_void()) { - throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name(); + throw std::runtime_error("CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + + tfield->get_name()); } string name = prefix + tfield->get_name() + suffix; @@ -4047,9 +4043,8 @@ void t_c_glib_generator::generate_deserialize_field(ofstream& out, << indent() << " return " << error_ret << ";" << endl << indent() << "xfer += ret;" << endl << indent() << name << " = (" << type_name(type) << ")" << t << ";" << endl; } else { - printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n", - tfield->get_name().c_str(), - type_name(type).c_str()); + throw std::logic_error("DO NOT KNOW HOW TO SERIALIZE FIELD '" + tfield->get_name() + "' TYPE '" + + type_name(type)); } // if the type is not required and this is a thrift struct (no prefix), @@ -4196,14 +4191,13 @@ void t_c_glib_generator::generate_deserialize_container(ofstream& out, scope_down(out); } -void t_c_glib_generator::declare_local_variable(ofstream& out, t_type* ttype, string& name) { +void t_c_glib_generator::declare_local_variable(ofstream& out, t_type* ttype, string& name, bool for_hash_table) { string tname = type_name(ttype); /* If the given type is a typedef, find its underlying type so we can correctly determine how to generate a pointer to it */ ttype = get_true_type(ttype); - - string ptr = ttype->is_string() || !ttype->is_base_type() ? "" : "*"; + string ptr = !is_numeric(ttype) ? "" : "*"; if (ttype->is_map()) { t_map* tmap = (t_map*)ttype; @@ -4213,14 +4207,24 @@ void t_c_glib_generator::declare_local_variable(ofstream& out, t_type* ttype, st t_list* tlist = (t_list*)ttype; out << indent() << tname << ptr << " " << name << " = " << generate_new_array_from_type(tlist->get_elem_type()) << endl; - } else if (ttype->is_enum()) { - out << indent() << tname << ptr << " " << name << ";" << endl; + } else if (for_hash_table && ttype->is_enum()) { + out << indent() << tname << " " << name << ";" << endl; } else { out << indent() << tname << ptr << " " << name << (ptr != "" ? " = g_new (" + tname + ", 1)" : " = NULL") << ";" << endl; } } +void t_c_glib_generator::declore_local_variable_for_write(ofstream& out, + t_type* ttype, + string& name) { + string tname = type_name(ttype); + ttype = get_true_type(ttype); + string ptr = ttype->is_string() || !ttype->is_base_type() ? " " : "* "; + string init_val = ttype->is_enum() ? "" : " = NULL"; + out << indent() << tname << ptr << name << init_val << ";" << endl; +} + void t_c_glib_generator::generate_deserialize_map_element(ofstream& out, t_map* tmap, string prefix, @@ -4230,8 +4234,8 @@ void t_c_glib_generator::generate_deserialize_map_element(ofstream& out, string keyname = tmp("key"); string valname = tmp("val"); - declare_local_variable(out, tkey, keyname); - declare_local_variable(out, tval, valname); + declare_local_variable(out, tkey, keyname, true); + declare_local_variable(out, tval, valname, true); /* If either the key or value type is a typedef, find its underlying type so we can correctly determine how to generate a pointer to @@ -4248,8 +4252,11 @@ void t_c_glib_generator::generate_deserialize_map_element(ofstream& out, t_field fval(tval, tval_ptr + valname); generate_deserialize_field(out, &fval, "", "", error_ret); + indent(out) << "if (" << prefix << " && " << keyname << ")" << endl; + indent_up(); indent(out) << "g_hash_table_insert ((GHashTable *)" << prefix << ", (gpointer) " << keyname << ", (gpointer) " << valname << ");" << endl; + indent_down(); } void t_c_glib_generator::generate_deserialize_set_element(ofstream& out, @@ -4260,13 +4267,16 @@ void t_c_glib_generator::generate_deserialize_set_element(ofstream& out, string elem = tmp("_elem"); string telem_ptr = telem->is_string() || !telem->is_base_type() ? "" : "*"; - declare_local_variable(out, telem, elem); + declare_local_variable(out, telem, elem, true); t_field felem(telem, telem_ptr + elem); generate_deserialize_field(out, &felem, "", "", error_ret); + indent(out) << "if (" << prefix << " && " << elem << ")" << endl; + indent_up(); indent(out) << "g_hash_table_insert ((GHashTable *) " << prefix << ", (gpointer) " << elem - << ", (gpointer) 1);" << endl; + << ", (gpointer) " << elem << ");" << endl; + indent_down(); } void t_c_glib_generator::generate_deserialize_list_element(ofstream& out, @@ -4275,38 +4285,22 @@ void t_c_glib_generator::generate_deserialize_list_element(ofstream& out, string index, int error_ret) { (void)index; - t_type* ttype = tlist->get_elem_type(); + t_type* ttype = get_true_type(tlist->get_elem_type()); string elem = tmp("_elem"); - string telem_ptr = ttype->is_string() || !ttype->is_base_type() ? "" : "*"; + string telem_ptr = !is_numeric(ttype) ? "" : "*"; - declare_local_variable(out, ttype, elem); + declare_local_variable(out, ttype, elem, false); t_field felem(ttype, telem_ptr + elem); generate_deserialize_field(out, &felem, "", "", error_ret); - indent(out); - - if (ttype->is_base_type()) { - t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base(); - switch (tbase) { - case t_base_type::TYPE_VOID: - throw "compiler error: cannot determine array type"; - case t_base_type::TYPE_STRING: - out << "g_ptr_array_add (" << prefix << ", " << elem << ");" << endl; - return; - case t_base_type::TYPE_BOOL: - case t_base_type::TYPE_I8: - case t_base_type::TYPE_I16: - case t_base_type::TYPE_I32: - case t_base_type::TYPE_I64: - case t_base_type::TYPE_DOUBLE: - out << "g_array_append_vals (" << prefix << ", " << elem << ", 1);" << endl; - return; - default: - throw "compiler error: no array info for type"; - } + if (ttype->is_void()) { + throw std::runtime_error("compiler error: list element type cannot be void"); + } else if (is_numeric(ttype)) { + indent(out) << "g_array_append_vals (" << prefix << ", " << elem << ", 1);" << endl; + } else { + indent(out) << "g_ptr_array_add (" << prefix << ", " << elem << ");" << endl; } - out << "g_ptr_array_add (" << prefix << ", " << elem << ");" << endl; } string t_c_glib_generator::generate_free_func_from_type(t_type* ttype) { @@ -4337,7 +4331,7 @@ string t_c_glib_generator::generate_free_func_from_type(t_type* ttype) { } else if (ttype->is_enum()) { return "NULL"; } else if (ttype->is_map() || ttype->is_set()) { - return "(GDestroyNotify) g_hash_table_destroy"; + return "(GDestroyNotify) thrift_safe_hash_table_destroy"; } else if (ttype->is_struct()) { return "g_object_unref"; } else if (ttype->is_list()) { @@ -4386,8 +4380,11 @@ string t_c_glib_generator::generate_hash_func_from_type(t_type* ttype) { throw "compiler error: cannot determine hash type"; break; case t_base_type::TYPE_BOOL: + return "thrift_boolean_hash"; case t_base_type::TYPE_I8: + return "thrift_int8_hash"; case t_base_type::TYPE_I16: + return "thrift_int16_hash"; case t_base_type::TYPE_I32: return "g_int_hash"; case t_base_type::TYPE_I64: @@ -4421,8 +4418,11 @@ string t_c_glib_generator::generate_cmp_func_from_type(t_type* ttype) { throw "compiler error: cannot determine hash type"; break; case t_base_type::TYPE_BOOL: + return "thrift_boolean_equal"; case t_base_type::TYPE_I8: + return "thrift_int8_equal"; case t_base_type::TYPE_I16: + return "thrift_int16_equal"; case t_base_type::TYPE_I32: return "g_int_equal"; case t_base_type::TYPE_I64: @@ -4456,37 +4456,14 @@ string t_c_glib_generator::generate_new_hash_from_type(t_type* key, t_type* valu } string t_c_glib_generator::generate_new_array_from_type(t_type* ttype) { - if (ttype->is_base_type()) { - t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base(); - switch (tbase) { - case t_base_type::TYPE_VOID: - throw "compiler error: cannot determine array type"; - break; - case t_base_type::TYPE_BOOL: - return "g_array_new (0, 1, sizeof (gboolean));"; - case t_base_type::TYPE_I8: - return "g_array_new (0, 1, sizeof (gint8));"; - case t_base_type::TYPE_I16: - return "g_array_new (0, 1, sizeof (gint16));"; - case t_base_type::TYPE_I32: - return "g_array_new (0, 1, sizeof (gint32));"; - case t_base_type::TYPE_I64: - return "g_array_new (0, 1, sizeof (gint64));"; - case t_base_type::TYPE_DOUBLE: - return "g_array_new (0, 1, sizeof (gdouble));"; - case t_base_type::TYPE_STRING: - return "g_ptr_array_new_with_free_func (g_free);"; - default: - throw "compiler error: no array info for type"; - } - } else if (ttype->is_enum()) { - return "g_array_new (0, 1, sizeof (gint32));"; + if (ttype->is_void()) { + throw std::runtime_error("compiler error: cannot determine array type"); + } else if (is_numeric(ttype)) { + return "g_array_new (0, 1, sizeof (" + base_type_name(ttype) + "));"; } else { string free_func = generate_free_func_from_type(ttype); return "g_ptr_array_new_with_free_func (" + free_func + ");"; } - - return "g_ptr_array_new();"; } /*************************************** http://git-wip-us.apache.org/repos/asf/thrift/blob/ba3fe86b/lib/c_glib/src/thrift/c_glib/thrift.c ---------------------------------------------------------------------- diff --git a/lib/c_glib/src/thrift/c_glib/thrift.c b/lib/c_glib/src/thrift/c_glib/thrift.c index 15f409f..8de869f 100644 --- a/lib/c_glib/src/thrift/c_glib/thrift.c +++ b/lib/c_glib/src/thrift/c_glib/thrift.c @@ -31,6 +31,67 @@ thrift_hash_table_get_keys (gpointer key, gpointer value, gpointer user_data) *list = g_list_append (*list, key); } +void thrift_safe_hash_table_destroy(GHashTable* hash_table) +{ + if (hash_table) + { + g_hash_table_destroy(hash_table); + } +} + +guint thrift_boolean_hash(gconstpointer v) +{ + const gboolean* p = v; + return p && *p ? 1 : 0; +} +gboolean thrift_boolean_equal(gconstpointer a, gconstpointer b) +{ + if (a == b) { + return TRUE; + } + if (!a || !b) { + return FALSE; + } + const gboolean* pa = a; + const gboolean* pb = b; + return *pa == *pb; +} + +guint thrift_int8_hash(gconstpointer v) +{ + const gint8* p = v; + return p ? *p : 0; +} +gboolean thrift_int8_equal(gconstpointer a, gconstpointer b) +{ + if (a == b) { + return TRUE; + } + if (!a || !b) { + return FALSE; + } + const gint8* pa = a; + const gint8* pb = b; + return *pa == *pb; +} + +guint thrift_int16_hash(gconstpointer v) +{ + const gint16* p = v; + return p ? *p : 0; +} +gboolean thrift_int16_equal(gconstpointer a, gconstpointer b) +{ + if (a == b) { + return TRUE; + } + if (!a || !b) { + return FALSE; + } + const gint16* pa = a; + const gint16* pb = b; + return *pa == *pb; +} void thrift_string_free (gpointer str) http://git-wip-us.apache.org/repos/asf/thrift/blob/ba3fe86b/lib/c_glib/src/thrift/c_glib/thrift.h ---------------------------------------------------------------------- diff --git a/lib/c_glib/src/thrift/c_glib/thrift.h b/lib/c_glib/src/thrift/c_glib/thrift.h index 858ad86..94a6478 100644 --- a/lib/c_glib/src/thrift/c_glib/thrift.h +++ b/lib/c_glib/src/thrift/c_glib/thrift.h @@ -33,6 +33,17 @@ void thrift_hash_table_get_keys (gpointer key, gpointer value, gpointer user_data); +void thrift_safe_hash_table_destroy(GHashTable* hash_table); + +guint thrift_boolean_hash(gconstpointer v); +gboolean thrift_boolean_equal(gconstpointer a, gconstpointer b); + +guint thrift_int8_hash(gconstpointer v); +gboolean thrift_int8_equal(gconstpointer a, gconstpointer b); + +guint thrift_int16_hash(gconstpointer v); +gboolean thrift_int16_equal(gconstpointer a, gconstpointer b); + void thrift_string_free (gpointer str); #endif /* #ifndef _THRIFT_THRIFT_H */ http://git-wip-us.apache.org/repos/asf/thrift/blob/ba3fe86b/lib/c_glib/test/CMakeLists.txt ---------------------------------------------------------------------- diff --git a/lib/c_glib/test/CMakeLists.txt b/lib/c_glib/test/CMakeLists.txt index 61dc490..48a30d0 100644 --- a/lib/c_glib/test/CMakeLists.txt +++ b/lib/c_glib/test/CMakeLists.txt @@ -28,6 +28,8 @@ include_directories(${Boost_INCLUDE_DIRS}) # Create the thrift C test library set(testgenc_SOURCES gen-c_glib/t_test_debug_proto_test_types.c + gen-c_glib/t_test_enum_test_types.c + gen-c_glib/t_test_enum_test_service.c gen-c_glib/t_test_empty_service.c gen-c_glib/t_test_inherited.c gen-c_glib/t_test_optional_required_test_types.c @@ -38,6 +40,8 @@ set(testgenc_SOURCES gen-c_glib/t_test_thrift_test.c gen-c_glib/t_test_thrift_test_types.c gen-c_glib/t_test_debug_proto_test_types.h + gen-c_glib/t_test_enum_test_types.h + gen-c_glib/t_test_enum_test_service.h gen-c_glib/t_test_empty_service.h gen-c_glib/t_test_inherited.h gen-c_glib/t_test_optional_required_test_types.h @@ -146,6 +150,14 @@ add_custom_command(OUTPUT ) add_custom_command(OUTPUT + gen-c_glib/t_test_enum_test_types.c + gen-c_glib/t_test_enum_test_types.h + gen-c_glib/t_test_enum_test_service.c + gen-c_glib/t_test_enum_test_service.h + COMMAND ${THRIFT_COMPILER} --gen c_glib ${PROJECT_SOURCE_DIR}/test/EnumTest.thrift +) + +add_custom_command(OUTPUT gen-c_glib/t_test_optional_required_test_types.c gen-c_glib/t_test_optional_required_test_types.h COMMAND ${THRIFT_COMPILER} --gen c_glib ${PROJECT_SOURCE_DIR}/test/OptionalRequiredTest.thrift http://git-wip-us.apache.org/repos/asf/thrift/blob/ba3fe86b/lib/c_glib/test/Makefile.am ---------------------------------------------------------------------- diff --git a/lib/c_glib/test/Makefile.am b/lib/c_glib/test/Makefile.am index 555380c..4d35f2a 100755 --- a/lib/c_glib/test/Makefile.am +++ b/lib/c_glib/test/Makefile.am @@ -169,6 +169,8 @@ endif nodist_libtestgenc_la_SOURCES = \ gen-c_glib/t_test_container_test_types.c \ gen-c_glib/t_test_debug_proto_test_types.c \ + gen-c_glib/t_test_enum_test_types.c \ + gen-c_glib/t_test_enum_test_service.c \ gen-c_glib/t_test_empty_service.c \ gen-c_glib/t_test_inherited.c \ gen-c_glib/t_test_optional_required_test_types.c \ @@ -181,6 +183,8 @@ nodist_libtestgenc_la_SOURCES = \ gen-c_glib/t_test_thrift_test_types.c \ gen-c_glib/t_test_container_test_types.h \ gen-c_glib/t_test_debug_proto_test_types.h \ + gen-c_glib/t_test_enum_test_types.h \ + gen-c_glib/t_test_enum_test_service.h \ gen-c_glib/t_test_empty_service.h \ gen-c_glib/t_test_inherited.h \ gen-c_glib/t_test_optional_required_test_types.h \ @@ -211,6 +215,9 @@ gen-c_glib/t_test_container_test_types.c gen-c_glib/t_test_container_test_types. gen-c_glib/t_test_debug_proto_test_types.c gen-c_glib/t_test_debug_proto_test_types.h gen-c_glib/t_test_empty_service.c gen-c_glib/t_test_empty_service.h gen-c_glib/t_test_inherited.c gen-c_glib/t_test_inherited.h gen-c_glib/t_test_reverse_order_service.c gen-c_glib/t_test_reverse_order_service.h gen-c_glib/t_test_service_for_exception_with_a_map.c gen-c_glib/t_test_service_for_exception_with_a_map.h gen-c_glib/t_test_srv.c gen-c_glib/t_test_srv.h: ../../../test/DebugProtoTest.thrift $(THRIFT) --gen c_glib $< +gen-c_glib/t_test_enum_test_types.c gen-c_glib/t_test_enum_test_types.h gen-c_glib/t_test_enum_test_service.c gen-c_glib/t_test_enum_test_service.h : ../../../test/EnumTest.thrift + $(THRIFT) --gen c_glib $< + gen-c_glib/t_test_optional_required_test_types.c gen-c_glib/t_test_optional_required_test_types.h: ../../../test/OptionalRequiredTest.thrift $(THRIFT) --gen c_glib $< http://git-wip-us.apache.org/repos/asf/thrift/blob/ba3fe86b/lib/c_glib/test/testoptionalrequired.c ---------------------------------------------------------------------- diff --git a/lib/c_glib/test/testoptionalrequired.c b/lib/c_glib/test/testoptionalrequired.c index ae0c3d2..cfc96a2 100755 --- a/lib/c_glib/test/testoptionalrequired.c +++ b/lib/c_glib/test/testoptionalrequired.c @@ -187,6 +187,26 @@ test_tricky4 (void) g_object_unref (t3); } +static void +test_non_set_binary (void) +{ + TTestBinaries *b1 = NULL; + TTestBinaries *b2 = NULL; + GError *error = NULL; + + b1 = g_object_new (T_TEST_TYPE_BINARIES, NULL); + b2 = g_object_new (T_TEST_TYPE_BINARIES, NULL); + + write_to_read (THRIFT_STRUCT (b1), THRIFT_STRUCT (b2), NULL, &error); + g_assert(!error); + write_to_read (THRIFT_STRUCT (b2), THRIFT_STRUCT (b1), NULL, &error); + g_assert(!error); + // OK. No segfault + + g_object_unref (b1); + g_object_unref (b2); +} + int main(int argc, char *argv[]) { @@ -202,6 +222,7 @@ main(int argc, char *argv[]) g_test_add_func ("/testoptionalrequired/Tricky2", test_tricky2); g_test_add_func ("/testoptionalrequired/Tricky3", test_tricky3); g_test_add_func ("/testoptionalrequired/Tricky4", test_tricky4); + g_test_add_func ("/testoptionalrequired/Binary", test_non_set_binary); return g_test_run (); } http://git-wip-us.apache.org/repos/asf/thrift/blob/ba3fe86b/lib/c_glib/test/testserialization.c ---------------------------------------------------------------------- diff --git a/lib/c_glib/test/testserialization.c b/lib/c_glib/test/testserialization.c index 0ece2ad..9fc6357 100644 --- a/lib/c_glib/test/testserialization.c +++ b/lib/c_glib/test/testserialization.c @@ -3,6 +3,53 @@ #include <thrift/c_glib/transport/thrift_memory_buffer.h> #include <thrift/c_glib/transport/thrift_transport.h> #include "gen-c_glib/t_test_debug_proto_test_types.h" +#include "gen-c_glib/t_test_enum_test_types.h" + +static void enum_constants_read_write() { + GError* error = NULL; + ThriftTransport* transport + = THRIFT_TRANSPORT(g_object_new(THRIFT_TYPE_MEMORY_BUFFER, "buf_size", 1024, NULL)); + ThriftProtocol* protocol + = THRIFT_PROTOCOL(g_object_new(THRIFT_TYPE_BINARY_PROTOCOL, "transport", transport, NULL)); + TTestEnumTestStruct* src = T_TEST_ENUM_TEST; + TTestEnumTestStruct* dst = g_object_new(T_TEST_TYPE_ENUM_TEST_STRUCT, NULL); + TTestEnumTestStructClass* cls = T_TEST_ENUM_TEST_STRUCT_GET_CLASS(src); + + int write_len = THRIFT_STRUCT_CLASS(cls)->write(THRIFT_STRUCT(src), protocol, &error); + g_assert(!error); + g_assert(write_len > 0); + + int read_len = THRIFT_STRUCT_CLASS(cls)->read(THRIFT_STRUCT(dst), protocol, &error); + g_assert(!error); + g_assert_cmpint(write_len, ==, read_len); + + g_object_unref(dst); + g_object_unref(protocol); + g_object_unref(transport); +} + +static void struct_constants_read_write() { + GError* error = NULL; + ThriftTransport* transport + = THRIFT_TRANSPORT(g_object_new(THRIFT_TYPE_MEMORY_BUFFER, "buf_size", 4096, NULL)); + ThriftProtocol* protocol + = THRIFT_PROTOCOL(g_object_new(THRIFT_TYPE_BINARY_PROTOCOL, "transport", transport, NULL)); + TTestCompactProtoTestStruct* src = T_TEST_COMPACT_TEST; + TTestCompactProtoTestStruct* dst = g_object_new(T_TEST_TYPE_COMPACT_PROTO_TEST_STRUCT, NULL); + TTestCompactProtoTestStructClass* cls = T_TEST_COMPACT_PROTO_TEST_STRUCT_GET_CLASS(src); + + int write_len = THRIFT_STRUCT_CLASS(cls)->write(THRIFT_STRUCT(src), protocol, &error); + g_assert(!error); + g_assert(write_len > 0); + + int read_len = THRIFT_STRUCT_CLASS(cls)->read(THRIFT_STRUCT(dst), protocol, &error); + g_assert(!error); + g_assert_cmpint(write_len, ==, read_len); + + g_object_unref(dst); + g_object_unref(protocol); + g_object_unref(transport); +} static void struct_read_write_length_should_equal() { GError* error = NULL; @@ -36,5 +83,7 @@ int main(int argc, char* argv[]) { g_test_add_func("/testserialization/StructReadWriteLengthShouldEqual", struct_read_write_length_should_equal); + g_test_add_func("/testserialization/StructConstants", struct_constants_read_write); + g_test_add_func("/testserialization/EnumConstants", enum_constants_read_write); return g_test_run(); } http://git-wip-us.apache.org/repos/asf/thrift/blob/ba3fe86b/test/EnumTest.thrift ---------------------------------------------------------------------- diff --git a/test/EnumTest.thrift b/test/EnumTest.thrift index 6201923..17af408 100644 --- a/test/EnumTest.thrift +++ b/test/EnumTest.thrift @@ -21,6 +21,8 @@ * details. */ +namespace c_glib TTest + enum MyEnum1 { ME1_0 = 0, ME1_1 = 1, @@ -70,3 +72,38 @@ struct MyStruct { 3: MyEnum3 me3_d1 = MyEnum3.ME3_D1 } +struct EnumTestStruct { + 1: MyEnum3 a_enum; + 2: list<MyEnum3> enum_list; + 3: set<MyEnum3> enum_set; + 4: map<MyEnum3, MyEnum3> enum_enum_map; + // collections as keys + 44: map<list<MyEnum3> (python.immutable = ""), MyEnum3> list_enum_map; + 45: map<set<MyEnum3> (python.immutable = ""), MyEnum3> set_enum_map; + 46: map<map<MyEnum3,MyEnum3> (python.immutable = ""), MyEnum3> map_enum_map; + // collections as values + 47: map<MyEnum3, map<MyEnum3, MyEnum3>> enum_map_map; + 48: map<MyEnum3, set<MyEnum3>> enum_set_map; + 49: map<MyEnum3, list<MyEnum3>> enum_list_map; +} + +const EnumTestStruct ENUM_TEST = { + 'a_enum': MyEnum3.ME3_D1, + 'enum_list': [MyEnum3.ME3_D1, MyEnum3.ME3_0, MyEnum3.ME3_N2], + 'enum_set': [MyEnum3.ME3_D1, MyEnum3.ME3_N1], + 'enum_enum_map': {MyEnum3.ME3_D1: MyEnum3.ME3_0, MyEnum3.ME3_0: MyEnum3.ME3_D1}, + 'list_enum_map': {[MyEnum3.ME3_D1, MyEnum3.ME3_0]: MyEnum3.ME3_0, [MyEnum3.ME3_D1]: MyEnum3.ME3_0, [MyEnum3.ME3_0]: MyEnum3.ME3_D1}, + 'set_enum_map': {[MyEnum3.ME3_D1, MyEnum3.ME3_0]: MyEnum3.ME3_0, [MyEnum3.ME3_D1]: MyEnum3.ME3_0}, + 'map_enum_map': {{MyEnum3.ME3_N1: MyEnum3.ME3_10}: MyEnum3.ME3_1}, + 'enum_map_map': {MyEnum3.ME3_N1: {MyEnum3.ME3_D1: MyEnum3.ME3_D1}}, + 'enum_set_map': {MyEnum3.ME3_N2: [MyEnum3.ME3_D1, MyEnum3.ME3_N1], MyEnum3.ME3_10: [MyEnum3.ME3_D1, MyEnum3.ME3_N1]}, + 'enum_list_map': {MyEnum3.ME3_D1: [MyEnum3.ME3_10], MyEnum3.ME3_0: [MyEnum3.ME3_9, MyEnum3.ME3_10]}, +} + +service EnumTestService { + MyEnum3 testEnum(1: MyEnum3 enum1), + list<MyEnum3> testEnumList(1: list<MyEnum3> enum1), + set<MyEnum3> testEnumSet(1: set<MyEnum3> enum1), + map<MyEnum3, MyEnum3> testEnumMap(1: map<MyEnum3, MyEnum3> enum1), + EnumTestStruct testEnumStruct(1: EnumTestStruct enum1), +} http://git-wip-us.apache.org/repos/asf/thrift/blob/ba3fe86b/test/OptionalRequiredTest.thrift ---------------------------------------------------------------------- diff --git a/test/OptionalRequiredTest.thrift b/test/OptionalRequiredTest.thrift index dcdd0f2..a608898 100644 --- a/test/OptionalRequiredTest.thrift +++ b/test/OptionalRequiredTest.thrift @@ -80,3 +80,9 @@ struct JavaTestHelper { 5: required binary req_bin; 6: optional binary opt_bin; } + +struct Binaries { + 4: binary bin; + 5: required binary req_bin; + 6: optional binary opt_bin; +} http://git-wip-us.apache.org/repos/asf/thrift/blob/ba3fe86b/test/c_glib/src/thrift_test_handler.c ---------------------------------------------------------------------- diff --git a/test/c_glib/src/thrift_test_handler.c b/test/c_glib/src/thrift_test_handler.c index 69ddbc1..86b29dd 100644 --- a/test/c_glib/src/thrift_test_handler.c +++ b/test/c_glib/src/thrift_test_handler.c @@ -144,6 +144,7 @@ thrift_test_handler_test_binary (TTestThriftTestIf *iface, THRIFT_UNUSED_VAR (error); printf ("testBinary()\n"); // TODO: hex output + g_byte_array_ref(thing); *_return = thing; return TRUE;
