thrift/lib/cpp/Thrift.h (162 lines of code) (raw):
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* Licensed 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.
*/
#ifndef THRIFT_THRIFT_H_
#define THRIFT_THRIFT_H_
#include <folly/Range.h>
#include <folly/Traits.h>
#include <folly/lang/Bits.h>
#include <folly/portability/Time.h>
#include <thrift/lib/cpp/thrift_config.h>
#ifdef THRIFT_PLATFORM_CONFIG
#include THRIFT_PLATFORM_CONFIG
#endif
#include <assert.h>
#include <sys/types.h>
#if __has_include(<inttypes.h>)
#include <inttypes.h>
#endif
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <exception>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <typeinfo>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <thrift/lib/cpp/TLogging.h>
namespace apache {
namespace thrift {
struct ltstr {
bool operator()(const char* s1, const char* s2) const {
return strcmp(s1, s2) < 0;
}
};
/**
* Specialization fwd-decl in _types.h.
* Specialization defn in _data.h.
*/
template <typename T>
struct TEnumDataStorage {
static_assert(sizeof(T) == ~0ull, "invalid use of base template");
};
template <typename T>
struct TStructDataStorage {
static_assert(sizeof(T) == ~0ull, "invalid use of base template");
};
/**
* Specialization defn in _types.h.
* Specialization member defns in _types.cpp.
*/
template <typename T>
struct TEnumTraits {
// When instantiated with an enum type T, includes:
//
// using type = T;
//
// static constexpr std::size_t const size = /*...*/;
// static folly::Range<type const*> const values;
// static folly::Range<folly::StringPiece const*> const names;
//
// static char const* findName(type value);
// static bool findValue(char const* name, type* out);
//
// When instantiated with an enum type T which is not empty, includes:
//
// static constexpr type min() { /*...*/ }
// static constexpr type max() { /*...*/ }
//
// To test at compile time whether a given enum T is generated by thrift, the
// presence of TEnumTraits<T>::type may be tested. If it is present, then T
// is generated by thrift; if absent, then T is not generated by thrift.
static char const* findName(T) {
static_assert(sizeof(T) == ~0ull, "invalid use of base template");
return nullptr;
}
static bool findValue(char const*, T*) {
static_assert(sizeof(T) == ~0ull, "invalid use of base template");
return false;
}
};
namespace detail {
template <typename EnumTypeT>
struct TEnumMapFactory {
using EnumType = EnumTypeT;
using ValuesToNamesMapType = std::map<EnumType, const char*>;
using NamesToValuesMapType = std::map<const char*, EnumType, ltstr>;
using Traits = TEnumTraits<EnumType>;
static ValuesToNamesMapType makeValuesToNamesMap() {
ValuesToNamesMapType _return;
for (size_t i = 0; i < Traits::size; ++i) {
_return.emplace(EnumType(Traits::values[i]), Traits::names[i].data());
}
return _return;
}
static NamesToValuesMapType makeNamesToValuesMap() {
NamesToValuesMapType _return;
for (size_t i = 0; i < Traits::size; ++i) {
_return.emplace(Traits::names[i].data(), EnumType(Traits::values[i]));
}
return _return;
}
};
} // namespace detail
class TOutput {
public:
TOutput() : f_(&errorTimeWrapper) {}
inline void setOutputFunction(void (*function)(const char*)) {
f_ = function;
}
inline void operator()(const char* message) { f_(message); }
// It is important to have a const char* overload here instead of
// just the string version, otherwise errno could be corrupted
// if there is some problem allocating memory when constructing
// the string.
void perror(const char* message, int errno_copy);
inline void perror(const std::string& message, int errno_copy) {
perror(message.c_str(), errno_copy);
}
void printf(const char* message, ...);
inline static void errorTimeWrapper(const char* msg) {
time_t now;
char dbgtime[26];
time(&now);
ctime_r(&now, dbgtime);
dbgtime[24] = 0;
fprintf(stderr, "Thrift: %s %s\n", dbgtime, msg);
}
/** Just like strerror_r but returns a C++ string object. */
static std::string strerror_s(int errno_copy);
private:
void (*f_)(const char*);
};
extern TOutput GlobalOutput;
/**
* Base class for all Thrift exceptions.
* Should never be instantiated, only caught.
*/
class FOLLY_EXPORT TException : public std::exception {
public:
TException() {}
TException(TException&&) noexcept {}
TException(const TException&) {}
TException& operator=(const TException&) { return *this; }
TException& operator=(TException&&) { return *this; }
};
/**
* Base class for exceptions from the Thrift library, and occasionally
* from the generated code. This class should not be thrown by user code.
* Instances of this class are not meant to be serialized.
*/
class FOLLY_EXPORT TLibraryException : public TException {
public:
TLibraryException() {}
explicit TLibraryException(const std::string& message) : message_(message) {}
TLibraryException(const char* message, int errnoValue);
~TLibraryException() throw() override {}
const char* what() const throw() override {
if (message_.empty()) {
return "Default TLibraryException.";
} else {
return message_.c_str();
}
}
protected:
std::string message_;
};
class FOLLY_EXPORT AppBaseError : public std::runtime_error {
public:
AppBaseError(const std::string& name, const std::string& what)
: std::runtime_error(what), name_(name) {}
AppBaseError(std::string&& name, std::string&& what)
: std::runtime_error(what), name_(std::move(name)) {}
virtual const char* name() const noexcept { return name_.c_str(); }
virtual bool isClientError() const noexcept = 0;
private:
std::string name_;
};
class FOLLY_EXPORT AppServerError : public AppBaseError {
public:
using AppBaseError::AppBaseError;
bool isClientError() const noexcept override { return false; }
};
class FOLLY_EXPORT AppClientError : public AppBaseError {
public:
using AppBaseError::AppBaseError;
bool isClientError() const noexcept override { return true; }
};
/**
* Below are class templates that allows the Thrift compiler to
* generate code for C++ types without polluting the user namespace.
*
* Given the following IDL:
* namespace cpp2 foo
* service Bar {}
* The Thrift compiler only requires an incomplete type to be declared in the
* user namespace.
* namespace foo {
* class Bar;
* }
* To implement server and client stubs for this service, the compiler can
* provide template specializations for apache::thrift::ServiceHandler<foo::Bar>
* and apache::thrift::Client<foo::Bar> respectively.
*
* This mechanism provides a framework to implement arbitrary "traits" on
* services with the guarantee that adding new types will not collide with
* user-defined types in their own namespaces.
*/
template <class ServiceTag>
class ServiceHandler {
static_assert(
folly::always_false<ServiceTag>,
"Invalid instantiation of base template. Is ServiceTag valid?");
};
template <class ServiceTag>
class Client {
static_assert(
folly::always_false<ServiceTag>,
"Invalid instantiation of base template. Is ServiceTag valid?");
};
} // namespace thrift
} // namespace apache
#endif // #ifndef THRIFT_THRIFT_H_