From 2375312fa05e1560f0fc83c642dcb2535d9d2eba Mon Sep 17 00:00:00 2001 From: David Reiss Date: Mon, 27 Aug 2007 19:57:34 +0000 Subject: [PATCH] Thrift: Limited Reflection for C++. Summary: The Thrift compiler now generates static methods for every service to generate a reflection of the methods provided by the service. This reflection is fairly limited, but should be enough for what we want to do with SMC. Reviewed By: mcslee Test Plan: test/ReflectionTest.cpp Revert Plan: ok git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@665226 13f79535-47bb-0310-9956-ffa450edef68 --- cleanup.sh | 3 +- compiler/cpp/src/generate/t_cpp_generator.cc | 178 +++++++ compiler/cpp/src/generate/t_cpp_generator.h | 6 +- if/reflection_limited.thrift | 70 +++ if/regen.sh | 5 + lib/cpp/Makefile.am | 2 + lib/cpp/src/TLogging.h | 6 +- lib/cpp/src/reflection_limited_types.cpp | 489 +++++++++++++++++++ lib/cpp/src/reflection_limited_types.h | 266 ++++++++++ test/DebugProtoTest.thrift | 10 + test/ReflectionTest.cpp | 30 ++ 11 files changed, 1060 insertions(+), 5 deletions(-) create mode 100644 if/reflection_limited.thrift create mode 100755 if/regen.sh create mode 100644 lib/cpp/src/reflection_limited_types.cpp create mode 100644 lib/cpp/src/reflection_limited_types.h create mode 100644 test/ReflectionTest.cpp diff --git a/cleanup.sh b/cleanup.sh index c78c3fc1..5c0046dd 100755 --- a/cleanup.sh +++ b/cleanup.sh @@ -28,7 +28,8 @@ install-sh \ .libs \ libtool \ ltmain.sh \ -missing +missing \ +if/gen-* for subdir in ${subdirs}; do if [ -x "${subdir}/cleanup.sh" ]; then diff --git a/compiler/cpp/src/generate/t_cpp_generator.cc b/compiler/cpp/src/generate/t_cpp_generator.cc index 796c9e0f..8580e2ac 100644 --- a/compiler/cpp/src/generate/t_cpp_generator.cc +++ b/compiler/cpp/src/generate/t_cpp_generator.cc @@ -7,6 +7,7 @@ #include #include #include +#include #include "t_cpp_generator.h" using namespace std; @@ -42,6 +43,7 @@ void t_cpp_generator::init_generator() { // Include base types f_types_ << "#include " << endl << + "#include " << endl << "#include " << endl << "#include " << endl << endl; @@ -891,6 +893,8 @@ void t_cpp_generator::generate_service_helpers(t_service* tservice) { generate_function_helpers(tservice, *f_iter); } + + generate_service_limited_reflector(tservice); } /** @@ -909,6 +913,20 @@ void t_cpp_generator::generate_service_interface(t_service* tservice) { indent_up(); f_header_ << indent() << "virtual ~" << service_name_ << "If() {}" << endl; + + f_header_ << + indent() << "static void getStaticLimitedReflection" << + "(facebook::thrift::reflection::limited::Service & _return);" << endl; + // TODO(dreiss): Uncomment and test this if we decide we need + // a virtual function with this effect. + //f_header_ << + // indent() << "virtual void getVirtualLimitedReflection" << + // "(facebook::thrift::reflection::limited::Service & _return) "; + //scope_up(f_header_); + //f_header_ << + // indent() << "getStaticLimitedReflection(_return);" << endl; + //scope_down(f_header_); + vector functions = tservice->get_functions(); vector::iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { @@ -1670,6 +1688,166 @@ void t_cpp_generator::generate_process_function(t_service* tservice, f_service_ << endl; } +/** + * Helper function for generate_service_limited_reflector. + * Generates a reflection of a single simple type. + * + * @param ttype The type to reflect + * @param target The name of the lvalue to reflect onto + * @return true iff the type really is simple + * + * Note: don't let this function output anything unless it is going to return true. + */ +bool t_cpp_generator::generate_simple_type_limited_reflection(ostream & out, t_type* ttype, string target) { + if (ttype->is_base_type()) { + string type; + switch (((t_base_type*)ttype)->get_base()) { + case t_base_type::TYPE_VOID : type = "T_VOID;" ; break; + case t_base_type::TYPE_STRING : type = "T_STRING;" ; break; + case t_base_type::TYPE_BOOL : type = "T_BOOL;" ; break; + case t_base_type::TYPE_BYTE : type = "T_BYTE;" ; break; + case t_base_type::TYPE_I16 : type = "T_I16;" ; break; + case t_base_type::TYPE_I32 : type = "T_I32;" ; break; + case t_base_type::TYPE_I64 : type = "T_I64;" ; break; + case t_base_type::TYPE_DOUBLE : type = "T_DOUBLE;" ; break; + default: return false; + } + out << indent() << target << ".ttype = " << type << endl; + return true; + } + + if (ttype->is_enum()) { + out << + indent() << target << ".ttype = T_ENUM;" << endl << + indent() << target << ".name = \"" << ttype->get_name() << "\";" << endl; + } + + if (ttype->is_struct()) { + out << + indent() << target << ".ttype = T_STRUCT;" << endl << + indent() << target << ".name = \"" << ttype->get_name() << "\";" << endl; + return true; + } + + return false; +} + +/** + * Helper function for generate_service_limited_reflector. + * Generates a reflection of a single type. + * + * @param ttype The type to reflect + * @param target The name of the lvalue to reflect onto + */ +bool t_cpp_generator::generate_type_limited_reflection(t_type* ttype, string target) { + bool is_simple = generate_simple_type_limited_reflection(f_service_, ttype, target + ".simple_type"); + if (is_simple) { + f_service_ << + indent() << target << ".is_container = false;" << endl << + indent() << target << ".__isset.simple_type = true;" << endl; + return true; + } + + ostringstream out; + + out << + indent() << target << ".is_container = true;" << endl << + indent() << target << ".__isset.container_type = true;" << endl << + indent() << target << ".container_type.ttype = "; + + if (ttype->is_list()) out << "T_LIST;" << endl; + if (ttype->is_set()) out << "T_SET;" << endl; + if (ttype->is_map()) out << "T_MAP;" << endl; + + bool reflected = false; + + if (ttype->is_list()) { + reflected = generate_simple_type_limited_reflection( + out, ((t_list*)ttype)->get_elem_type(), target + ".container_type.subtype1"); + } + if (ttype->is_set()) { + reflected = generate_simple_type_limited_reflection( + out, ((t_set*)ttype)->get_elem_type(), target + ".container_type.subtype1"); + } + if (ttype->is_map()) { + reflected = + generate_simple_type_limited_reflection( + out, ((t_map*)ttype)->get_key_type(), target + ".container_type.subtype1") + && + generate_simple_type_limited_reflection( + out, ((t_map*)ttype)->get_val_type(), target + ".container_type.subtype2"); + out << indent() << target << ".container_type.__isset.subtype2 = true;" << endl; + } + + if (reflected) { + f_service_ << out.str(); + return true; + } else { + f_service_ << + indent() << target << ".is_container = false;" << endl << + indent() << target << ".__isset.simple_type = true;" << endl; + f_service_ << indent() << target << ".simple_type.ttype = T_NOT_REFLECTED;" << endl; + return false; + } +} + +/** + * Generates a service reflector definition. + * This uses thrift::reflection::limited. + * + * @param tservice The service to write a reflector for + */ +void t_cpp_generator::generate_service_limited_reflector(t_service* tservice) { + // Open function + f_service_ << + indent() << "void " << tservice->get_name() << "If::getStaticLimitedReflection" << + "(facebook::thrift::reflection::limited::Service & _return) "; + scope_up(f_service_); + + f_service_ << indent() << "using namespace facebook::thrift::reflection::limited;" << endl; + + f_service_ << indent() << "_return.name = \"" << tservice->get_name() << "\";" << endl; + f_service_ << indent() << "_return.fully_reflected = true;" << endl; + + bool all_reflectable = true; + bool one_reflectable; + + const vector & funcs = tservice->get_functions(); + vector::const_iterator f_iter; + for (f_iter = funcs.begin(); f_iter != funcs.end(); ++f_iter) { + + f_service_ << indent() << "_return.methods.resize(_return.methods.size() + 1);" << endl; + f_service_ << indent() << "_return.methods.back().name = \"" << (*f_iter)->get_name() << "\";" << endl; + one_reflectable = generate_type_limited_reflection( + (*f_iter)->get_returntype(), "_return.methods.back().return_type"); + all_reflectable = all_reflectable && one_reflectable; + + t_struct* arglist = (*f_iter)->get_arglist(); + const vector & args = arglist->get_members(); + vector::const_iterator a_iter; + for (a_iter = args.begin(); a_iter != args.end(); ++a_iter) { + f_service_ << + indent() << "_return.methods.back().arguments.resize(" + "_return.methods.back().arguments.size() + 1);" << endl << + indent() << "_return.methods.back().arguments.back().name = \"" << + (*a_iter)->get_name() << "\";" << endl << + indent() << "_return.methods.back().arguments.back().key = " << + (*a_iter)->get_key() << ";" << endl; + one_reflectable = generate_type_limited_reflection( + (*a_iter)->get_type(), "_return.methods.back().arguments.back().type"); + all_reflectable = all_reflectable && one_reflectable; + } + } + + if (!all_reflectable) { + f_service_ << indent() << "_return.fully_reflected = false;" << endl; + } + + // Close function + scope_down(f_service_); + f_service_ << endl; +} + /** * Generates a skeleton file of a server * diff --git a/compiler/cpp/src/generate/t_cpp_generator.h b/compiler/cpp/src/generate/t_cpp_generator.h index acc75f6d..302f2706 100644 --- a/compiler/cpp/src/generate/t_cpp_generator.h +++ b/compiler/cpp/src/generate/t_cpp_generator.h @@ -70,10 +70,14 @@ class t_cpp_generator : public t_oop_generator { void generate_service_helpers (t_service* tservice); void generate_service_client (t_service* tservice); void generate_service_processor (t_service* tservice); - void generate_service_skeleton (t_service* tservice); + void generate_service_skeleton (t_service* tservice); void generate_process_function (t_service* tservice, t_function* tfunction); void generate_function_helpers (t_service* tservice, t_function* tfunction); + void generate_service_limited_reflector(t_service* tservice); + bool generate_type_limited_reflection(t_type* ttype, std::string target); + bool generate_simple_type_limited_reflection(std::ostream& out, t_type* ttype, std::string target); + /** * Serialization constructs */ diff --git a/if/reflection_limited.thrift b/if/reflection_limited.thrift new file mode 100644 index 00000000..77698174 --- /dev/null +++ b/if/reflection_limited.thrift @@ -0,0 +1,70 @@ +#!/usr/local/bin/thrift -php -java -cpp -py + +// NOTICE!!! +// DO NOT FORGET to run regen.sh if you change this file +// (or if you change the compiler). + +// This interface is deprecated. +// There is no replacement yet, but I hate it so much that +// I'm deprecating it before it's done. +// @author I'm too ashamed to say. + +// dreiss naively thinks he knows how to do this better, +// so talk to him if you are interested in taking it on, +// or if you just want someone to make it better for you. + +cpp_namespace facebook.thrift.reflection.limited +java_package com.facebook.thrift.reflection.limited + +enum TTypeTag { + T_VOID = 1, + T_BOOL = 2, + T_BYTE = 3, + T_I16 = 6, + T_I32 = 8, + T_I64 = 10, + T_DOUBLE = 4, + T_STRING = 11, + T_STRUCT = 12, + T_MAP = 13, + T_SET = 14, + T_LIST = 15, + // This doesn't exist in TBinaryProtocol, but it could be useful for reflection. + T_ENUM = 101, + T_NOT_REFLECTED = 102, +} + +struct SimpleType { + 1: TTypeTag ttype, + 2: string name, // For structs and emums. +} + +struct ContainerType { + 1: TTypeTag ttype, + 2: SimpleType subtype1, + 3: optional SimpleType subtype2, +} + +struct ThriftType { + 1: bool is_container, + 2: optional SimpleType simple_type, + 3: optional ContainerType container_type, +} + +struct Argument { + 1: i16 key, + 2: string name, + 3: ThriftType type, +} + +struct Method { + 1: string name, + 2: ThriftType return_type, + 3: list arguments, +} + +struct Service { + 1: string name, + 2: list methods, + 3: bool fully_reflected, +} diff --git a/if/regen.sh b/if/regen.sh new file mode 100755 index 00000000..03dad02a --- /dev/null +++ b/if/regen.sh @@ -0,0 +1,5 @@ +#!/bin/sh +cd "`dirname $0`" +../compiler/cpp/thrift -cpp reflection_limited.thrift +cp gen-cpp/reflection_limited_types.h ../lib/cpp/src/ +cp gen-cpp/reflection_limited_types.cpp ../lib/cpp/src/ diff --git a/lib/cpp/Makefile.am b/lib/cpp/Makefile.am index b8d3cea4..fa48e3ef 100644 --- a/lib/cpp/Makefile.am +++ b/lib/cpp/Makefile.am @@ -6,6 +6,7 @@ common_ldflags = -Wall $(BOOST_LDFLAGS) $(EVENT_LDFLAGS) # Define the source file for the module libthrift_sources = src/Thrift.cpp \ + src/reflection_limited_types.cpp \ src/concurrency/Mutex.cpp \ src/concurrency/Monitor.cpp \ src/concurrency/PosixThreadFactory.cpp \ @@ -40,6 +41,7 @@ include_thriftdir = $(includedir)/thrift include_thrift_HEADERS = \ config.h \ src/Thrift.h \ + src/reflection_limited_types.h \ src/TProcessor.h \ src/TLogging.h diff --git a/lib/cpp/src/TLogging.h b/lib/cpp/src/TLogging.h index 15c9c06b..4d3060d8 100644 --- a/lib/cpp/src/TLogging.h +++ b/lib/cpp/src/TLogging.h @@ -4,8 +4,8 @@ // See accompanying file LICENSE or visit the Thrift site at: // http://developers.facebook.com/thrift/ -#ifndef _THRIFT_LOGGING_H -#define _THRIFT_LOGGING_H 1 +#ifndef _THRIFT_TLOGGING_H_ +#define _THRIFT_TLOGGING_H_ 1 #ifdef HAVE_CONFIG_H #include "config.h" @@ -148,4 +148,4 @@ #define T_LOG_OPER(format_string,...) #endif -#endif // _THRIFT_LOGGING_H +#endif // #ifndef _THRIFT_TLOGGING_H_ diff --git a/lib/cpp/src/reflection_limited_types.cpp b/lib/cpp/src/reflection_limited_types.cpp new file mode 100644 index 00000000..d5c61530 --- /dev/null +++ b/lib/cpp/src/reflection_limited_types.cpp @@ -0,0 +1,489 @@ +/** + * Autogenerated by Thrift + * + * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING + */ +#include "reflection_limited_types.h" + +namespace facebook { namespace thrift { namespace reflection { namespace limited { + +uint32_t SimpleType::read(facebook::thrift::protocol::TProtocol* iprot) { + + uint32_t xfer = 0; + std::string fname; + facebook::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using facebook::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == facebook::thrift::protocol::T_STOP) { + break; + } + switch (fid) + { + case 1: + if (ftype == facebook::thrift::protocol::T_I32) { + int32_t ecast0; + xfer += iprot->readI32(ecast0); + this->ttype = (TTypeTag)ecast0; + this->__isset.ttype = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 2: + if (ftype == facebook::thrift::protocol::T_STRING) { + xfer += iprot->readString(this->name); + this->__isset.name = true; + } else { + xfer += iprot->skip(ftype); + } + break; + default: + xfer += iprot->skip(ftype); + break; + } + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t SimpleType::write(facebook::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + xfer += oprot->writeStructBegin("SimpleType"); + xfer += oprot->writeFieldBegin("ttype", facebook::thrift::protocol::T_I32, 1); + xfer += oprot->writeI32((int32_t)this->ttype); + xfer += oprot->writeFieldEnd(); + xfer += oprot->writeFieldBegin("name", facebook::thrift::protocol::T_STRING, 2); + xfer += oprot->writeString(this->name); + xfer += oprot->writeFieldEnd(); + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + +uint32_t ContainerType::read(facebook::thrift::protocol::TProtocol* iprot) { + + uint32_t xfer = 0; + std::string fname; + facebook::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using facebook::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == facebook::thrift::protocol::T_STOP) { + break; + } + switch (fid) + { + case 1: + if (ftype == facebook::thrift::protocol::T_I32) { + int32_t ecast1; + xfer += iprot->readI32(ecast1); + this->ttype = (TTypeTag)ecast1; + this->__isset.ttype = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 2: + if (ftype == facebook::thrift::protocol::T_STRUCT) { + xfer += this->subtype1.read(iprot); + this->__isset.subtype1 = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 3: + if (ftype == facebook::thrift::protocol::T_STRUCT) { + xfer += this->subtype2.read(iprot); + this->__isset.subtype2 = true; + } else { + xfer += iprot->skip(ftype); + } + break; + default: + xfer += iprot->skip(ftype); + break; + } + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t ContainerType::write(facebook::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + xfer += oprot->writeStructBegin("ContainerType"); + xfer += oprot->writeFieldBegin("ttype", facebook::thrift::protocol::T_I32, 1); + xfer += oprot->writeI32((int32_t)this->ttype); + xfer += oprot->writeFieldEnd(); + xfer += oprot->writeFieldBegin("subtype1", facebook::thrift::protocol::T_STRUCT, 2); + xfer += this->subtype1.write(oprot); + xfer += oprot->writeFieldEnd(); + if (this->__isset.subtype2) { + xfer += oprot->writeFieldBegin("subtype2", facebook::thrift::protocol::T_STRUCT, 3); + xfer += this->subtype2.write(oprot); + xfer += oprot->writeFieldEnd(); + } + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + +uint32_t ThriftType::read(facebook::thrift::protocol::TProtocol* iprot) { + + uint32_t xfer = 0; + std::string fname; + facebook::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using facebook::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == facebook::thrift::protocol::T_STOP) { + break; + } + switch (fid) + { + case 1: + if (ftype == facebook::thrift::protocol::T_BOOL) { + xfer += iprot->readBool(this->is_container); + this->__isset.is_container = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 2: + if (ftype == facebook::thrift::protocol::T_STRUCT) { + xfer += this->simple_type.read(iprot); + this->__isset.simple_type = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 3: + if (ftype == facebook::thrift::protocol::T_STRUCT) { + xfer += this->container_type.read(iprot); + this->__isset.container_type = true; + } else { + xfer += iprot->skip(ftype); + } + break; + default: + xfer += iprot->skip(ftype); + break; + } + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t ThriftType::write(facebook::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + xfer += oprot->writeStructBegin("ThriftType"); + xfer += oprot->writeFieldBegin("is_container", facebook::thrift::protocol::T_BOOL, 1); + xfer += oprot->writeBool(this->is_container); + xfer += oprot->writeFieldEnd(); + if (this->__isset.simple_type) { + xfer += oprot->writeFieldBegin("simple_type", facebook::thrift::protocol::T_STRUCT, 2); + xfer += this->simple_type.write(oprot); + xfer += oprot->writeFieldEnd(); + } + if (this->__isset.container_type) { + xfer += oprot->writeFieldBegin("container_type", facebook::thrift::protocol::T_STRUCT, 3); + xfer += this->container_type.write(oprot); + xfer += oprot->writeFieldEnd(); + } + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + +uint32_t Argument::read(facebook::thrift::protocol::TProtocol* iprot) { + + uint32_t xfer = 0; + std::string fname; + facebook::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using facebook::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == facebook::thrift::protocol::T_STOP) { + break; + } + switch (fid) + { + case 1: + if (ftype == facebook::thrift::protocol::T_I16) { + xfer += iprot->readI16(this->key); + this->__isset.key = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 2: + if (ftype == facebook::thrift::protocol::T_STRING) { + xfer += iprot->readString(this->name); + this->__isset.name = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 3: + if (ftype == facebook::thrift::protocol::T_STRUCT) { + xfer += this->type.read(iprot); + this->__isset.type = true; + } else { + xfer += iprot->skip(ftype); + } + break; + default: + xfer += iprot->skip(ftype); + break; + } + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t Argument::write(facebook::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + xfer += oprot->writeStructBegin("Argument"); + xfer += oprot->writeFieldBegin("key", facebook::thrift::protocol::T_I16, 1); + xfer += oprot->writeI16(this->key); + xfer += oprot->writeFieldEnd(); + xfer += oprot->writeFieldBegin("name", facebook::thrift::protocol::T_STRING, 2); + xfer += oprot->writeString(this->name); + xfer += oprot->writeFieldEnd(); + xfer += oprot->writeFieldBegin("type", facebook::thrift::protocol::T_STRUCT, 3); + xfer += this->type.write(oprot); + xfer += oprot->writeFieldEnd(); + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + +uint32_t Method::read(facebook::thrift::protocol::TProtocol* iprot) { + + uint32_t xfer = 0; + std::string fname; + facebook::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using facebook::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == facebook::thrift::protocol::T_STOP) { + break; + } + switch (fid) + { + case 1: + if (ftype == facebook::thrift::protocol::T_STRING) { + xfer += iprot->readString(this->name); + this->__isset.name = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 2: + if (ftype == facebook::thrift::protocol::T_STRUCT) { + xfer += this->return_type.read(iprot); + this->__isset.return_type = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 3: + if (ftype == facebook::thrift::protocol::T_LIST) { + { + this->arguments.clear(); + uint32_t _size2; + facebook::thrift::protocol::TType _etype5; + iprot->readListBegin(_etype5, _size2); + uint32_t _i6; + for (_i6 = 0; _i6 < _size2; ++_i6) + { + Argument _elem7; + xfer += _elem7.read(iprot); + this->arguments.push_back(_elem7); + } + iprot->readListEnd(); + } + this->__isset.arguments = true; + } else { + xfer += iprot->skip(ftype); + } + break; + default: + xfer += iprot->skip(ftype); + break; + } + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t Method::write(facebook::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + xfer += oprot->writeStructBegin("Method"); + xfer += oprot->writeFieldBegin("name", facebook::thrift::protocol::T_STRING, 1); + xfer += oprot->writeString(this->name); + xfer += oprot->writeFieldEnd(); + xfer += oprot->writeFieldBegin("return_type", facebook::thrift::protocol::T_STRUCT, 2); + xfer += this->return_type.write(oprot); + xfer += oprot->writeFieldEnd(); + xfer += oprot->writeFieldBegin("arguments", facebook::thrift::protocol::T_LIST, 3); + { + xfer += oprot->writeListBegin(facebook::thrift::protocol::T_STRUCT, this->arguments.size()); + std::vector ::const_iterator _iter8; + for (_iter8 = this->arguments.begin(); _iter8 != this->arguments.end(); ++_iter8) + { + xfer += (*_iter8).write(oprot); + } + xfer += oprot->writeListEnd(); + } + xfer += oprot->writeFieldEnd(); + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + +uint32_t Service::read(facebook::thrift::protocol::TProtocol* iprot) { + + uint32_t xfer = 0; + std::string fname; + facebook::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using facebook::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == facebook::thrift::protocol::T_STOP) { + break; + } + switch (fid) + { + case 1: + if (ftype == facebook::thrift::protocol::T_STRING) { + xfer += iprot->readString(this->name); + this->__isset.name = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 2: + if (ftype == facebook::thrift::protocol::T_LIST) { + { + this->methods.clear(); + uint32_t _size9; + facebook::thrift::protocol::TType _etype12; + iprot->readListBegin(_etype12, _size9); + uint32_t _i13; + for (_i13 = 0; _i13 < _size9; ++_i13) + { + Method _elem14; + xfer += _elem14.read(iprot); + this->methods.push_back(_elem14); + } + iprot->readListEnd(); + } + this->__isset.methods = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 3: + if (ftype == facebook::thrift::protocol::T_BOOL) { + xfer += iprot->readBool(this->fully_reflected); + this->__isset.fully_reflected = true; + } else { + xfer += iprot->skip(ftype); + } + break; + default: + xfer += iprot->skip(ftype); + break; + } + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t Service::write(facebook::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + xfer += oprot->writeStructBegin("Service"); + xfer += oprot->writeFieldBegin("name", facebook::thrift::protocol::T_STRING, 1); + xfer += oprot->writeString(this->name); + xfer += oprot->writeFieldEnd(); + xfer += oprot->writeFieldBegin("methods", facebook::thrift::protocol::T_LIST, 2); + { + xfer += oprot->writeListBegin(facebook::thrift::protocol::T_STRUCT, this->methods.size()); + std::vector ::const_iterator _iter15; + for (_iter15 = this->methods.begin(); _iter15 != this->methods.end(); ++_iter15) + { + xfer += (*_iter15).write(oprot); + } + xfer += oprot->writeListEnd(); + } + xfer += oprot->writeFieldEnd(); + xfer += oprot->writeFieldBegin("fully_reflected", facebook::thrift::protocol::T_BOOL, 3); + xfer += oprot->writeBool(this->fully_reflected); + xfer += oprot->writeFieldEnd(); + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + +}}}} // namespace diff --git a/lib/cpp/src/reflection_limited_types.h b/lib/cpp/src/reflection_limited_types.h new file mode 100644 index 00000000..843c6913 --- /dev/null +++ b/lib/cpp/src/reflection_limited_types.h @@ -0,0 +1,266 @@ +/** + * Autogenerated by Thrift + * + * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING + */ +#ifndef reflection_limited_TYPES_H +#define reflection_limited_TYPES_H + +#include +#include +#include + + + +namespace facebook { namespace thrift { namespace reflection { namespace limited { + +enum TTypeTag { + T_VOID = 1, + T_BOOL = 2, + T_BYTE = 3, + T_I16 = 6, + T_I32 = 8, + T_I64 = 10, + T_DOUBLE = 4, + T_STRING = 11, + T_STRUCT = 12, + T_MAP = 13, + T_SET = 14, + T_LIST = 15, + T_ENUM = 101, + T_NOT_REFLECTED = 102 +}; + +class SimpleType { + public: + + SimpleType() : name("") { + } + + virtual ~SimpleType() throw() {} + + TTypeTag ttype; + std::string name; + + struct __isset { + __isset() : ttype(false), name(false) {} + bool ttype; + bool name; + } __isset; + + bool operator == (const SimpleType & rhs) const + { + if (!(ttype == rhs.ttype)) + return false; + if (!(name == rhs.name)) + return false; + return true; + } + bool operator != (const SimpleType &rhs) const { + return !(*this == rhs); + } + + uint32_t read(facebook::thrift::protocol::TProtocol* iprot); + uint32_t write(facebook::thrift::protocol::TProtocol* oprot) const; + +}; + +class ContainerType { + public: + + ContainerType() { + } + + virtual ~ContainerType() throw() {} + + TTypeTag ttype; + SimpleType subtype1; + SimpleType subtype2; + + struct __isset { + __isset() : ttype(false), subtype1(false), subtype2(false) {} + bool ttype; + bool subtype1; + bool subtype2; + } __isset; + + bool operator == (const ContainerType & rhs) const + { + if (!(ttype == rhs.ttype)) + return false; + if (!(subtype1 == rhs.subtype1)) + return false; + if (__isset.subtype2 != rhs.__isset.subtype2) + return false; + else if (__isset.subtype2 && !(subtype2 == rhs.subtype2)) + return false; + return true; + } + bool operator != (const ContainerType &rhs) const { + return !(*this == rhs); + } + + uint32_t read(facebook::thrift::protocol::TProtocol* iprot); + uint32_t write(facebook::thrift::protocol::TProtocol* oprot) const; + +}; + +class ThriftType { + public: + + ThriftType() : is_container(0) { + } + + virtual ~ThriftType() throw() {} + + bool is_container; + SimpleType simple_type; + ContainerType container_type; + + struct __isset { + __isset() : is_container(false), simple_type(false), container_type(false) {} + bool is_container; + bool simple_type; + bool container_type; + } __isset; + + bool operator == (const ThriftType & rhs) const + { + if (!(is_container == rhs.is_container)) + return false; + if (__isset.simple_type != rhs.__isset.simple_type) + return false; + else if (__isset.simple_type && !(simple_type == rhs.simple_type)) + return false; + if (__isset.container_type != rhs.__isset.container_type) + return false; + else if (__isset.container_type && !(container_type == rhs.container_type)) + return false; + return true; + } + bool operator != (const ThriftType &rhs) const { + return !(*this == rhs); + } + + uint32_t read(facebook::thrift::protocol::TProtocol* iprot); + uint32_t write(facebook::thrift::protocol::TProtocol* oprot) const; + +}; + +class Argument { + public: + + Argument() : key(0), name("") { + } + + virtual ~Argument() throw() {} + + int16_t key; + std::string name; + ThriftType type; + + struct __isset { + __isset() : key(false), name(false), type(false) {} + bool key; + bool name; + bool type; + } __isset; + + bool operator == (const Argument & rhs) const + { + if (!(key == rhs.key)) + return false; + if (!(name == rhs.name)) + return false; + if (!(type == rhs.type)) + return false; + return true; + } + bool operator != (const Argument &rhs) const { + return !(*this == rhs); + } + + uint32_t read(facebook::thrift::protocol::TProtocol* iprot); + uint32_t write(facebook::thrift::protocol::TProtocol* oprot) const; + +}; + +class Method { + public: + + Method() : name("") { + } + + virtual ~Method() throw() {} + + std::string name; + ThriftType return_type; + std::vector arguments; + + struct __isset { + __isset() : name(false), return_type(false), arguments(false) {} + bool name; + bool return_type; + bool arguments; + } __isset; + + bool operator == (const Method & rhs) const + { + if (!(name == rhs.name)) + return false; + if (!(return_type == rhs.return_type)) + return false; + if (!(arguments == rhs.arguments)) + return false; + return true; + } + bool operator != (const Method &rhs) const { + return !(*this == rhs); + } + + uint32_t read(facebook::thrift::protocol::TProtocol* iprot); + uint32_t write(facebook::thrift::protocol::TProtocol* oprot) const; + +}; + +class Service { + public: + + Service() : name(""), fully_reflected(0) { + } + + virtual ~Service() throw() {} + + std::string name; + std::vector methods; + bool fully_reflected; + + struct __isset { + __isset() : name(false), methods(false), fully_reflected(false) {} + bool name; + bool methods; + bool fully_reflected; + } __isset; + + bool operator == (const Service & rhs) const + { + if (!(name == rhs.name)) + return false; + if (!(methods == rhs.methods)) + return false; + if (!(fully_reflected == rhs.fully_reflected)) + return false; + return true; + } + bool operator != (const Service &rhs) const { + return !(*this == rhs); + } + + uint32_t read(facebook::thrift::protocol::TProtocol* iprot); + uint32_t write(facebook::thrift::protocol::TProtocol* oprot) const; + +}; + +}}}} // namespace + +#endif diff --git a/test/DebugProtoTest.thrift b/test/DebugProtoTest.thrift index bbd86df0..090418c7 100644 --- a/test/DebugProtoTest.thrift +++ b/test/DebugProtoTest.thrift @@ -63,3 +63,13 @@ struct RandomStuff { service Srv { i32 Janky(i32 arg) } + +service PartiallyReflectable { + map> returnNotReflectable(1: i32 hello), + void argNotReflectable(1: list> arg), + void arg2NotReflectable(1: i32 arg1, 2: list> argNotReflectable), + void withMap(1: map amap), + + OneOfEach refl1(1: list arg1), + OneOfEach refl2(2: list arg1, 1: Bonk arg2); +} diff --git a/test/ReflectionTest.cpp b/test/ReflectionTest.cpp new file mode 100644 index 00000000..614c6138 --- /dev/null +++ b/test/ReflectionTest.cpp @@ -0,0 +1,30 @@ +/* +../compiler/cpp/thrift -cpp DebugProtoTest.thrift +../compiler/cpp/thrift -cpp StressTest.thrift +g++ -Wall -I../lib/cpp/src -I/usr/local/include/boost-1_33_1 \ + ReflectionTest.cpp \ + gen-cpp/StressTest_types.cpp gen-cpp/DebugProtoTest_types.cpp \ + gen-cpp/Service.cpp gen-cpp/PartiallyReflectable.cpp \ + ../lib/cpp/.libs/libthrift.a -o ReflectionTest +./ReflectionTest +*/ + +#include +#include "gen-cpp/PartiallyReflectable.h" +#include "gen-cpp/Service.h" +#include "../lib/cpp/src/protocol/TDebugProtocol.h" + +int main() { + using std::cout; + using std::endl; + + facebook::thrift::reflection::limited::Service srv1; + thrift::test::PartiallyReflectableIf::getStaticLimitedReflection(srv1); + cout << facebook::thrift::ThriftDebugString(srv1) << endl << endl; + + facebook::thrift::reflection::limited::Service srv2; + test::stress::ServiceIf::getStaticLimitedReflection(srv2); + cout << facebook::thrift::ThriftDebugString(srv2) << endl << endl; + + return 0; +} -- 2.17.1