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
diff --git a/cleanup.sh b/cleanup.sh
index c78c3fc..5c0046d 100755
--- a/cleanup.sh
+++ b/cleanup.sh
@@ -28,7 +28,8 @@
.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 796c9e0..8580e2a 100644
--- a/compiler/cpp/src/generate/t_cpp_generator.cc
+++ b/compiler/cpp/src/generate/t_cpp_generator.cc
@@ -7,6 +7,7 @@
#include <stdlib.h>
#include <sys/stat.h>
#include <sstream>
+#include <boost/lexical_cast.hpp>
#include "t_cpp_generator.h"
using namespace std;
@@ -42,6 +43,7 @@
// Include base types
f_types_ <<
"#include <Thrift.h>" << endl <<
+ "#include <reflection_limited_types.h>" << endl <<
"#include <protocol/TProtocol.h>" << endl <<
"#include <transport/TTransport.h>" << endl <<
endl;
@@ -891,6 +893,8 @@
generate_function_helpers(tservice, *f_iter);
}
+
+ generate_service_limited_reflector(tservice);
}
/**
@@ -909,6 +913,20 @@
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<t_function*> functions = tservice->get_functions();
vector<t_function*>::iterator f_iter;
for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
@@ -1671,6 +1689,166 @@
}
/**
+ * 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<t_function*> & funcs = tservice->get_functions();
+ vector<t_function*>::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<t_field*> & args = arglist->get_members();
+ vector<t_field*>::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
*
* @param tservice The service to generate a server for.
diff --git a/compiler/cpp/src/generate/t_cpp_generator.h b/compiler/cpp/src/generate/t_cpp_generator.h
index acc75f6..302f270 100644
--- a/compiler/cpp/src/generate/t_cpp_generator.h
+++ b/compiler/cpp/src/generate/t_cpp_generator.h
@@ -70,10 +70,14 @@
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 0000000..7769817
--- /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<Argument> arguments,
+}
+
+struct Service {
+ 1: string name,
+ 2: list<Method> methods,
+ 3: bool fully_reflected,
+}
diff --git a/if/regen.sh b/if/regen.sh
new file mode 100755
index 0000000..03dad02
--- /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 b8d3cea..fa48e3e 100644
--- a/lib/cpp/Makefile.am
+++ b/lib/cpp/Makefile.am
@@ -6,6 +6,7 @@
# 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_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 15c9c06..4d3060d 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 0000000..d5c6153
--- /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<Argument> ::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<Method> ::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 0000000..843c691
--- /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 <Thrift.h>
+#include <protocol/TProtocol.h>
+#include <transport/TTransport.h>
+
+
+
+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<Argument> 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<Method> 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 bbd86df..090418c 100644
--- a/test/DebugProtoTest.thrift
+++ b/test/DebugProtoTest.thrift
@@ -63,3 +63,13 @@
service Srv {
i32 Janky(i32 arg)
}
+
+service PartiallyReflectable {
+ map<i32,map<i32,i32>> returnNotReflectable(1: i32 hello),
+ void argNotReflectable(1: list<set<i32>> arg),
+ void arg2NotReflectable(1: i32 arg1, 2: list<set<i32>> argNotReflectable),
+ void withMap(1: map<i32, string> amap),
+
+ OneOfEach refl1(1: list<Bonk> arg1),
+ OneOfEach refl2(2: list<string> arg1, 1: Bonk arg2);
+}
diff --git a/test/ReflectionTest.cpp b/test/ReflectionTest.cpp
new file mode 100644
index 0000000..614c613
--- /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 <iostream>
+#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;
+}