diff options
62 files changed, 740 insertions, 137 deletions
diff --git a/.gitignore b/.gitignore index 6278185b2..85b694cad 100644 --- a/.gitignore +++ b/.gitignore @@ -201,9 +201,9 @@ project.lock.json /lib/delphi/*.local /lib/delphi/*.identcache /lib/delphi/test/skip/bin -/lib/delphi/test/serializer/*.dat +/lib/delphi/test/serializer/**/*.dat /lib/delphi/test/serializer/bin -/lib/delphi/test/thrift-testing +/lib/delphi/test/thrift-testing/*.thrift /lib/delphi/**/*.identcache /lib/delphi/**/*.local /lib/delphi/**/*.dcu diff --git a/compiler/cpp/src/thrift/common.cc b/compiler/cpp/src/thrift/common.cc index 6dcd85500..3a28407a4 100644 --- a/compiler/cpp/src/thrift/common.cc +++ b/compiler/cpp/src/thrift/common.cc @@ -23,6 +23,7 @@ t_type* g_type_void; t_type* g_type_string; t_type* g_type_binary; +t_type* g_type_uuid; t_type* g_type_bool; t_type* g_type_i8; t_type* g_type_i16; @@ -35,6 +36,7 @@ void initGlobals() { g_type_string = new t_base_type("string", t_base_type::TYPE_STRING); g_type_binary = new t_base_type("string", t_base_type::TYPE_STRING); ((t_base_type*)g_type_binary)->set_binary(true); + g_type_uuid = new t_base_type("string", t_base_type::TYPE_UUID); g_type_bool = new t_base_type("bool", t_base_type::TYPE_BOOL); g_type_i8 = new t_base_type("i8", t_base_type::TYPE_I8); g_type_i16 = new t_base_type("i16", t_base_type::TYPE_I16); @@ -46,6 +48,8 @@ void initGlobals() { void clearGlobals() { delete g_type_void; delete g_type_string; + delete g_type_binary; + delete g_type_uuid; delete g_type_bool; delete g_type_i8; delete g_type_i16; diff --git a/compiler/cpp/src/thrift/common.h b/compiler/cpp/src/thrift/common.h index 06392cda7..059421df1 100644 --- a/compiler/cpp/src/thrift/common.h +++ b/compiler/cpp/src/thrift/common.h @@ -29,6 +29,7 @@ extern t_type* g_type_void; extern t_type* g_type_string; extern t_type* g_type_binary; +extern t_type* g_type_uuid; extern t_type* g_type_bool; extern t_type* g_type_i8; extern t_type* g_type_i16; diff --git a/compiler/cpp/src/thrift/generate/t_c_glib_generator.cc b/compiler/cpp/src/thrift/generate/t_c_glib_generator.cc index 8cb82c180..4ce9c5fdc 100644 --- a/compiler/cpp/src/thrift/generate/t_c_glib_generator.cc +++ b/compiler/cpp/src/thrift/generate/t_c_glib_generator.cc @@ -723,6 +723,8 @@ string t_c_glib_generator::type_to_enum(t_type* type) { return "T_I64"; case t_base_type::TYPE_DOUBLE: return "T_DOUBLE"; + default: + break; } } else if (type->is_enum()) { return "T_I32"; diff --git a/compiler/cpp/src/thrift/generate/t_cpp_generator.cc b/compiler/cpp/src/thrift/generate/t_cpp_generator.cc index d9898b7c5..0420e62e7 100644 --- a/compiler/cpp/src/thrift/generate/t_cpp_generator.cc +++ b/compiler/cpp/src/thrift/generate/t_cpp_generator.cc @@ -689,7 +689,7 @@ void t_cpp_generator::generate_enum_to_string_helper_function(std::ostream& out, out << tenum->get_name() << "::type&"; } out << " val) " ; - scope_up(out); + scope_up(out); out << indent() << "std::map<int, const char*>::const_iterator it = _" << tenum->get_name() << "_VALUES_TO_NAMES.find(val);" << endl; @@ -1221,7 +1221,7 @@ void t_cpp_generator::generate_struct_declaration(ostream& out, // Declare all fields for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { - generate_java_doc(out, *m_iter); + generate_java_doc(out, *m_iter); indent(out) << declare_field(*m_iter, false, (pointers && !(*m_iter)->get_type()->is_xception()), @@ -2475,11 +2475,11 @@ void t_cpp_generator::generate_service_client(t_service* tservice, string style) indent_up(); if (style != "Cob") { f_header_ << indent() << service_name_ << style << "Client" << short_suffix << "(" << prot_ptr - << " prot"; - if (style == "Concurrent") { - f_header_ << ", std::shared_ptr< ::apache::thrift::async::TConcurrentClientSyncInfo> sync"; - } - f_header_ << ") "; + << " prot"; + if (style == "Concurrent") { + f_header_ << ", std::shared_ptr< ::apache::thrift::async::TConcurrentClientSyncInfo> sync"; + } + f_header_ << ") "; if (extends.empty()) { if (style == "Concurrent") { @@ -2498,12 +2498,12 @@ void t_cpp_generator::generate_service_client(t_service* tservice, string style) } f_header_ << indent() << service_name_ << style << "Client" << short_suffix << "(" << prot_ptr - << " iprot, " << prot_ptr << " oprot"; - if (style == "Concurrent") { - f_header_ << ", std::shared_ptr< ::apache::thrift::async::TConcurrentClientSyncInfo> sync"; - } - f_header_ << ") "; - + << " iprot, " << prot_ptr << " oprot"; + if (style == "Concurrent") { + f_header_ << ", std::shared_ptr< ::apache::thrift::async::TConcurrentClientSyncInfo> sync"; + } + f_header_ << ") "; + if (extends.empty()) { if (style == "Concurrent") { f_header_ << ": sync_(sync)" << endl; @@ -4660,6 +4660,8 @@ string t_cpp_generator::type_to_enum(t_type* type) { return "::apache::thrift::protocol::T_I64"; case t_base_type::TYPE_DOUBLE: return "::apache::thrift::protocol::T_DOUBLE"; + default: + break; } } else if (type->is_enum()) { return "::apache::thrift::protocol::T_I32"; diff --git a/compiler/cpp/src/thrift/generate/t_d_generator.cc b/compiler/cpp/src/thrift/generate/t_d_generator.cc index afae5b53d..f9e485642 100644 --- a/compiler/cpp/src/thrift/generate/t_d_generator.cc +++ b/compiler/cpp/src/thrift/generate/t_d_generator.cc @@ -74,9 +74,9 @@ protected: // D reserved words are suffixed with an underscore static string suffix_if_reserved(const string& name) { - const bool isIn = std::binary_search(std::begin(d_reserved_words), std::end(d_reserved_words), name); - string ret = isIn ? name + "_" : name; - return ret; + const bool isIn = std::binary_search(std::begin(d_reserved_words), std::end(d_reserved_words), name); + string ret = isIn ? name + "_" : name; + return ret; } void init_generator() override { @@ -403,8 +403,8 @@ private: out << indent() << "// Your implementation goes here." << endl << indent() << "writeln(\"" << suffix_if_reserved((*f_iter)->get_name()) << " called\");" << endl; - t_type* rt = (*f_iter)->get_returntype(); - if (!rt->is_void()) { + t_type* rt = (*f_iter)->get_returntype(); + if (!rt->is_void()) { indent(out) << "return typeof(return).init;" << endl; } diff --git a/compiler/cpp/src/thrift/generate/t_dart_generator.cc b/compiler/cpp/src/thrift/generate/t_dart_generator.cc index 65d0f535f..61cd98167 100644 --- a/compiler/cpp/src/thrift/generate/t_dart_generator.cc +++ b/compiler/cpp/src/thrift/generate/t_dart_generator.cc @@ -2216,6 +2216,8 @@ string t_dart_generator::declare_field(t_field* tfield, bool init) { case t_base_type::TYPE_DOUBLE: result += " = 0.0"; break; + default: + throw "compiler error: unhandled type"; } } else if (ttype->is_enum()) { @@ -2297,6 +2299,8 @@ string t_dart_generator::type_to_enum(t_type* type) { return "TType.I64"; case t_base_type::TYPE_DOUBLE: return "TType.DOUBLE"; + default: + break; } } else if (type->is_enum()) { return "TType.I32"; @@ -2351,6 +2355,8 @@ std::string t_dart_generator::init_value(t_field* field) { case t_base_type::TYPE_STRING: result = ""; break; + default: + throw "compiler error: unhandled type"; } return result; diff --git a/compiler/cpp/src/thrift/generate/t_delphi_generator.cc b/compiler/cpp/src/thrift/generate/t_delphi_generator.cc index 2d0af119f..f35ffcb99 100644 --- a/compiler/cpp/src/thrift/generate/t_delphi_generator.cc +++ b/compiler/cpp/src/thrift/generate/t_delphi_generator.cc @@ -1024,6 +1024,7 @@ void t_delphi_generator::init_known_types_list() { // known base types types_known[type_name(g_type_string)] = 1; types_known[type_name(g_type_binary)] = 1; + types_known[type_name(g_type_uuid)] = 1; types_known[type_name(g_type_bool)] = 1; types_known[type_name(g_type_i8)] = 1; types_known[type_name(g_type_i16)] = 1; @@ -1398,6 +1399,9 @@ string t_delphi_generator::render_const_value(ostream& vars, case t_base_type::TYPE_STRING: render << "'" << get_escaped_string(value) << "'"; break; + case t_base_type::TYPE_UUID: + render << "['{" << value->get_uuid() << "}']"; + break; case t_base_type::TYPE_BOOL: render << ((value->get_integer() > 0) ? "True" : "False"); break; @@ -2709,6 +2713,9 @@ void t_delphi_generator::generate_deserialize_field(ostream& out, out << "ReadString();"; } break; + case t_base_type::TYPE_UUID: + out << "ReadUuid();"; + break; case t_base_type::TYPE_BOOL: out << "ReadBool();"; break; @@ -2910,6 +2917,9 @@ void t_delphi_generator::generate_serialize_field(ostream& out, } out << name << ");"; break; + case t_base_type::TYPE_UUID: + out << "WriteUuid(" << name << ");"; + break; case t_base_type::TYPE_BOOL: out << "WriteBool(" << name << ");"; break; @@ -3195,6 +3205,7 @@ string t_delphi_generator::input_arg_prefix(t_type* ttype) { // these should be const'ed for optimal performamce case t_base_type::TYPE_STRING: // refcounted pointer + case t_base_type::TYPE_UUID: // refcounted pointer case t_base_type::TYPE_I64: // larger than 32 bit case t_base_type::TYPE_DOUBLE: // larger than 32 bit return "const "; @@ -3247,6 +3258,8 @@ string t_delphi_generator::base_type_name(t_base_type* tbase) { } else { return com_types_ ? "System.WideString" : "System.string"; } + case t_base_type::TYPE_UUID: + return "System.TGuid"; case t_base_type::TYPE_BOOL: return "System.Boolean"; case t_base_type::TYPE_I8: @@ -3413,6 +3426,8 @@ string t_delphi_generator::type_to_enum(t_type* type) { throw "NO T_VOID CONSTRUCT"; case t_base_type::TYPE_STRING: return "TType.String_"; + case t_base_type::TYPE_UUID: + return "TType.Uuid"; case t_base_type::TYPE_BOOL: return "TType.Bool_"; case t_base_type::TYPE_I8: @@ -3461,6 +3476,8 @@ string t_delphi_generator::empty_value(t_type* type) { } else { return "''"; } + case t_base_type::TYPE_UUID: + return "System.TGuid.Empty"; case t_base_type::TYPE_BOOL: return "False"; case t_base_type::TYPE_I8: @@ -4065,6 +4082,9 @@ void t_delphi_generator::generate_delphi_struct_tostring_impl(ostream& out, << type_name(ttype, false, true, false, false) << ">.ToString( System.Ord( Self." << prop_name((*f_iter), is_exception) << ")));" << endl; + } else if (ttype->is_uuid()) { + indent_impl(out) << tmp_sb << ".Append( GUIDToString(Self." << prop_name((*f_iter), is_exception) << "));" + << endl; } else { indent_impl(out) << tmp_sb << ".Append( Self." << prop_name((*f_iter), is_exception) << ");" << endl; diff --git a/compiler/cpp/src/thrift/generate/t_erl_generator.cc b/compiler/cpp/src/thrift/generate/t_erl_generator.cc index c06ea437d..1f4fd506d 100644 --- a/compiler/cpp/src/thrift/generate/t_erl_generator.cc +++ b/compiler/cpp/src/thrift/generate/t_erl_generator.cc @@ -1168,6 +1168,8 @@ string t_erl_generator::type_to_enum(t_type* type) { return "?tType_I64"; case t_base_type::TYPE_DOUBLE: return "?tType_DOUBLE"; + default: + break; } } else if (type->is_enum()) { return "?tType_I32"; @@ -1211,6 +1213,8 @@ std::string t_erl_generator::render_type_term(t_type* type, return "i64"; case t_base_type::TYPE_DOUBLE: return "double"; + default: + break; } } else if (type->is_enum()) { return "i32"; diff --git a/compiler/cpp/src/thrift/generate/t_go_generator.cc b/compiler/cpp/src/thrift/generate/t_go_generator.cc index f4b94a455..90f34c8ca 100644 --- a/compiler/cpp/src/thrift/generate/t_go_generator.cc +++ b/compiler/cpp/src/thrift/generate/t_go_generator.cc @@ -368,6 +368,8 @@ bool t_go_generator::omit_initialization(t_field* tfield) { } else { return value->get_double() == 0.; } + default: + throw "compiler error: unhandled type"; } } return false; @@ -420,6 +422,8 @@ bool t_go_generator::is_pointer_field(t_field* tfield, bool in_container_value) case t_base_type::TYPE_I64: case t_base_type::TYPE_DOUBLE: return !has_default; + default: + break; } } else if (type->is_enum()) { return !has_default; @@ -4057,6 +4061,9 @@ string t_go_generator::type_to_enum(t_type* type) { case t_base_type::TYPE_DOUBLE: return "thrift.DOUBLE"; + + default: + break; } } else if (type->is_enum()) { return "thrift.I32"; @@ -4144,6 +4151,9 @@ string t_go_generator::type_to_go_type_with_opt(t_type* type, case t_base_type::TYPE_DOUBLE: return maybe_pointer + "float64"; + + default: + break; } } else if (type->is_enum()) { return maybe_pointer + publicize(type_name(type)); diff --git a/compiler/cpp/src/thrift/generate/t_haxe_generator.cc b/compiler/cpp/src/thrift/generate/t_haxe_generator.cc index 757f207f0..fdd21f2a3 100644 --- a/compiler/cpp/src/thrift/generate/t_haxe_generator.cc +++ b/compiler/cpp/src/thrift/generate/t_haxe_generator.cc @@ -2698,6 +2698,8 @@ string t_haxe_generator::declare_field(t_field* tfield, bool init) { case t_base_type::TYPE_DOUBLE: result += " = (double)0"; break; + default: + throw "unhandled type"; } } else if (ttype->is_enum()) { @@ -2805,6 +2807,8 @@ string t_haxe_generator::type_to_enum(t_type* type) { return "TType.I64"; case t_base_type::TYPE_DOUBLE: return "TType.DOUBLE"; + default: + break; } } else if (type->is_enum()) { return "TType.I32"; diff --git a/compiler/cpp/src/thrift/generate/t_java_generator.cc b/compiler/cpp/src/thrift/generate/t_java_generator.cc index 7dfd10f52..743d150fe 100644 --- a/compiler/cpp/src/thrift/generate/t_java_generator.cc +++ b/compiler/cpp/src/thrift/generate/t_java_generator.cc @@ -1833,6 +1833,8 @@ void t_java_generator::generate_java_struct_parcelable(ostream& out, t_struct* t break; case t_base_type::TYPE_VOID: break; + default: + throw "compiler error: unhandled type"; } } } @@ -1931,6 +1933,8 @@ void t_java_generator::generate_java_struct_parcelable(ostream& out, t_struct* t break; case t_base_type::TYPE_VOID: break; + default: + throw "compiler error: unhandled type"; } } } @@ -4666,6 +4670,8 @@ string t_java_generator::declare_field(t_field* tfield, bool init, bool comment) case t_base_type::TYPE_DOUBLE: result += " = (double)0"; break; + default: + throw "compiler error: unhandled type"; } } else if (ttype->is_enum()) { result += " = null"; @@ -4843,6 +4849,8 @@ string t_java_generator::type_to_enum(t_type* type) { return "org.apache.thrift.protocol.TType.I64"; case t_base_type::TYPE_DOUBLE: return "org.apache.thrift.protocol.TType.DOUBLE"; + default: + throw "compiler error: unhandled type"; } } else if (type->is_enum()) { return "org.apache.thrift.protocol.TType.I32"; diff --git a/compiler/cpp/src/thrift/generate/t_javame_generator.cc b/compiler/cpp/src/thrift/generate/t_javame_generator.cc index b37a43bd0..4da086965 100644 --- a/compiler/cpp/src/thrift/generate/t_javame_generator.cc +++ b/compiler/cpp/src/thrift/generate/t_javame_generator.cc @@ -2869,6 +2869,8 @@ string t_javame_generator::declare_field(t_field* tfield, bool init) { case t_base_type::TYPE_DOUBLE: result += " = (double)0"; break; + default: + throw "compiler error: unhandled type"; } } else if (ttype->is_enum()) { @@ -2951,6 +2953,8 @@ string t_javame_generator::type_to_enum(t_type* type) { return "TType.I64"; case t_base_type::TYPE_DOUBLE: return "TType.DOUBLE"; + default: + throw "compiler error: unhandled type"; } } else if (type->is_enum()) { return "TType.I32"; diff --git a/compiler/cpp/src/thrift/generate/t_js_generator.cc b/compiler/cpp/src/thrift/generate/t_js_generator.cc index 5fcac1659..03a307f82 100644 --- a/compiler/cpp/src/thrift/generate/t_js_generator.cc +++ b/compiler/cpp/src/thrift/generate/t_js_generator.cc @@ -2697,6 +2697,8 @@ string t_js_generator::type_to_enum(t_type* type) { return "Thrift.Type.I64"; case t_base_type::TYPE_DOUBLE: return "Thrift.Type.DOUBLE"; + default: + throw "compiler error: unhandled type"; } } else if (type->is_enum()) { return "Thrift.Type.I32"; @@ -2745,6 +2747,9 @@ string t_js_generator::ts_get_type(t_type* type) { break; case t_base_type::TYPE_VOID: ts_type = "void"; + break; + default: + throw "compiler error: unhandled type"; } } else if (type->is_enum() || type->is_struct() || type->is_xception()) { std::string type_name; diff --git a/compiler/cpp/src/thrift/generate/t_kotlin_generator.cc b/compiler/cpp/src/thrift/generate/t_kotlin_generator.cc index 3a2afe6d5..3a3543e63 100644 --- a/compiler/cpp/src/thrift/generate/t_kotlin_generator.cc +++ b/compiler/cpp/src/thrift/generate/t_kotlin_generator.cc @@ -1892,6 +1892,8 @@ string t_kotlin_generator::type_to_enum(t_type* type) { return "org.apache.thrift.protocol.TType.I64"; case t_base_type::TYPE_DOUBLE: return "org.apache.thrift.protocol.TType.DOUBLE"; + default: + throw "compiler error: unhandled type"; } } else if (type->is_enum()) { return "org.apache.thrift.protocol.TType.I32"; diff --git a/compiler/cpp/src/thrift/generate/t_lua_generator.cc b/compiler/cpp/src/thrift/generate/t_lua_generator.cc index de3b89011..a4b4a37d3 100644 --- a/compiler/cpp/src/thrift/generate/t_lua_generator.cc +++ b/compiler/cpp/src/thrift/generate/t_lua_generator.cc @@ -1146,6 +1146,8 @@ string t_lua_generator::type_to_enum(t_type* type) { return "TType.I64"; case t_base_type::TYPE_DOUBLE: return "TType.DOUBLE"; + default: + throw "compiler error: unhandled type"; } } else if (type->is_enum()) { return "TType.I32"; diff --git a/compiler/cpp/src/thrift/generate/t_markdown_generator.cc b/compiler/cpp/src/thrift/generate/t_markdown_generator.cc index 17e90f759..0f6aa2227 100644 --- a/compiler/cpp/src/thrift/generate/t_markdown_generator.cc +++ b/compiler/cpp/src/thrift/generate/t_markdown_generator.cc @@ -199,7 +199,7 @@ void t_markdown_generator::generate_program_toc_row(t_program* tprog) { string fn_name = (*fn_iter)->get_name(); filling.emplace_back(); fill = &filling.back(); - (*fill)[1] = " [ • " + fn_name + "](" + (*fill)[1] = " [ • " + fn_name + "](" + make_file_link(fname) + "#function-" + str_to_id(name + fn_name) + ")"; } diff --git a/compiler/cpp/src/thrift/generate/t_netstd_generator.cc b/compiler/cpp/src/thrift/generate/t_netstd_generator.cc index ad9e57965..547457130 100644 --- a/compiler/cpp/src/thrift/generate/t_netstd_generator.cc +++ b/compiler/cpp/src/thrift/generate/t_netstd_generator.cc @@ -636,6 +636,9 @@ string t_netstd_generator::render_const_value(ostream& out, string name, t_type* render << '"' << get_escaped_string(value) << '"'; } break; + case t_base_type::TYPE_UUID: + render << "new System.Guid(\"" << get_escaped_string(value) << "\")"; + break; case t_base_type::TYPE_BOOL: render << ((value->get_integer() > 0) ? "true" : "false"); break; @@ -2703,6 +2706,9 @@ void t_netstd_generator::generate_deserialize_field(ostream& out, t_field* tfiel out << "ReadStringAsync(" << CANCELLATION_TOKEN_NAME << ");"; } break; + case t_base_type::TYPE_UUID: + out << "ReadUuidAsync(" << CANCELLATION_TOKEN_NAME << ");"; + break; case t_base_type::TYPE_BOOL: out << "ReadBoolAsync(" << CANCELLATION_TOKEN_NAME << ");"; break; @@ -2906,6 +2912,9 @@ void t_netstd_generator::generate_serialize_field(ostream& out, t_field* tfield, } out << name << ", " << CANCELLATION_TOKEN_NAME << ");"; break; + case t_base_type::TYPE_UUID: + out << "WriteUuidAsync(" << nullable_name << ", " << CANCELLATION_TOKEN_NAME << ");"; + break; case t_base_type::TYPE_BOOL: out << "WriteBoolAsync(" << nullable_name << ", " << CANCELLATION_TOKEN_NAME << ");"; break; @@ -3453,7 +3462,7 @@ string t_netstd_generator::type_name(t_type* ttype, bool with_namespace) if (ttype->is_set()) { t_set* tset = static_cast<t_set*>(ttype); - return "HashSet<" + type_name(tset->get_elem_type()) + ">"; + return "HashSet<" + type_name(tset->get_elem_type()) + ">"; } if (ttype->is_list()) @@ -3492,6 +3501,8 @@ string t_netstd_generator::base_type_name(t_base_type* tbase) } else { return "string"; } + case t_base_type::TYPE_UUID: + return "global::System.Guid"; case t_base_type::TYPE_BOOL: return "bool"; case t_base_type::TYPE_I8: @@ -3614,6 +3625,9 @@ string t_netstd_generator::initialize_field(t_field* tfield) return " = null"; } break; + case t_base_type::TYPE_UUID: + return " = System.Guid.Empty"; + break; case t_base_type::TYPE_BOOL: return " = false"; break; @@ -3725,6 +3739,8 @@ string t_netstd_generator::type_to_enum(t_type* type) throw "NO T_VOID CONSTRUCT"; case t_base_type::TYPE_STRING: return "TType.String"; + case t_base_type::TYPE_UUID: + return "TType.Uuid"; case t_base_type::TYPE_BOOL: return "TType.Bool"; case t_base_type::TYPE_I8: diff --git a/compiler/cpp/src/thrift/generate/t_ocaml_generator.cc b/compiler/cpp/src/thrift/generate/t_ocaml_generator.cc index 0a961467e..300b5ac71 100644 --- a/compiler/cpp/src/thrift/generate/t_ocaml_generator.cc +++ b/compiler/cpp/src/thrift/generate/t_ocaml_generator.cc @@ -1698,6 +1698,8 @@ string t_ocaml_generator::type_to_enum(t_type* type) { return "Protocol.T_I64"; case t_base_type::TYPE_DOUBLE: return "Protocol.T_DOUBLE"; + default: + throw "compiler error: unhandled type"; } } else if (type->is_enum()) { return "Protocol.T_I32"; @@ -1739,6 +1741,8 @@ string t_ocaml_generator::render_ocaml_type(t_type* type) { return "Int64.t"; case t_base_type::TYPE_DOUBLE: return "float"; + default: + throw "compiler error: unhandled type"; } } else if (type->is_enum()) { return capitalize(((t_enum*)type)->get_name()) + ".t"; diff --git a/compiler/cpp/src/thrift/generate/t_perl_generator.cc b/compiler/cpp/src/thrift/generate/t_perl_generator.cc index 68bd57f0f..72de69887 100644 --- a/compiler/cpp/src/thrift/generate/t_perl_generator.cc +++ b/compiler/cpp/src/thrift/generate/t_perl_generator.cc @@ -1003,12 +1003,12 @@ void t_perl_generator::generate_service_rest(t_service* tservice) { f_service_ << indent() << "my $" << (*a_iter)->get_name() << " = (" << req << ") ? " << req << " : undef;" << endl; /* slist no longer supported - if (atype->is_string() && ((t_base_type*)atype)->is_string_list()) { + if (atype->is_string() && ((t_base_type*)atype)->is_string_list()) { f_service_ << indent() << "my @" << (*a_iter)->get_name() << " = split(/,/, $" << (*a_iter)->get_name() << ");" << endl << indent() << "$" << (*a_iter)->get_name() << " = \\@" << (*a_iter)->get_name() << endl; } - */ + */ } f_service_ << indent() << "return $self->{impl}->" << (*f_iter)->get_name() << "(" << argument_list((*f_iter)->get_arglist()) << ");" << endl; @@ -1666,6 +1666,8 @@ string t_perl_generator::type_to_enum(t_type* type) { return "Thrift::TType::I64"; case t_base_type::TYPE_DOUBLE: return "Thrift::TType::DOUBLE"; + default: + throw "compiler error: unhandled type"; } } else if (type->is_enum()) { return "Thrift::TType::I32"; diff --git a/compiler/cpp/src/thrift/generate/t_php_generator.cc b/compiler/cpp/src/thrift/generate/t_php_generator.cc index 39968a658..c6e60c82a 100644 --- a/compiler/cpp/src/thrift/generate/t_php_generator.cc +++ b/compiler/cpp/src/thrift/generate/t_php_generator.cc @@ -62,7 +62,7 @@ public: validate_ = false; json_serializable_ = false; getters_setters_ = false; - + nsglobal_ = ""; // by default global namespace is empty classmap_ = false; for (iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { @@ -874,8 +874,8 @@ void t_php_generator::generate_reflection_getters(ostringstream& out, * Generates a setter for the generated private fields */ void t_php_generator::generate_reflection_setters(ostringstream& out, - string field_name, - string cap_name) { + string field_name, + string cap_name) { out << indent() << "public function set" << cap_name << "(" << "$" << field_name << ")" << endl << indent() << "{" << endl; @@ -2798,6 +2798,8 @@ string t_php_generator::type_to_enum(t_type* type) { return "TType::I64"; case t_base_type::TYPE_DOUBLE: return "TType::DOUBLE"; + default: + throw "compiler error: unhandled type"; } } else if (type->is_enum()) { return "TType::I32"; @@ -2839,6 +2841,8 @@ string t_php_generator::type_to_phpdoc(t_type* type) { return "int"; case t_base_type::TYPE_DOUBLE: return "double"; + default: + throw "compiler error: unhandled type"; } } else if (type->is_enum()) { return "int"; diff --git a/compiler/cpp/src/thrift/generate/t_py_generator.cc b/compiler/cpp/src/thrift/generate/t_py_generator.cc index 7f3cae546..33437fd00 100644 --- a/compiler/cpp/src/thrift/generate/t_py_generator.cc +++ b/compiler/cpp/src/thrift/generate/t_py_generator.cc @@ -2767,6 +2767,8 @@ string t_py_generator::type_to_enum(t_type* type) { return "TType.I64"; case t_base_type::TYPE_DOUBLE: return "TType.DOUBLE"; + default: + throw "compiler error: unhandled type"; } } else if (type->is_enum()) { return "TType.I32"; diff --git a/compiler/cpp/src/thrift/generate/t_rb_generator.cc b/compiler/cpp/src/thrift/generate/t_rb_generator.cc index 116ccaaa7..2ec578771 100644 --- a/compiler/cpp/src/thrift/generate/t_rb_generator.cc +++ b/compiler/cpp/src/thrift/generate/t_rb_generator.cc @@ -1171,6 +1171,8 @@ string t_rb_generator::type_to_enum(t_type* type) { return "::Thrift::Types::I64"; case t_base_type::TYPE_DOUBLE: return "::Thrift::Types::DOUBLE"; + default: + throw "compiler error: unhandled type"; } } else if (type->is_enum()) { return "::Thrift::Types::I32"; diff --git a/compiler/cpp/src/thrift/generate/t_rs_generator.cc b/compiler/cpp/src/thrift/generate/t_rs_generator.cc index 6ce402739..5946e1d9a 100644 --- a/compiler/cpp/src/thrift/generate/t_rs_generator.cc +++ b/compiler/cpp/src/thrift/generate/t_rs_generator.cc @@ -1551,6 +1551,8 @@ void t_rs_generator::render_type_sync_write(const string &type_var, bool type_va case t_base_type::TYPE_DOUBLE: f_gen_ << indent() << "o_prot.write_double(" + type_var + ".into())?;" << endl; return; + default: + throw "compiler error: unhandled type"; } } else if (ttype->is_typedef()) { t_typedef* ttypedef = (t_typedef*) ttype; @@ -1926,6 +1928,8 @@ void t_rs_generator::render_type_sync_read(const string &type_var, t_type *ttype case t_base_type::TYPE_DOUBLE: f_gen_ << indent() << "let " << type_var << " = OrderedFloat::from(i_prot.read_double()?);" << endl; return; + default: + throw "compiler error: unhandled type"; } } else if (ttype->is_typedef()) { // FIXME: not a fan of separate `is_boxed` parameter @@ -3025,6 +3029,8 @@ string t_rs_generator::to_rust_type(t_type* ttype) { return "i64"; case t_base_type::TYPE_DOUBLE: return "OrderedFloat<f64>"; + default: + throw "compiler error: unhandled type"; } } else if (ttype->is_typedef()) { t_typedef* ttypedef = (t_typedef*)ttype; @@ -3085,6 +3091,8 @@ string t_rs_generator::to_rust_field_type_enum(t_type* ttype) { return "TType::I64"; case t_base_type::TYPE_DOUBLE: return "TType::Double"; + default: + throw "compiler error: unhandled type"; } } else if (ttype->is_enum()) { return "TType::I32"; @@ -3123,6 +3131,8 @@ string t_rs_generator::opt_in_req_out_value(t_type* ttype) { return "Some(0)"; case t_base_type::TYPE_DOUBLE: return "Some(OrderedFloat::from(0.0))"; + default: + throw "compiler error: unhandled type"; } } else if (ttype->is_enum() || ttype->is_struct() || ttype->is_xception()) { diff --git a/compiler/cpp/src/thrift/generate/t_st_generator.cc b/compiler/cpp/src/thrift/generate/t_st_generator.cc index 109adc705..5edb85281 100644 --- a/compiler/cpp/src/thrift/generate/t_st_generator.cc +++ b/compiler/cpp/src/thrift/generate/t_st_generator.cc @@ -1037,6 +1037,8 @@ string t_st_generator::type_to_enum(t_type* type) { return "TType i64"; case t_base_type::TYPE_DOUBLE: return "TType double"; + default: + throw "compiler error: unhandled type"; } } else if (type->is_enum()) { return "TType i32"; diff --git a/compiler/cpp/src/thrift/generate/t_swift_generator.cc b/compiler/cpp/src/thrift/generate/t_swift_generator.cc index d8eb73310..834e31dc8 100644 --- a/compiler/cpp/src/thrift/generate/t_swift_generator.cc +++ b/compiler/cpp/src/thrift/generate/t_swift_generator.cc @@ -51,7 +51,7 @@ public: const string& option_string) : t_oop_generator(program) { update_keywords(); - + (void)option_string; map<string, string>::const_iterator iter; @@ -292,7 +292,7 @@ private: protected: std::set<std::string> lang_keywords() const override { - return {}; + return {}; } }; @@ -3136,6 +3136,8 @@ string t_swift_generator::type_to_enum(t_type* type, bool qualified) { return result + "i64"; case t_base_type::TYPE_DOUBLE: return result + "double"; + default: + throw "compiler error: unhandled type"; } } else if (type->is_enum()) { return result + "i32"; @@ -3168,6 +3170,8 @@ string t_swift_generator::type_to_enum(t_type* type, bool qualified) { return result + "I64"; case t_base_type::TYPE_DOUBLE: return result + "DOUBLE"; + default: + throw "compiler error: unhandled type"; } } else if (type->is_enum()) { return result + "I32"; diff --git a/compiler/cpp/src/thrift/main.cc b/compiler/cpp/src/thrift/main.cc index c5aa65f32..a07f4295a 100644 --- a/compiler/cpp/src/thrift/main.cc +++ b/compiler/cpp/src/thrift/main.cc @@ -738,6 +738,12 @@ void validate_const_rec(std::string name, t_type* type, t_const_value* value) { throw "type error: const \"" + name + "\" was declared as string"; } break; + case t_base_type::TYPE_UUID: + if (value->get_type() != t_const_value::CV_STRING) { + throw "type error: const \"" + name + "\" was declared as uuid"; + } + value->get_uuid(); // validates constant + break; case t_base_type::TYPE_BOOL: if (value->get_type() != t_const_value::CV_INTEGER) { throw "type error: const \"" + name + "\" was declared as bool"; diff --git a/compiler/cpp/src/thrift/parse/t_base_type.h b/compiler/cpp/src/thrift/parse/t_base_type.h index 5676f0492..4e5228d54 100644 --- a/compiler/cpp/src/thrift/parse/t_base_type.h +++ b/compiler/cpp/src/thrift/parse/t_base_type.h @@ -36,6 +36,7 @@ public: enum t_base { TYPE_VOID, TYPE_STRING, + TYPE_UUID, TYPE_BOOL, TYPE_I8, TYPE_I16, @@ -55,6 +56,8 @@ public: bool is_bool() const override { return base_ == TYPE_BOOL; } + bool is_uuid() const override { return base_ == TYPE_UUID; } + void set_binary(bool val) { binary_ = val; } bool is_binary() const override { return binary_ && (base_ == TYPE_STRING); } @@ -69,6 +72,9 @@ public: case TYPE_STRING: return "string"; break; + case TYPE_UUID: + return "uuid"; + break; case TYPE_BOOL: return "bool"; break; diff --git a/compiler/cpp/src/thrift/parse/t_const_value.h b/compiler/cpp/src/thrift/parse/t_const_value.h index 5b8156f1a..452a90c5b 100644 --- a/compiler/cpp/src/thrift/parse/t_const_value.h +++ b/compiler/cpp/src/thrift/parse/t_const_value.h @@ -85,6 +85,17 @@ public: } } + void set_uuid(std::string val) { + validate_uuid(val); + valType_ = CV_STRING; + stringVal_ = val; + } + + std::string get_uuid() const { + validate_uuid(stringVal_); + return stringVal_; + } + void set_double(double val) { valType_ = CV_DOUBLE; doubleVal_ = val; @@ -199,6 +210,34 @@ private: t_enum* enum_; t_const_value_type valType_; + + void validate_uuid(std::string uuid) const { + bool valid = (uuid.length() == 36); + const std::string HEXCHARS = std::string("0123456789ABCDEFabcdef"); + + // canonical format "01234567-9012-4567-9012-456789012345" expected + for( size_t i = 0; valid && (i < uuid.length()); ++i) { + switch(i) { + case 8: + case 13: + case 18: + case 23: + if(uuid[i] != '-') { + valid = false; + } + break; + default: + if(HEXCHARS.find(uuid[i]) == std::string::npos) { + valid = false; + } + break; + } + } + + if( ! valid) { + throw "invalid uuid " + uuid; + } + } }; #endif diff --git a/compiler/cpp/src/thrift/parse/t_scope.h b/compiler/cpp/src/thrift/parse/t_scope.h index 17a360f08..71ab4f389 100644 --- a/compiler/cpp/src/thrift/parse/t_scope.h +++ b/compiler/cpp/src/thrift/parse/t_scope.h @@ -166,6 +166,9 @@ public: case t_base_type::TYPE_STRING: const_val->set_string(constant->get_value()->get_string()); break; + case t_base_type::TYPE_UUID: + const_val->set_uuid(constant->get_value()->get_uuid()); + break; case t_base_type::TYPE_DOUBLE: const_val->set_double(constant->get_value()->get_double()); break; diff --git a/compiler/cpp/src/thrift/parse/t_type.h b/compiler/cpp/src/thrift/parse/t_type.h index 63f99ed87..8dbeb9efc 100644 --- a/compiler/cpp/src/thrift/parse/t_type.h +++ b/compiler/cpp/src/thrift/parse/t_type.h @@ -47,6 +47,7 @@ public: virtual bool is_void() const { return false; } virtual bool is_base_type() const { return false; } virtual bool is_string() const { return false; } + virtual bool is_uuid() const { return false; } virtual bool is_binary() const { return false; } virtual bool is_bool() const { return false; } virtual bool is_typedef() const { return false; } diff --git a/compiler/cpp/src/thrift/thriftl.ll b/compiler/cpp/src/thrift/thriftl.ll index 810a983e0..d60e84645 100644 --- a/compiler/cpp/src/thrift/thriftl.ll +++ b/compiler/cpp/src/thrift/thriftl.ll @@ -239,6 +239,7 @@ literal_begin (['\"]) "double" { return tok_double; } "string" { return tok_string; } "binary" { return tok_binary; } +"uuid" { return tok_uuid; } "slist" { error_no_longer_supported("slist","string"); } diff --git a/compiler/cpp/src/thrift/thrifty.yy b/compiler/cpp/src/thrift/thrifty.yy index a062a0e40..40c2a9373 100644 --- a/compiler/cpp/src/thrift/thrifty.yy +++ b/compiler/cpp/src/thrift/thrifty.yy @@ -134,6 +134,7 @@ const int struct_is_union = 1; %token tok_bool %token tok_string %token tok_binary +%token tok_uuid %token tok_i8 %token tok_i16 %token tok_i32 @@ -1002,6 +1003,11 @@ SimpleBaseType: pdebug("BaseType -> tok_binary"); $$ = g_type_binary; } +| tok_uuid + { + pdebug("BaseType -> tok_uuid"); + $$ = g_type_uuid; + } | tok_bool { pdebug("BaseType -> tok_bool"); diff --git a/lib/delphi/src/Thrift.Protocol.Compact.pas b/lib/delphi/src/Thrift.Protocol.Compact.pas index 3a1dbfd0b..02a19ea80 100644 --- a/lib/delphi/src/Thrift.Protocol.Compact.pas +++ b/lib/delphi/src/Thrift.Protocol.Compact.pas @@ -77,7 +77,8 @@ type LIST = $09, SET_ = $0A, MAP = $0B, - STRUCT = $0C + STRUCT = $0C, + UUID = $0D ); private type @@ -100,7 +101,8 @@ type Types.STRUCT, // Struct = 12, Types.MAP, // Map = 13, Types.SET_, // Set_ = 14, - Types.LIST // List = 15, + Types.LIST, // List = 15, + Types.UUID // Uuid = 16 ); tcompactTypeToType : array[Types] of TType = ( @@ -116,7 +118,8 @@ type TType.List, // LIST TType.Set_, // SET_ TType.Map, // MAP - TType.Struct // STRUCT + TType.Struct, // STRUCT + TType.Uuid // UUID ); strict private @@ -173,6 +176,7 @@ type procedure WriteI64( const i64: Int64); override; procedure WriteDouble( const dub: Double); override; procedure WriteBinary( const b: TBytes); overload; override; + procedure WriteUuid( const uuid: TGuid); override; private // unit visible stuff class function DoubleToInt64Bits( const db : Double) : Int64; @@ -219,6 +223,7 @@ type function ReadI64: Int64; override; function ReadDouble:Double; override; function ReadBinary: TBytes; overload; override; + function ReadUuid: TGuid; override; private // Internal Reading methods @@ -537,6 +542,14 @@ begin Transport.Write( b); end; +procedure TCompactProtocolImpl.WriteUuid( const uuid: TGuid); +var network : TGuid; // in network order (Big Endian) +begin + ASSERT( SizeOf(uuid) = 16); + network := uuid.SwapByteOrder; + Transport.Write( @network, 0, SizeOf(network)); +end; + procedure TCompactProtocolImpl.WriteMessageEnd; begin // nothing to do @@ -850,6 +863,14 @@ begin then Transport.ReadAll( result, 0, length); end; +function TCompactProtocolImpl.ReadUuid: TGuid; +var network : TGuid; // in network order (Big Endian) +begin + ASSERT( SizeOf(result) = 16); + FTrans.ReadAll( @network, SizeOf(network), 0, SizeOf(network)); + result := network.SwapByteOrder; +end; + procedure TCompactProtocolImpl.ReadMessageEnd; begin @@ -994,6 +1015,7 @@ begin TType.Map: result := SizeOf(Byte); // element count TType.Set_: result := SizeOf(Byte); // element count TType.List: result := SizeOf(Byte); // element count + TType.Uuid: result := SizeOf(TGuid); else raise TTransportExceptionBadArgs.Create('Unhandled type code'); end; diff --git a/lib/delphi/src/Thrift.Protocol.JSON.pas b/lib/delphi/src/Thrift.Protocol.JSON.pas index 52909b778..2a9682ced 100644 --- a/lib/delphi/src/Thrift.Protocol.JSON.pas +++ b/lib/delphi/src/Thrift.Protocol.JSON.pas @@ -198,6 +198,7 @@ type procedure WriteDouble( const d: Double); override; procedure WriteString( const s: string ); override; procedure WriteBinary( const b: TBytes); override; + procedure WriteUuid( const uuid: TGuid); override; // function ReadMessageBegin: TThriftMessage; override; procedure ReadMessageEnd(); override; @@ -219,6 +220,7 @@ type function ReadDouble:Double; override; function ReadString : string; override; function ReadBinary: TBytes; override; + function ReadUuid: TGuid; override; strict private @@ -288,6 +290,7 @@ const NAME_MAP = 'map'; NAME_LIST = 'lst'; NAME_SET = 'set'; + NAME_UUID = 'uid'; INVARIANT_CULTURE : TFormatSettings = ( ThousandSeparator: ','; @@ -317,6 +320,7 @@ begin TType.Map: result := NAME_MAP; TType.Set_: result := NAME_SET; TType.List: result := NAME_LIST; + TType.Uuid: result := NAME_UUID; else raise TProtocolExceptionNotImplemented.Create('Unrecognized type ('+IntToStr(Ord(typeID))+')'); end; @@ -336,6 +340,7 @@ begin else if name = NAME_MAP then result := TType.Map else if name = NAME_LIST then result := TType.List else if name = NAME_SET then result := TType.Set_ + else if name = NAME_UUID then result := TType.Uuid else raise TProtocolExceptionNotImplemented.Create('Unrecognized type ('+name+')'); end; @@ -831,6 +836,11 @@ begin WriteJSONBase64( b); end; +procedure TJSONProtocolImpl.WriteUuid( const uuid: TGuid); +begin + WriteString( Copy( GuidToString(uuid), 2, 36)); // strip off the { braces } +end; + function TJSONProtocolImpl.ReadJSONString( skipContext : Boolean) : TBytes; var buffer : TThriftMemoryStream; @@ -1237,6 +1247,12 @@ begin end; +function TJSONProtocolImpl.ReadUuid: TGuid; +begin + result := StringToGUID( '{' + ReadString + '}'); +end; + + function TJSONProtocolImpl.GetMinSerializedSize( const aType : TType) : Integer; // Return the minimum number of bytes a type will consume on the wire begin @@ -1254,6 +1270,7 @@ begin TType.Map: result := 2; // empty map TType.Set_: result := 2; // empty set TType.List: result := 2; // empty list + TType.Uuid: result := 36; // "E236974D-F0B0-4E05-8F29-0B455D41B1A1" else raise TTransportExceptionBadArgs.Create('Unhandled type code'); end; diff --git a/lib/delphi/src/Thrift.Protocol.pas b/lib/delphi/src/Thrift.Protocol.pas index 9f2cac8d1..636f20100 100644 --- a/lib/delphi/src/Thrift.Protocol.pas +++ b/lib/delphi/src/Thrift.Protocol.pas @@ -49,7 +49,8 @@ type Struct = 12, Map = 13, Set_ = 14, - List = 15 + List = 15, + Uuid = 16 ); TMessageType = ( @@ -62,7 +63,7 @@ type const VALID_TTYPES = [ TType.Stop, TType.Void, - TType.Bool_, TType.Byte_, TType.Double_, TType.I16, TType.I32, TType.I64, TType.String_, + TType.Bool_, TType.Byte_, TType.Double_, TType.I16, TType.I32, TType.I64, TType.String_, TType.Uuid, TType.Struct, TType.Map, TType.Set_, TType.List ]; @@ -221,6 +222,7 @@ type procedure WriteAnsiString( const s: AnsiString); procedure WriteBinary( const b: TBytes); overload; procedure WriteBinary( const b: IThriftBytes); overload; + procedure WriteUuid( const uuid: TGuid); function ReadMessageBegin: TThriftMessage; procedure ReadMessageEnd(); @@ -242,6 +244,7 @@ type function ReadDouble:Double; function ReadBinary: TBytes; // IMPORTANT: this is NOT safe across module boundaries function ReadBinaryCOM : IThriftBytes; + function ReadUuid: TGuid; function ReadString: string; function ReadAnsiString: AnsiString; @@ -297,6 +300,7 @@ type procedure WriteString( const s: string ); virtual; procedure WriteAnsiString( const s: AnsiString); virtual; procedure WriteBinary( const b: TBytes); overload; virtual; abstract; + procedure WriteUuid( const b: TGuid); virtual; abstract; function ReadMessageBegin: TThriftMessage; virtual; abstract; procedure ReadMessageEnd(); virtual; abstract; @@ -317,6 +321,7 @@ type function ReadI64: Int64; virtual; abstract; function ReadDouble:Double; virtual; abstract; function ReadBinary: TBytes; virtual; abstract; + function ReadUuid: TGuid; virtual; abstract; function ReadString: string; virtual; function ReadAnsiString: AnsiString; virtual; @@ -415,6 +420,7 @@ type procedure WriteI64( const i64: Int64); override; procedure WriteDouble( const d: Double); override; procedure WriteBinary( const b: TBytes); override; + procedure WriteUuid( const uuid: TGuid); override; function ReadMessageBegin: TThriftMessage; override; procedure ReadMessageEnd(); override; @@ -435,6 +441,7 @@ type function ReadI64: Int64; override; function ReadDouble:Double; override; function ReadBinary: TBytes; override; + function ReadUuid: TGuid; override; end; @@ -479,6 +486,7 @@ type procedure WriteString( const s: string ); override; procedure WriteAnsiString( const s: AnsiString); override; procedure WriteBinary( const b: TBytes); override; + procedure WriteUuid( const uuid: TGuid); override; function ReadMessageBegin: TThriftMessage; override; procedure ReadMessageEnd(); override; @@ -499,6 +507,7 @@ type function ReadI64: Int64; override; function ReadDouble:Double; override; function ReadBinary: TBytes; override; + function ReadUuid: TGuid; override; function ReadString: string; override; function ReadAnsiString: AnsiString; override; end; @@ -800,6 +809,7 @@ begin TType.I64 : prot.ReadI64(); TType.Double_ : prot.ReadDouble(); TType.String_ : prot.ReadBinary();// Don't try to decode the string, just skip it. + TType.Uuid : prot.ReadUuid(); // structured types TType.Struct : begin @@ -874,6 +884,14 @@ begin Result := buf; end; +function TBinaryProtocolImpl.ReadUuid : TGuid; +var network : TGuid; // in network order (Big Endian) +begin + ASSERT( SizeOf(result) = 16); + FTrans.ReadAll( @network, SizeOf(network), 0, SizeOf(network)); + result := network.SwapByteOrder; +end; + function TBinaryProtocolImpl.ReadBool: Boolean; begin Result := (ReadByte = 1); @@ -1042,6 +1060,14 @@ begin if iLen > 0 then FTrans.Write(b, 0, iLen); end; +procedure TBinaryProtocolImpl.WriteUuid( const uuid: TGuid); +var network : TGuid; // in network order (Big Endian) +begin + ASSERT( SizeOf(uuid) = 16); + network := uuid.SwapByteOrder; + Transport.Write( @network, 0, SizeOf(network)); +end; + procedure TBinaryProtocolImpl.WriteBool(b: Boolean); begin if b then begin @@ -1191,6 +1217,7 @@ begin TType.Map: result := SizeOf(Int32); // element count TType.Set_: result := SizeOf(Int32); // element count TType.List: result := SizeOf(Int32); // element count + TType.Uuid: result := SizeOf(TGuid); else raise TTransportExceptionBadArgs.Create('Unhandled type code'); end; @@ -1437,6 +1464,12 @@ begin end; +procedure TProtocolDecorator.WriteUuid( const uuid: TGuid); +begin + FWrappedProtocol.WriteUuid( uuid); +end; + + function TProtocolDecorator.ReadMessageBegin: TThriftMessage; begin result := FWrappedProtocol.ReadMessageBegin; @@ -1551,6 +1584,12 @@ begin end; +function TProtocolDecorator.ReadUuid: TGuid; +begin + result := FWrappedProtocol.ReadUuid; +end; + + function TProtocolDecorator.ReadString: string; begin result := FWrappedProtocol.ReadString; diff --git a/lib/delphi/src/Thrift.Utils.pas b/lib/delphi/src/Thrift.Utils.pas index 4a75af8b7..122653572 100644 --- a/lib/delphi/src/Thrift.Utils.pas +++ b/lib/delphi/src/Thrift.Utils.pas @@ -84,11 +84,34 @@ type class function IsHtmlDoctype( const fourBytes : Integer) : Boolean; static; end; + + IntegerUtils = class sealed + strict private + class procedure SwapBytes( var one, two : Byte); static; inline; + class procedure Swap2( const pValue : Pointer); static; + class procedure Swap4( const pValue : Pointer); static; + class procedure Swap8( const pValue : Pointer); static; + public + class procedure SwapByteOrder( const pValue : Pointer; const size : Integer); overload; static; + end; + + + TGuidHelper = record helper for System.TGuid + public + function SwapByteOrder : TGuid; + + {$IFDEF Debug} + class procedure SelfTest; static; + {$ENDIF} + end; + + EnumUtils<T> = class sealed public class function ToString(const value : Integer) : string; reintroduce; static; inline; end; + StringUtils<T> = class sealed public class function ToString(const value : T) : string; reintroduce; static; inline; @@ -283,6 +306,97 @@ begin result := (UpCase(pc^) = HTML_BEGIN[3]); end; +{ IntegerUtils } + + +class procedure IntegerUtils.SwapBytes( var one, two : Byte); +var tmp : Byte; +begin + tmp := one; + one := two; + two := tmp; +end; + + +class procedure IntegerUtils.Swap2( const pValue : Pointer); +var pData : PByteArray absolute pValue; +begin + SwapBytes( pData^[0], pData^[1]); +end; + + +class procedure IntegerUtils.Swap4( const pValue : Pointer); +var pData : PByteArray absolute pValue; +begin + SwapBytes( pData^[0], pData^[3]); + SwapBytes( pData^[1], pData^[2]); +end; + + +class procedure IntegerUtils.Swap8( const pValue : Pointer); +var pData : PByteArray absolute pValue; +begin + SwapBytes( pData^[0], pData^[7]); + SwapBytes( pData^[1], pData^[6]); + SwapBytes( pData^[2], pData^[5]); + SwapBytes( pData^[3], pData^[4]); +end; + + +class procedure IntegerUtils.SwapByteOrder( const pValue : Pointer; const size : Integer); +begin + case size of + 2 : Swap2( pValue); + 4 : Swap4( pValue); + 8 : Swap8( pValue); + else + raise EArgumentException.Create('Unexpected size'); + end; +end; + + +{ TGuidHelper } + + +function TGuidHelper.SwapByteOrder : TGuid; +// convert to/from network byte order +// - https://www.ietf.org/rfc/rfc4122.txt +// - https://stackoverflow.com/questions/10850075/guid-uuid-compatibility-issue-between-net-and-linux +// - https://lists.gnu.org/archive/html/bug-parted/2002-01/msg00099.html +begin + result := Self; + + IntegerUtils.SwapByteOrder( @result.D1, SizeOf(result.D1)); + IntegerUtils.SwapByteOrder( @result.D2, SizeOf(result.D2)); + IntegerUtils.SwapByteOrder( @result.D3, SizeOf(result.D3)); + //result.D4 = array of byte -> implicitly correct +end; + + +{$IFDEF Debug} +class procedure TGuidHelper.SelfTest; +var guid : TGuid; + pBytes : PByteArray; + i, expected : Integer; +const TEST_GUID : TGuid = '{00112233-4455-6677-8899-aabbccddeeff}'; +begin + // host to network + guid := TEST_GUID; + guid := guid.SwapByteOrder; + + // validate network order + pBytes := @guid; + for i := 0 to $F do begin + expected := i * $11; + ASSERT( pBytes^[i] = expected); + end; + + // network to host and final validation + guid := guid.SwapByteOrder; + ASSERT( IsEqualGuid( guid, TEST_GUID)); +end; +{$ENDIF} + {$IFDEF Win64} @@ -378,4 +492,8 @@ begin end; +begin + {$IFDEF Debug} + TGuid.SelfTest; + {$ENDIF} end. diff --git a/lib/delphi/test/TestClient.pas b/lib/delphi/test/TestClient.pas index 040f815ce..86235ebaf 100644 --- a/lib/delphi/test/TestClient.pas +++ b/lib/delphi/test/TestClient.pas @@ -34,7 +34,7 @@ unit TestClient; interface uses - Windows, SysUtils, Classes, Math, ComObj, ActiveX, + Classes, Windows, SysUtils, Math, ActiveX, ComObj, {$IFDEF SupportsAsync} System.Threading, {$ENDIF} DateUtils, Generics.Collections, @@ -393,6 +393,7 @@ var i32 : Integer; i64 : Int64; binOut,binIn : TBytes; + guidIn, guidOut : TGuid; dub : Double; o : IXtruct; o2 : IXtruct2; @@ -543,6 +544,16 @@ begin i64 := client.testI64(-34359738368); Expect( i64 = -34359738368, 'testI64(-34359738368) = ' + IntToStr( i64)); + guidOut := StringToGUID('{00112233-4455-6677-8899-AABBCCDDEEFF}'); + Console.WriteLine('testUuid('+GUIDToString(guidOut)+')'); + try + guidIn := client.testUuid(guidOut); + Expect( IsEqualGUID(guidIn, guidOut), 'testUuid('+GUIDToString(guidOut)+') = '+GUIDToString(guidIn)); + except + on e:TApplicationException do Console.WriteLine('testUuid(): '+e.Message); + on e:Exception do Expect( FALSE, 'testUuid(): Unexpected exception "'+e.ClassName+'": '+e.Message); + end; + // random binary small for testsize := Low(TTestSize) to High(TTestSize) do begin binOut := PrepareBinaryData( TRUE, testsize); diff --git a/lib/delphi/test/TestServer.pas b/lib/delphi/test/TestServer.pas index d7cc02694..3ae82a1fc 100644 --- a/lib/delphi/test/TestServer.pas +++ b/lib/delphi/test/TestServer.pas @@ -67,6 +67,7 @@ type function testI64(const thing: Int64): Int64; function testDouble(const thing: Double): Double; function testBinary(const thing: TBytes): TBytes; + function testUuid(const thing: System.TGuid): System.TGuid; function testStruct(const thing: IXtruct): IXtruct; function testNest(const thing: IXtruct2): IXtruct2; function testMap(const thing: IThriftDictionary<Integer, Integer>): IThriftDictionary<Integer, Integer>; @@ -150,6 +151,12 @@ begin Result := thing; end; +function TTestServer.TTestHandlerImpl.testUuid(const thing: System.TGuid): System.TGuid; +begin + Console.WriteLine('testUuid('+GUIDToString(thing)+')'); + Result := thing; +end; + function TTestServer.TTestHandlerImpl.testEnum(thing: TNumberz): TNumberz; begin Console.WriteLine('testEnum(' + EnumUtils<TNumberz>.ToString(Ord(thing)) + ')'); diff --git a/lib/delphi/test/client.dproj b/lib/delphi/test/client.dproj index c57424db1..ae6683d99 100644 --- a/lib/delphi/test/client.dproj +++ b/lib/delphi/test/client.dproj @@ -1,22 +1,4 @@ -<!-- - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. ---> - <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> <ProjectGuid>{F262F488-F81C-4B6E-8694-518C54CBB8F3}</ProjectGuid> <MainSource>client.dpr</MainSource> @@ -142,7 +124,9 @@ <VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys> <VersionInfoKeys Name="Comments"/> </VersionInfoKeys> - <Parameters/> + <Parameters> + <Parameters Name="RunParams">--protocol=compact </Parameters> + </Parameters> </Delphi.Personality> <Platforms> <Platform value="Win32">True</Platform> diff --git a/lib/delphi/test/serializer/TestSerializer.Data.pas b/lib/delphi/test/serializer/TestSerializer.Data.pas index 4b8cc6696..269e307a6 100644 --- a/lib/delphi/test/serializer/TestSerializer.Data.pas +++ b/lib/delphi/test/serializer/TestSerializer.Data.pas @@ -23,6 +23,8 @@ interface uses SysUtils, + ActiveX, + ComObj, Thrift.Protocol, Thrift.Collections, DebugProtoTest; @@ -193,6 +195,8 @@ begin // !! result.setZomg_unicode( UnicodeString( us)); + result.Rfc4122_uuid := TGuid.Create('{00112233-4455-6677-8899-aabbccddeeff}'); + {$IF cDebugProtoTest_Option_AnsiStr_Binary} result.SetBase64('base64'); {$ELSEIF cDebugProtoTest_Option_COM_Types} diff --git a/lib/delphi/test/serializer/TestSerializer.Tests.pas b/lib/delphi/test/serializer/TestSerializer.Tests.pas index 443a22d5f..6ed1a48a2 100644 --- a/lib/delphi/test/serializer/TestSerializer.Tests.pas +++ b/lib/delphi/test/serializer/TestSerializer.Tests.pas @@ -43,6 +43,7 @@ uses System_, DebugProtoTest; +{$TYPEINFO ON} type TFactoryPair = record @@ -208,6 +209,7 @@ begin ASSERT( Abs( tested.Double_precision - correct.Double_precision) < 1E-12); ASSERT( tested.Some_characters = correct.Some_characters); ASSERT( tested.Zomg_unicode = correct.Zomg_unicode); + ASSERT( tested.Rfc4122_uuid = correct.Rfc4122_uuid); ASSERT( tested.What_who = correct.What_who); ASSERT( LengthOf(tested.Base64) = LengthOf(correct.Base64)); @@ -303,9 +305,9 @@ end; class function TTestSerializer.UserFriendlyName( const method : TMethod) : string; +const NAMES : array[TMethod] of string = ('TBytes','Stream'); begin - result := EnumUtils<TMethod>.ToString(Ord(method)); - result := StringReplace( result, 'mt_', '', [rfReplaceAll]); + result := NAMES[method]; end; @@ -342,7 +344,7 @@ var serial : TSerializer; config : IThriftConfiguration; begin config := TThriftConfigurationImpl.Create; - config.MaxMessageSize := 0; // we don't read anything here + //config.MaxMessageSize := 0; // we don't read anything here serial := TSerializer.Create( factory.prot, factory.trans, config); try @@ -358,7 +360,7 @@ var serial : TSerializer; config : IThriftConfiguration; begin config := TThriftConfigurationImpl.Create; - config.MaxMessageSize := 0; // we don't read anything here + //config.MaxMessageSize := 0; // we don't read anything here serial := TSerializer.Create( factory.prot, factory.trans, config); try diff --git a/lib/delphi/test/server.dproj b/lib/delphi/test/server.dproj index 9f7e5c647..151f7ee72 100644 --- a/lib/delphi/test/server.dproj +++ b/lib/delphi/test/server.dproj @@ -1,22 +1,4 @@ -<!-- - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. ---> - <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> <ProjectGuid>{07CEDA3D-0963-40FE-B3C2-0ED4E24DE067}</ProjectGuid> <MainSource>server.dpr</MainSource> @@ -140,6 +122,9 @@ <VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys> <VersionInfoKeys Name="Comments"/> </VersionInfoKeys> + <Parameters> + <Parameters Name="RunParams">--protocol=compact </Parameters> + </Parameters> </Delphi.Personality> <Platforms> <Platform value="Win32">True</Platform> diff --git a/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/optional_required_default.thrift b/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/optional_required_default.thrift index 4a38205dc..bf5a379b1 100644 --- a/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/optional_required_default.thrift +++ b/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/optional_required_default.thrift @@ -36,57 +36,63 @@ struct RaceDetails 2: optional double opt_two 3: optional i16 opt_three 4: optional string opt_four - 5: optional binary opt_five + 5: optional uuid opt_five 6: optional list<i32> opt_six 7: optional set<i64> opt_seven 8: optional map<i8,i16> opt_eight + 9: optional binary opt_nine 11: required Distance req_one 12: required double req_two 13: required i16 req_three 14: required string req_four - 15: required binary req_five + 15: required uuid req_five 16: required list<i32> req_six 17: required set<i64> req_seven 18: required map<i8,i16> req_eight + 19: required binary req_nine 21: Distance def_one 22: double def_two 23: i16 def_three 24: string def_four - 25: binary def_five + 25: uuid def_five 26: list<i32> def_six 27: set<i64> def_seven 28: map<i8,i16> def_eight - + 29: binary def_nine + // having default values 31: optional Distance opt_one_with_value = Distance.bar 32: optional double opt_two_with_value = 2.22 33: optional i16 opt_three_with_value = 3 34: optional string opt_four_with_value = "four" - 35: optional binary opt_five_with_value = "five\t" + 35: optional uuid opt_five_with_value = "55555555-5555-5555-5555-000000000000" 36: optional list<i32> opt_six_with_value = [6] 37: optional set<i64> opt_seven_with_value = [7] 38: optional map<i8,i16> opt_eight_with_value = { 8 : 8 } - + 39: optional binary opt_nine_with_value = "nine\t" + 41: required Distance req_one_with_value = Distance.bar 42: required double req_two_with_value = 2.22 43: required i16 req_three_with_value = 3 44: required string req_four_with_value = "four" - 45: required binary req_five_with_value = "five" + 45: required uuid req_five_with_value = "55555555-5555-5555-5555-000000000000" 46: required list<i32> req_six_with_value = [6] 47: required set<i64> req_seven_with_value = [7] 48: required map<i8,i16> req_eight_with_value = { 8 : 8 } + 49: required binary req_nine_with_value = "nine" 51: Distance def_one_with_value = Distance.bar 52: double def_two_with_value = 2.22 53: i16 def_three_with_value = 3 54: string def_four_with_value = "four" - 55: binary def_five_with_value = "five" + 55: uuid def_five_with_value = "55555555-5555-5555-5555-000000000000" 56: list<i32> def_six_with_value = [6] 57: set<i64> def_seven_with_value = [7] 58: map<i8,i16> def_eight_with_value = { 8 : 8 } + 59: binary def_nine_with_value = "nine" 90: optional bool last_of_the_mohicans @@ -124,10 +130,11 @@ union jack { 402: optional double opt_two 403: optional i16 opt_three 404: optional string opt_four - 405: optional binary opt_five + 405: optional uuid opt_five 406: optional list<i32> opt_six 407: optional set<i64> opt_seven 408: optional map<i8,i16> opt_eight + 409: optional binary opt_nine } typedef RaceDetails RaceDetails2 diff --git a/lib/netstd/Tests/Thrift.Tests/DataModel/DeepCopy.cs b/lib/netstd/Tests/Thrift.Tests/DataModel/DeepCopy.cs index afffed5f6..11b5af4ee 100644 --- a/lib/netstd/Tests/Thrift.Tests/DataModel/DeepCopy.cs +++ b/lib/netstd/Tests/Thrift.Tests/DataModel/DeepCopy.cs @@ -81,16 +81,18 @@ namespace Thrift.Tests.DataModel Assert.IsFalse(instance.__isset.opt_six); Assert.IsFalse(instance.__isset.opt_seven); Assert.IsFalse(instance.__isset.opt_eight); + Assert.IsFalse(instance.__isset.opt_nine); // set all required to null/default instance.Req_one = default; instance.Req_two = default; instance.Req_three = default; Assert.IsNotNull(instance.Req_four); - Assert.IsNotNull(instance.Req_five); - instance.Req_six = default; - instance.Req_seven = default;; + instance.Req_five = default; + instance.Req_six = default; + instance.Req_seven = default; instance.Req_eight = default; + Assert.IsNotNull(instance.Req_nine); // leave non-required fields unset again Assert.IsFalse(instance.__isset.def_one); @@ -101,6 +103,7 @@ namespace Thrift.Tests.DataModel Assert.IsFalse(instance.__isset.def_six); Assert.IsFalse(instance.__isset.def_seven); Assert.IsFalse(instance.__isset.def_eight); + Assert.IsFalse(instance.__isset.def_nine); // these should have IDL defaults set @@ -112,12 +115,13 @@ namespace Thrift.Tests.DataModel Assert.IsTrue(instance.__isset.opt_six_with_value); Assert.IsTrue(instance.__isset.opt_seven_with_value); Assert.IsTrue(instance.__isset.opt_eight_with_value); + Assert.IsTrue(instance.__isset.opt_nine_with_value); Assert.AreEqual(instance.Req_one_with_value, (Distance)1); Assert.AreEqual(instance.Req_two_with_value, 2.22); Assert.AreEqual(instance.Req_three_with_value, 3); Assert.AreEqual(instance.Req_four_with_value, "four"); - Assert.AreEqual("five", Encoding.UTF8.GetString(instance.Req_five_with_value!)); + Assert.AreEqual(new Guid("55555555-5555-5555-5555-000000000000"), instance.Req_five_with_value); Assert.IsTrue(instance.Req_six_with_value!.Count == 1); Assert.AreEqual(instance.Req_six_with_value[0], 6 ); @@ -128,6 +132,8 @@ namespace Thrift.Tests.DataModel Assert.IsTrue(instance.Req_eight_with_value!.Count == 1); Assert.IsTrue(instance.Req_eight_with_value[8] == 8); + Assert.AreEqual("nine", Encoding.UTF8.GetString(instance.Req_nine_with_value!)); + Assert.IsTrue(instance.__isset.def_one_with_value); Assert.IsTrue(instance.__isset.def_two_with_value); Assert.IsTrue(instance.__isset.def_three_with_value); @@ -136,6 +142,7 @@ namespace Thrift.Tests.DataModel Assert.IsTrue(instance.__isset.def_six_with_value); Assert.IsTrue(instance.__isset.def_seven_with_value); Assert.IsTrue(instance.__isset.def_eight_with_value); + Assert.IsTrue(instance.__isset.def_nine_with_value); instance.Last_of_the_mohicans = true; @@ -180,6 +187,7 @@ namespace Thrift.Tests.DataModel instance.Opt_six = ModifyValue(instance.Opt_six); instance.Opt_seven = ModifyValue(instance.Opt_seven); instance.Opt_eight = ModifyValue(instance.Opt_eight); + instance.Opt_nine = ModifyValue(instance.Opt_nine); instance.Req_one = ModifyValue(instance.Req_one); instance.Req_two = ModifyValue(instance.Req_two); @@ -189,6 +197,7 @@ namespace Thrift.Tests.DataModel instance.Req_six = ModifyValue(instance.Req_six); instance.Req_seven = ModifyValue(instance.Req_seven); instance.Req_eight = ModifyValue(instance.Req_eight); + instance.Req_nine = ModifyValue(instance.Req_nine); instance.Def_one = ModifyValue(instance.Def_one); instance.Def_two = ModifyValue(instance.Def_two); @@ -198,6 +207,7 @@ namespace Thrift.Tests.DataModel instance.Def_six = ModifyValue(instance.Def_six); instance.Def_seven = ModifyValue(instance.Def_seven); instance.Def_eight = ModifyValue(instance.Def_eight); + instance.Def_nine = ModifyValue(instance.Def_nine); instance.Opt_one_with_value = ModifyValue(instance.Opt_one_with_value); instance.Opt_two_with_value = ModifyValue(instance.Opt_two_with_value); @@ -207,6 +217,7 @@ namespace Thrift.Tests.DataModel instance.Opt_six_with_value = ModifyValue(instance.Opt_six_with_value); instance.Opt_seven_with_value = ModifyValue(instance.Opt_seven_with_value); instance.Opt_eight_with_value = ModifyValue(instance.Opt_eight_with_value); + instance.Opt_nine_with_value = ModifyValue(instance.Opt_nine_with_value); instance.Req_one_with_value = ModifyValue(instance.Req_one_with_value); instance.Req_two_with_value = ModifyValue(instance.Req_two_with_value); @@ -216,6 +227,7 @@ namespace Thrift.Tests.DataModel instance.Req_six_with_value = ModifyValue(instance.Req_six_with_value); instance.Req_seven_with_value = ModifyValue(instance.Req_seven_with_value); instance.Req_eight_with_value = ModifyValue(instance.Req_eight_with_value); + instance.Req_nine_with_value = ModifyValue(instance.Req_nine_with_value); instance.Def_one_with_value = ModifyValue(instance.Def_one_with_value); instance.Def_two_with_value = ModifyValue(instance.Def_two_with_value); @@ -225,6 +237,7 @@ namespace Thrift.Tests.DataModel instance.Def_six_with_value = ModifyValue(instance.Def_six_with_value); instance.Def_seven_with_value = ModifyValue(instance.Def_seven_with_value); instance.Def_eight_with_value = ModifyValue(instance.Def_eight_with_value); + instance.Def_nine_with_value = ModifyValue(instance.Def_nine_with_value); instance.Last_of_the_mohicans = ModifyValue(instance.Last_of_the_mohicans); @@ -435,6 +448,11 @@ namespace Thrift.Tests.DataModel return value + "1"; } + private static Guid ModifyValue(Guid value) + { + return new Guid( ModifyValue(value.ToByteArray())); + } + private static double ModifyValue(double value) { return value + 1.1; @@ -461,6 +479,7 @@ namespace Thrift.Tests.DataModel Assert.IsFalse(TCollections.Equals(first.Opt_six, second.Opt_six)); Assert.IsFalse(TCollections.Equals(first.Opt_seven, second.Opt_seven)); Assert.IsFalse(TCollections.Equals(first.Opt_eight, second.Opt_eight)); + Assert.IsFalse(TCollections.Equals(first.Opt_nine, second.Opt_nine)); Assert.AreNotEqual(first.Req_one, second.Req_one); Assert.AreNotEqual(first.Req_two, second.Req_two); @@ -470,6 +489,7 @@ namespace Thrift.Tests.DataModel Assert.IsFalse(TCollections.Equals(first.Req_six, second.Req_six)); Assert.IsFalse(TCollections.Equals(first.Req_seven, second.Req_seven)); Assert.IsFalse(TCollections.Equals(first.Req_eight, second.Req_eight)); + Assert.IsFalse(TCollections.Equals(first.Req_nine, second.Req_nine)); Assert.AreNotEqual(first.Def_one, second.Def_one); Assert.AreNotEqual(first.Def_two, second.Def_two); @@ -479,6 +499,7 @@ namespace Thrift.Tests.DataModel Assert.IsFalse(TCollections.Equals(first.Def_six, second.Def_six)); Assert.IsFalse(TCollections.Equals(first.Def_seven, second.Def_seven)); Assert.IsFalse(TCollections.Equals(first.Def_eight, second.Def_eight)); + Assert.IsFalse(TCollections.Equals(first.Def_nine, second.Def_nine)); Assert.AreNotEqual(first.Opt_one_with_value, second.Opt_one_with_value); Assert.AreNotEqual(first.Opt_two_with_value, second.Opt_two_with_value); @@ -488,6 +509,7 @@ namespace Thrift.Tests.DataModel Assert.IsFalse(TCollections.Equals(first.Opt_six_with_value, second.Opt_six_with_value)); Assert.IsFalse(TCollections.Equals(first.Opt_seven_with_value, second.Opt_seven_with_value)); Assert.IsFalse(TCollections.Equals(first.Opt_eight_with_value, second.Opt_eight_with_value)); + Assert.IsFalse(TCollections.Equals(first.Opt_nine_with_value, second.Opt_nine_with_value)); Assert.AreNotEqual(first.Req_one_with_value, second.Req_one_with_value); Assert.AreNotEqual(first.Req_two_with_value, second.Req_two_with_value); @@ -497,6 +519,7 @@ namespace Thrift.Tests.DataModel Assert.IsFalse(TCollections.Equals(first.Req_six_with_value, second.Req_six_with_value)); Assert.IsFalse(TCollections.Equals(first.Req_seven_with_value, second.Req_seven_with_value)); Assert.IsFalse(TCollections.Equals(first.Req_eight_with_value, second.Req_eight_with_value)); + Assert.IsFalse(TCollections.Equals(first.Req_nine_with_value, second.Req_nine_with_value)); Assert.AreNotEqual(first.Def_one_with_value, second.Def_one_with_value); Assert.AreNotEqual(first.Def_two_with_value, second.Def_two_with_value); @@ -506,6 +529,7 @@ namespace Thrift.Tests.DataModel Assert.IsFalse(TCollections.Equals(first.Def_six_with_value, second.Def_six_with_value)); Assert.IsFalse(TCollections.Equals(first.Def_seven_with_value, second.Def_seven_with_value)); Assert.IsFalse(TCollections.Equals(first.Def_eight_with_value, second.Def_eight_with_value)); + Assert.IsFalse(TCollections.Equals(first.Def_nine_with_value, second.Def_nine_with_value)); Assert.AreNotEqual(first.Last_of_the_mohicans, second.Last_of_the_mohicans); @@ -539,6 +563,7 @@ namespace Thrift.Tests.DataModel Assert.IsTrue(TCollections.Equals(first.Opt_six, second.Opt_six)); Assert.IsTrue(TCollections.Equals(first.Opt_seven, second.Opt_seven)); Assert.IsTrue(TCollections.Equals(first.Opt_eight, second.Opt_eight)); + Assert.IsTrue(TCollections.Equals(first.Opt_nine, second.Opt_nine)); Assert.AreEqual(first.Req_one, second.Req_one); Assert.AreEqual(first.Req_two, second.Req_two); @@ -548,6 +573,7 @@ namespace Thrift.Tests.DataModel Assert.IsTrue(TCollections.Equals(first.Req_six, second.Req_six)); Assert.IsTrue(TCollections.Equals(first.Req_seven, second.Req_seven)); Assert.IsTrue(TCollections.Equals(first.Req_eight, second.Req_eight)); + Assert.IsTrue(TCollections.Equals(first.Req_nine, second.Req_nine)); Assert.AreEqual(first.Def_one, second.Def_one); Assert.AreEqual(first.Def_two, second.Def_two); @@ -557,6 +583,7 @@ namespace Thrift.Tests.DataModel Assert.IsTrue(TCollections.Equals(first.Def_six, second.Def_six)); Assert.IsTrue(TCollections.Equals(first.Def_seven, second.Def_seven)); Assert.IsTrue(TCollections.Equals(first.Def_eight, second.Def_eight)); + Assert.IsTrue(TCollections.Equals(first.Def_nine, second.Def_nine)); Assert.AreEqual(first.Opt_one_with_value, second.Opt_one_with_value); Assert.AreEqual(first.Opt_two_with_value, second.Opt_two_with_value); @@ -566,6 +593,7 @@ namespace Thrift.Tests.DataModel Assert.IsTrue(TCollections.Equals(first.Opt_six_with_value, second.Opt_six_with_value)); Assert.IsTrue(TCollections.Equals(first.Opt_seven_with_value, second.Opt_seven_with_value)); Assert.IsTrue(TCollections.Equals(first.Opt_eight_with_value, second.Opt_eight_with_value)); + Assert.IsTrue(TCollections.Equals(first.Opt_nine_with_value, second.Opt_nine_with_value)); Assert.AreEqual(first.Req_one_with_value, second.Req_one_with_value); Assert.AreEqual(first.Req_two_with_value, second.Req_two_with_value); @@ -575,6 +603,7 @@ namespace Thrift.Tests.DataModel Assert.IsTrue(TCollections.Equals(first.Req_six_with_value, second.Req_six_with_value)); Assert.IsTrue(TCollections.Equals(first.Req_seven_with_value, second.Req_seven_with_value)); Assert.IsTrue(TCollections.Equals(first.Req_eight_with_value, second.Req_eight_with_value)); + Assert.IsTrue(TCollections.Equals(first.Req_nine_with_value, second.Req_nine_with_value)); Assert.AreEqual(first.Def_one_with_value, second.Def_one_with_value); Assert.AreEqual(first.Def_two_with_value, second.Def_two_with_value); @@ -584,6 +613,7 @@ namespace Thrift.Tests.DataModel Assert.IsTrue(TCollections.Equals(first.Def_six_with_value, second.Def_six_with_value)); Assert.IsTrue(TCollections.Equals(first.Def_seven_with_value, second.Def_seven_with_value)); Assert.IsTrue(TCollections.Equals(first.Def_eight_with_value, second.Def_eight_with_value)); + Assert.IsTrue(TCollections.Equals(first.Def_nine_with_value, second.Def_nine_with_value)); Assert.AreEqual(first.Last_of_the_mohicans, second.Last_of_the_mohicans); diff --git a/lib/netstd/Tests/Thrift.Tests/DataModel/NullValuesSet.cs b/lib/netstd/Tests/Thrift.Tests/DataModel/NullValuesSet.cs index ebc171747..80eacc258 100644 --- a/lib/netstd/Tests/Thrift.Tests/DataModel/NullValuesSet.cs +++ b/lib/netstd/Tests/Thrift.Tests/DataModel/NullValuesSet.cs @@ -48,19 +48,19 @@ namespace Thrift.Tests.DataModel Assert.IsNull(instance.Def_four); Assert.IsNull(instance.Opt_four); - // byte[] - Assert.IsTrue(instance.__isset.def_five); - Assert.IsTrue(instance.__isset.opt_five); - Assert.IsTrue((instance.Req_five == null) || (instance.Req_five.Length == 0)); - Assert.IsNull(instance.Def_five); - Assert.IsNull(instance.Opt_five); - // list<> Assert.IsTrue(instance.__isset.def_six); Assert.IsTrue(instance.__isset.opt_six); Assert.IsNull(instance.Req_six); Assert.IsNull(instance.Opt_six); Assert.IsNull(instance.Def_six); + + // byte[] + Assert.IsTrue(instance.__isset.def_nine); + Assert.IsTrue(instance.__isset.opt_nine); + Assert.IsTrue((instance.Req_nine == null) || (instance.Req_nine.Length == 0)); + Assert.IsNull(instance.Def_nine); + Assert.IsNull(instance.Opt_nine); } [TestMethod] @@ -80,27 +80,27 @@ namespace Thrift.Tests.DataModel instance.Def_four = null; instance.Opt_four = null; - // byte[] - instance.Req_five = null; - instance.Def_five = null; - instance.Opt_five = null; - // list<> instance.Req_six = null; instance.Opt_six = null; instance.Def_six = null; + // byte[] + instance.Req_nine = null; + instance.Def_nine = null; + instance.Opt_nine = null; + // back to normal #pragma warning restore CS8625 // test the setup CheckInstance(instance); - // validate proper null checks , any of these throws if not + // validate proper null checks, any of these throws if not instance.ToString(); instance.GetHashCode(); - // validate proper null checks , any of these throws if not + // validate proper null checks, any of these throws if not var copy = instance.DeepCopy(); CheckInstance(copy); } diff --git a/lib/netstd/Thrift/Protocol/Entities/TType.cs b/lib/netstd/Thrift/Protocol/Entities/TType.cs index 4e922a7e7..2f3037b86 100644 --- a/lib/netstd/Thrift/Protocol/Entities/TType.cs +++ b/lib/netstd/Thrift/Protocol/Entities/TType.cs @@ -32,6 +32,7 @@ namespace Thrift.Protocol.Entities Struct = 12, Map = 13, Set = 14, - List = 15 + List = 15, + Uuid = 16 } -}
\ No newline at end of file +} diff --git a/lib/netstd/Thrift/Protocol/TBinaryProtocol.cs b/lib/netstd/Thrift/Protocol/TBinaryProtocol.cs index eee137ca1..ba2a7abbc 100644 --- a/lib/netstd/Thrift/Protocol/TBinaryProtocol.cs +++ b/lib/netstd/Thrift/Protocol/TBinaryProtocol.cs @@ -21,6 +21,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using Thrift.Protocol.Entities; +using Thrift.Protocol.Utilities; using Thrift.Transport; @@ -209,6 +210,14 @@ namespace Thrift.Protocol await Trans.WriteAsync(bytes, 0, bytes.Length, cancellationToken); } + public override async Task WriteUuidAsync(Guid uuid, CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + + var bytes = uuid.SwapByteOrder().ToByteArray(); + await Trans.WriteAsync(bytes, 0, bytes.Length, cancellationToken); + } + public override async ValueTask<TMessage> ReadMessageBeginAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -401,6 +410,16 @@ namespace Thrift.Protocol return buf; } + public override async ValueTask<Guid> ReadUuidAsync(CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + + Transport.CheckReadBytesAvailable(16); // = sizeof(uuid) + var buf = new byte[16]; + await Trans.ReadAllAsync(buf, 0, 16, cancellationToken); + return new Guid(buf).SwapByteOrder(); + } + public override async ValueTask<string> ReadStringAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -443,6 +462,7 @@ namespace Thrift.Protocol case TType.Map: return sizeof(int); // element count case TType.Set: return sizeof(int); // element count case TType.List: return sizeof(int); // element count + case TType.Uuid: return 16; // uuid bytes default: throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED, "unrecognized type code"); } } diff --git a/lib/netstd/Thrift/Protocol/TCompactProtocol.cs b/lib/netstd/Thrift/Protocol/TCompactProtocol.cs index 6893ad476..b899d3dbc 100644 --- a/lib/netstd/Thrift/Protocol/TCompactProtocol.cs +++ b/lib/netstd/Thrift/Protocol/TCompactProtocol.cs @@ -24,6 +24,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using Thrift.Protocol.Entities; +using Thrift.Protocol.Utilities; using Thrift.Transport; @@ -43,8 +44,8 @@ namespace Thrift.Protocol private const byte NoTypeOverride = 0xFF; // ReSharper disable once InconsistentNaming - private static readonly byte[] TTypeToCompactType = new byte[16]; - private static readonly TType[] CompactTypeToTType = new TType[13]; + private static readonly byte[] TTypeToCompactType = new byte[17]; + private static readonly TType[] CompactTypeToTType = new TType[14]; /// <summary> /// Used to keep track of the last field for the current and previous structs, so we can do the delta stuff. @@ -86,18 +87,19 @@ namespace Thrift.Protocol public TCompactProtocol(TTransport trans) : base(trans) { - TTypeToCompactType[(int) TType.Stop] = Types.Stop; - TTypeToCompactType[(int) TType.Bool] = Types.BooleanTrue; - TTypeToCompactType[(int) TType.Byte] = Types.Byte; - TTypeToCompactType[(int) TType.I16] = Types.I16; - TTypeToCompactType[(int) TType.I32] = Types.I32; - TTypeToCompactType[(int) TType.I64] = Types.I64; - TTypeToCompactType[(int) TType.Double] = Types.Double; - TTypeToCompactType[(int) TType.String] = Types.Binary; - TTypeToCompactType[(int) TType.List] = Types.List; - TTypeToCompactType[(int) TType.Set] = Types.Set; - TTypeToCompactType[(int) TType.Map] = Types.Map; - TTypeToCompactType[(int) TType.Struct] = Types.Struct; + TTypeToCompactType[(int)TType.Stop] = Types.Stop; + TTypeToCompactType[(int)TType.Bool] = Types.BooleanTrue; + TTypeToCompactType[(int)TType.Byte] = Types.Byte; + TTypeToCompactType[(int)TType.I16] = Types.I16; + TTypeToCompactType[(int)TType.I32] = Types.I32; + TTypeToCompactType[(int)TType.I64] = Types.I64; + TTypeToCompactType[(int)TType.Double] = Types.Double; + TTypeToCompactType[(int)TType.String] = Types.Binary; + TTypeToCompactType[(int)TType.List] = Types.List; + TTypeToCompactType[(int)TType.Set] = Types.Set; + TTypeToCompactType[(int)TType.Map] = Types.Map; + TTypeToCompactType[(int)TType.Struct] = Types.Struct; + TTypeToCompactType[(int)TType.Uuid] = Types.Uuid; CompactTypeToTType[Types.Stop] = TType.Stop; CompactTypeToTType[Types.BooleanTrue] = TType.Bool; @@ -112,6 +114,7 @@ namespace Thrift.Protocol CompactTypeToTType[Types.Set] = TType.Set; CompactTypeToTType[Types.Map] = TType.Map; CompactTypeToTType[Types.Struct] = TType.Struct; + CompactTypeToTType[Types.Uuid] = TType.Uuid; } public void Reset() @@ -395,6 +398,14 @@ namespace Thrift.Protocol await Trans.WriteAsync(bytes, 0, bytes.Length, cancellationToken); } + public override async Task WriteUuidAsync(Guid uuid, CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + + var bytes = uuid.SwapByteOrder().ToByteArray(); + await Trans.WriteAsync(bytes, 0, bytes.Length, cancellationToken); + } + public override async Task WriteMapBeginAsync(TMap map, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -665,6 +676,16 @@ namespace Thrift.Protocol return buf; } + public override async ValueTask<Guid> ReadUuidAsync(CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + + Transport.CheckReadBytesAvailable(16); // = sizeof(uuid) + var buf = new byte[16]; + await Trans.ReadAllAsync(buf, 0, 16, cancellationToken); + return new Guid(buf).SwapByteOrder(); + } + public override async ValueTask<TList> ReadListBeginAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -792,19 +813,20 @@ namespace Thrift.Protocol { switch (type) { - case TType.Stop: return 0; - case TType.Void: return 0; - case TType.Bool: return sizeof(byte); + case TType.Stop: return 0; + case TType.Void: return 0; + case TType.Bool: return sizeof(byte); case TType.Double: return 8; // uses fixedLongToBytes() which always writes 8 bytes case TType.Byte: return sizeof(byte); - case TType.I16: return sizeof(byte); // zigzag - case TType.I32: return sizeof(byte); // zigzag - case TType.I64: return sizeof(byte); // zigzag + case TType.I16: return sizeof(byte); // zigzag + case TType.I32: return sizeof(byte); // zigzag + case TType.I64: return sizeof(byte); // zigzag case TType.String: return sizeof(byte); // string length - case TType.Struct: return 0; // empty struct - case TType.Map: return sizeof(byte); // element count - case TType.Set: return sizeof(byte); // element count - case TType.List: return sizeof(byte); // element count + case TType.Struct: return 0; // empty struct + case TType.Map: return sizeof(byte); // element count + case TType.Set: return sizeof(byte); // element count + case TType.List: return sizeof(byte); // element count + case TType.Uuid: return 16; // uuid bytes default: throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED, "unrecognized type code"); } } @@ -835,6 +857,7 @@ namespace Thrift.Protocol public const byte Set = 0x0A; public const byte Map = 0x0B; public const byte Struct = 0x0C; + public const byte Uuid = 0x0D; } } } diff --git a/lib/netstd/Thrift/Protocol/TJSONProtocol.cs b/lib/netstd/Thrift/Protocol/TJSONProtocol.cs index 8799026ba..c100d8627 100644 --- a/lib/netstd/Thrift/Protocol/TJSONProtocol.cs +++ b/lib/netstd/Thrift/Protocol/TJSONProtocol.cs @@ -401,6 +401,10 @@ namespace Thrift.Protocol { await WriteJsonBase64Async(bytes, cancellationToken); } + public override async Task WriteUuidAsync(Guid uuid, CancellationToken cancellationToken = default) + { + await WriteStringAsync(uuid.ToString("D"), cancellationToken); // no curly braces + } /// <summary> /// Read in a JSON string, unescaping as appropriate.. Skip Reading from the @@ -817,6 +821,11 @@ namespace Thrift.Protocol return await ReadJsonBase64Async(cancellationToken); } + public override async ValueTask<Guid> ReadUuidAsync(CancellationToken cancellationToken = default) + { + return new Guid( await ReadStringAsync(cancellationToken)); + } + // Return the minimum number of bytes a type will consume on the wire public override int GetMinSerializedSize(TType type) { @@ -835,6 +844,7 @@ namespace Thrift.Protocol case TType.Map: return 2; // empty map case TType.Set: return 2; // empty set case TType.List: return 2; // empty list + case TType.Uuid: return 36; // "E236974D-F0B0-4E05-8F29-0B455D41B1A1" default: throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED, "unrecognized type code"); } } diff --git a/lib/netstd/Thrift/Protocol/TProtocol.cs b/lib/netstd/Thrift/Protocol/TProtocol.cs index cd9383389..f2bec6000 100644 --- a/lib/netstd/Thrift/Protocol/TProtocol.cs +++ b/lib/netstd/Thrift/Protocol/TProtocol.cs @@ -148,6 +148,7 @@ namespace Thrift.Protocol } public abstract Task WriteBinaryAsync(byte[] bytes, CancellationToken cancellationToken = default); + public abstract Task WriteUuidAsync(Guid uuid, CancellationToken cancellationToken = default); public abstract ValueTask<TMessage> ReadMessageBeginAsync(CancellationToken cancellationToken = default); @@ -192,5 +193,7 @@ namespace Thrift.Protocol } public abstract ValueTask<byte[]> ReadBinaryAsync(CancellationToken cancellationToken = default); + + public abstract ValueTask<Guid> ReadUuidAsync(CancellationToken cancellationToken = default); } } diff --git a/lib/netstd/Thrift/Protocol/TProtocolDecorator.cs b/lib/netstd/Thrift/Protocol/TProtocolDecorator.cs index b032e836a..1ea9fb9ae 100644 --- a/lib/netstd/Thrift/Protocol/TProtocolDecorator.cs +++ b/lib/netstd/Thrift/Protocol/TProtocolDecorator.cs @@ -144,6 +144,11 @@ namespace Thrift.Protocol await _wrappedProtocol.WriteBinaryAsync(bytes, cancellationToken); } + public override async Task WriteUuidAsync(Guid uuid, CancellationToken cancellationToken) + { + await _wrappedProtocol.WriteUuidAsync(uuid, cancellationToken); + } + public override async ValueTask<TMessage> ReadMessageBeginAsync(CancellationToken cancellationToken) { return await _wrappedProtocol.ReadMessageBeginAsync(cancellationToken); @@ -244,6 +249,11 @@ namespace Thrift.Protocol return await _wrappedProtocol.ReadBinaryAsync(cancellationToken); } + public override async ValueTask<Guid> ReadUuidAsync(CancellationToken cancellationToken) + { + return await _wrappedProtocol.ReadUuidAsync(cancellationToken); + } + // Returns the minimum amount of bytes needed to store the smallest possible instance of TType. public override int GetMinSerializedSize(TType type) { diff --git a/lib/netstd/Thrift/Protocol/Utilities/TGuidExtensions.cs b/lib/netstd/Thrift/Protocol/Utilities/TGuidExtensions.cs new file mode 100644 index 000000000..190ddbbc5 --- /dev/null +++ b/lib/netstd/Thrift/Protocol/Utilities/TGuidExtensions.cs @@ -0,0 +1,82 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; + +namespace Thrift.Protocol.Utilities +{ + public static class TGuidExtensions + { + public static Guid SwapByteOrder(this Guid self) + { + var bytes = self.ToByteArray(); + + // already network order on BigEndian machines + if (BitConverter.IsLittleEndian) + { + SwapBytes(ref bytes[0], ref bytes[3]); + SwapBytes(ref bytes[1], ref bytes[2]); + SwapBytes(ref bytes[4], ref bytes[5]); + SwapBytes(ref bytes[6], ref bytes[7]); + } + + return new Guid(bytes); + } + + private static void SwapBytes(ref byte one, ref byte two) + { + var tmp = one; + one = two; + two = tmp; + } + + #region SelfTest +#if DEBUG + static private readonly Guid TEST_GUID = new Guid("{00112233-4455-6677-8899-aabbccddeeff}"); + + static TGuidExtensions() + { + SelfTest(); + } + + private static void SelfTest() + { + // host to network + var guid = TEST_GUID; + guid = guid.SwapByteOrder(); + + // validate network order + var bytes = guid.ToByteArray(); + for (var i = 0; i < 10; ++i) + { + var expected = i * 0x11; + Debug.Assert( bytes[i] == expected); + } + + // network to host and final validation + guid = guid.SwapByteOrder(); + Debug.Assert(guid.Equals(TEST_GUID)); + } + +#endif + #endregion + + } +} diff --git a/lib/netstd/Thrift/Protocol/Utilities/TJsonProtocolConstants.cs b/lib/netstd/Thrift/Protocol/Utilities/TJsonProtocolConstants.cs index 6cc1302e9..f8c261aa8 100644 --- a/lib/netstd/Thrift/Protocol/Utilities/TJsonProtocolConstants.cs +++ b/lib/netstd/Thrift/Protocol/Utilities/TJsonProtocolConstants.cs @@ -1,4 +1,4 @@ -// Licensed to the Apache Software Foundation(ASF) under one +// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file @@ -56,6 +56,7 @@ namespace Thrift.Protocol.Utilities public static readonly byte[] NameMap = { (byte)'m', (byte)'a', (byte)'p' }; public static readonly byte[] NameList = { (byte)'l', (byte)'s', (byte)'t' }; public static readonly byte[] NameSet = { (byte)'s', (byte)'e', (byte)'t' }; + public static readonly byte[] NameUuid = { (byte)'u', (byte)'i', (byte)'d' }; } } -}
\ No newline at end of file +} diff --git a/lib/netstd/Thrift/Protocol/Utilities/TJsonProtocolHelper.cs b/lib/netstd/Thrift/Protocol/Utilities/TJsonProtocolHelper.cs index ff49ebe24..67c7bc065 100644 --- a/lib/netstd/Thrift/Protocol/Utilities/TJsonProtocolHelper.cs +++ b/lib/netstd/Thrift/Protocol/Utilities/TJsonProtocolHelper.cs @@ -1,4 +1,4 @@ -// Licensed to the Apache Software Foundation(ASF) under one +// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file @@ -48,6 +48,8 @@ namespace Thrift.Protocol.Utilities return TJSONProtocolConstants.TypeNames.NameSet; case TType.List: return TJSONProtocolConstants.TypeNames.NameList; + case TType.Uuid: + return TJSONProtocolConstants.TypeNames.NameUuid; default: throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED, "Unrecognized exType"); } @@ -102,6 +104,9 @@ namespace Thrift.Protocol.Utilities case (byte) 't': result = TType.Bool; break; + case (byte)'u': + result = TType.Uuid; + break; } } if (result == TType.Stop) @@ -173,4 +178,4 @@ namespace Thrift.Protocol.Utilities return (byte)((char)val + 'a'); } } -}
\ No newline at end of file +} diff --git a/lib/netstd/Thrift/Protocol/Utilities/TProtocolUtil.cs b/lib/netstd/Thrift/Protocol/Utilities/TProtocolUtil.cs index 832e46e6c..3c8b37ae3 100644 --- a/lib/netstd/Thrift/Protocol/Utilities/TProtocolUtil.cs +++ b/lib/netstd/Thrift/Protocol/Utilities/TProtocolUtil.cs @@ -55,6 +55,9 @@ namespace Thrift.Protocol.Utilities // Don't try to decode the string, just skip it. await protocol.ReadBinaryAsync(cancellationToken); break; + case TType.Uuid: + await protocol.ReadUuidAsync(cancellationToken); + break; case TType.Struct: await protocol.ReadStructBeginAsync(cancellationToken); while (true) diff --git a/test/ConstantsDemo.thrift b/test/ConstantsDemo.thrift index 204e805b1..e03f0537d 100644 --- a/test/ConstantsDemo.thrift +++ b/test/ConstantsDemo.thrift @@ -65,6 +65,8 @@ const map<i32,thing> GEN_WHAT = { 35 : { 'hello' : 325, 'goodbye' : 325352 } } const set<i32> GEN_SET = [ 235, 235, 53235 ] +const uuid GEN_UUID = "00000000-4444-CCCC-ffff-0123456789ab" + exception Blah { 1: i32 bing } diff --git a/test/DebugProtoTest.thrift b/test/DebugProtoTest.thrift index 5d0face4b..3750d8d93 100644 --- a/test/DebugProtoTest.thrift +++ b/test/DebugProtoTest.thrift @@ -48,6 +48,7 @@ struct OneOfEach { 12: list<i8> byte_list = [1, 2, 3], 13: list<i16> i16_list = [1,2,3], 14: list<i64> i64_list = [1,2,3] + 15: uuid rfc4122_uuid } struct Bonk { diff --git a/test/ThriftTest.thrift b/test/ThriftTest.thrift index 4a1045fcd..42607cc35 100644 --- a/test/ThriftTest.thrift +++ b/test/ThriftTest.thrift @@ -112,6 +112,7 @@ struct CrazyNesting { // Do not insert line break as test/go/Makefile.am is removing this line with pattern match 3: required list<map<set<i32> (python.immutable = ""), map<i32,set<list<map<Insanity,string>(python.immutable = "")> (python.immutable = "")>>>> list_field, 4: binary binary_field + 5: uuid uuid_field } union SomeUnion { @@ -196,6 +197,13 @@ service ThriftTest binary testBinary(1: binary thing), /** + * Prints 'testUuid("%s")' where '%s' is the uuid given. Note that the uuid byte order should be correct. + * @param uuid thing - the uuid to print + * @return uuid - returns the uuid 'thing' + */ + uuid testUuid(1: uuid thing), + + /** * Prints 'testStruct("{%s}")' where thing has been formatted into a string of comma separated values * @param Xtruct thing - the Xtruct to print * @return Xtruct - returns the Xtruct 'thing' diff --git a/test/netstd/Client/TestClient.cs b/test/netstd/Client/TestClient.cs index 29c0d2ef3..4700de88b 100644 --- a/test/netstd/Client/TestClient.cs +++ b/test/netstd/Client/TestClient.cs @@ -588,8 +588,28 @@ namespace ThriftTest returnCode |= ErrorBaseTypes; } + // testUuid() + var uuidOut = new Guid("{00112233-4455-6677-8899-AABBCCDDEEFF}"); + Console.Write("testUuid({0})", uuidOut); + try + { + var uuidIn = await client.testUuid(uuidOut, MakeTimeoutToken()); + Console.WriteLine(" = {0}", uuidIn); + if (!uuidIn.Equals(uuidOut)) + { + Console.WriteLine("*** FAILED ***"); + returnCode |= ErrorBaseTypes; + } + } + catch (Thrift.TApplicationException ex) + { + Console.WriteLine("*** FAILED ***"); + returnCode |= ErrorBaseTypes; + Console.WriteLine(ex.Message + "\n" + ex.StackTrace); + } + // testBinary() - foreach(BinaryTestSize binTestCase in Enum.GetValues(typeof(BinaryTestSize))) + foreach (BinaryTestSize binTestCase in Enum.GetValues(typeof(BinaryTestSize))) { var binOut = PrepareTestData(true, binTestCase); diff --git a/test/netstd/Server/Server.csproj b/test/netstd/Server/Server.csproj index 8faad9dc9..0a78e8836 100644 --- a/test/netstd/Server/Server.csproj +++ b/test/netstd/Server/Server.csproj @@ -1,4 +1,4 @@ -<Project Sdk="Microsoft.NET.Sdk"> +<Project Sdk="Microsoft.NET.Sdk"> <!-- Licensed to the Apache Software Foundation(ASF) under one or more contributor license agreements.See the NOTICE file diff --git a/test/netstd/Server/TestServer.cs b/test/netstd/Server/TestServer.cs index 86072b0a7..71a2a30a1 100644 --- a/test/netstd/Server/TestServer.cs +++ b/test/netstd/Server/TestServer.cs @@ -271,6 +271,12 @@ namespace ThriftTest return Task.FromResult(thing ?? Array.Empty<byte>()); } + public Task<Guid> testUuid(Guid thing, CancellationToken cancellationToken) + { + logger.Invoke("testUuid({0})", thing.ToString("B")); + return Task.FromResult(thing); + } + public Task<Xtruct> testStruct(Xtruct? thing, CancellationToken cancellationToken) { logger.Invoke("testStruct({{\"{0}\", {1}, {2}, {3}}})", thing?.String_thing ?? "<null>", thing?.Byte_thing ?? 0, thing?.I32_thing ?? 0, thing?.I64_thing ?? 0); |