THRIFT-5772: UUID support for c++ #2952
Client: cpp
Patch: CJCombrink
This closes #2952
diff --git a/compiler/cpp/src/thrift/generate/t_cpp_generator.cc b/compiler/cpp/src/thrift/generate/t_cpp_generator.cc
index a085ada..e21252e 100644
--- a/compiler/cpp/src/thrift/generate/t_cpp_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_cpp_generator.cc
@@ -296,7 +296,7 @@
(ttype->annotations_.find("cpp.customostream") != ttype->annotations_.end());
}
- /**
+ /**
* Determine if all fields of t_struct's storage do not throw
* Move/Copy Constructors and Assignments applicable for 'noexcept'
* Move defaults to 'noexcept'
@@ -318,7 +318,7 @@
/**
* Returns the legal program name to use for a file generated by program, if the
- * program name contains dots then replace it with underscores, otherwise return the
+ * program name contains dots then replace it with underscores, otherwise return the
* original program name.
*/
std::string get_legal_program_name(std::string program_name);
@@ -981,7 +981,7 @@
for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
t_type* t = get_true_type((*m_iter)->get_type());
- if (is_reference(*m_iter) || t->is_string()) {
+ if (is_reference(*m_iter) || t->is_string() || t->is_uuid()) {
t_const_value* cv = (*m_iter)->get_value();
if (cv != nullptr) {
return true;
@@ -1032,7 +1032,7 @@
} else if (t->is_enum()) {
dval += "static_cast<" + type_name(t) + ">(0)";
} else {
- dval += (t->is_string() || is_reference(*m_iter)) ? "" : "0";
+ dval += (t->is_string() || is_reference(*m_iter) || t->is_uuid()) ? "" : "0";
}
if (!init_ctor) {
init_ctor = true;
@@ -1127,7 +1127,7 @@
has_nonrequired_fields = true;
indent(out) << (*f_iter)->get_name() << " = "
<< maybeMove(
- tmp_name + "." + (*f_iter)->get_name(),
+ tmp_name + "." + (*f_iter)->get_name(),
is_move && is_complex_type((*f_iter)->get_type()))
<< ";" << endl;
}
@@ -1177,7 +1177,7 @@
has_nonrequired_fields = true;
indent(out) << (*f_iter)->get_name() << " = "
<< maybeMove(
- tmp_name + "." + (*f_iter)->get_name(),
+ tmp_name + "." + (*f_iter)->get_name(),
is_move && is_complex_type((*f_iter)->get_type()))
<< ";" << endl;
}
@@ -1276,7 +1276,7 @@
// Move constructor
if (gen_moveable_) {
- indent(out) << tstruct->get_name() << "(" << tstruct->get_name() << "&&) noexcept;"
+ indent(out) << tstruct->get_name() << "(" << tstruct->get_name() << "&&) noexcept;"
<< endl;
}
@@ -1286,12 +1286,12 @@
// Move assignment operator
if (gen_moveable_) {
- indent(out) << tstruct->get_name() << "& operator=(" << tstruct->get_name() << "&&) noexcept;"
+ indent(out) << tstruct->get_name() << "& operator=(" << tstruct->get_name() << "&&) noexcept;"
<< endl;
}
bool has_default_value = has_field_with_default_value(tstruct);
-
+
// Default constructor
std::string clsname_ctor = tstruct->get_name() + "()";
indent(out) << clsname_ctor << (has_default_value ? "" : " noexcept") << ";" << endl;
@@ -1732,7 +1732,7 @@
void t_cpp_generator::generate_struct_swap(ostream& out, t_struct* tstruct) {
if (tstruct->get_name() == "a" || tstruct->get_name() == "b") {
out << indent() << "void swap(" << tstruct->get_name() << " &a1, " << tstruct->get_name()
- << " &a2) {" << endl;
+ << " &a2) {" << endl;
} else {
out << indent() << "void swap(" << tstruct->get_name() << " &a, " << tstruct->get_name()
<< " &b) {" << endl;
@@ -1763,7 +1763,7 @@
if (has_nonrequired_fields) {
if (tstruct->get_name() == "a" || tstruct->get_name() == "b") {
- out << indent() << "swap(a1.__isset, a2.__isset);" << endl;
+ out << indent() << "swap(a1.__isset, a2.__isset);" << endl;
} else {
out << indent() << "swap(a.__isset, b.__isset);" << endl;
}
@@ -1942,7 +1942,7 @@
<< endl;
if (gen_cob_style_) {
f_header_ << "#include <thrift/transport/TBufferTransports.h>" << endl // TMemoryBuffer
- << "#include <functional>" << endl
+ << "#include <functional>" << endl
<< "namespace apache { namespace thrift { namespace async {" << endl
<< "class TAsyncChannel;" << endl << "}}}" << endl;
}
@@ -2578,7 +2578,7 @@
f_header_ << ", std::shared_ptr< ::apache::thrift::async::TConcurrentClientSyncInfo> sync";
}
f_header_ << ") ";
-
+
if (extends.empty()) {
if (style == "Concurrent") {
f_header_ << ": sync_(sync)" << endl;
@@ -2677,7 +2677,7 @@
vector<t_function*>::const_iterator f_iter;
for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
generate_java_doc(f_header_, *f_iter);
- indent(f_header_) << function_signature(*f_iter, ifstyle)
+ indent(f_header_) << function_signature(*f_iter, ifstyle)
<< " override;" << endl;
// TODO(dreiss): Use private inheritance to avoid generating thise in cob-style.
if (style == "Concurrent" && !(*f_iter)->is_oneway()) {
@@ -3227,7 +3227,7 @@
f_header_ << indent() << "virtual " << ret_type_ << "dispatchCall(" << finish_cob_
<< "::apache::thrift::protocol::TProtocol* iprot, "
<< "::apache::thrift::protocol::TProtocol* oprot, "
- << "const std::string& fname, int32_t seqid" << call_context_
+ << "const std::string& fname, int32_t seqid" << call_context_
<< ") override;" << endl;
if (generator_->gen_templates_) {
f_header_ << indent() << "virtual " << ret_type_ << "dispatchCallTemplated(" << finish_cob_
@@ -4046,6 +4046,9 @@
case t_base_type::TYPE_VOID:
throw "compiler error: cannot serialize void field in a struct: " + name;
break;
+ case t_base_type::TYPE_UUID:
+ out << "readUUID(" << name << ");";
+ break;
case t_base_type::TYPE_STRING:
if (type->is_binary()) {
out << "readBinary(" << name << ");";
@@ -4072,13 +4075,13 @@
out << "readDouble(" << name << ");";
break;
default:
- throw "compiler error: no C++ reader for base type " + t_base_type::t_base_name(tbase) + name;
+ throw "compiler error: no C++ reader for base type " + t_base_type::t_base_name(tbase) + " " + name;
}
out << endl;
} else if (type->is_enum()) {
string t = tmp("ecast");
out << indent() << "int32_t " << t << ";" << endl << indent() << "xfer += iprot->readI32(" << t
- << ");" << endl << indent() << name << " = static_cast<"
+ << ");" << endl << indent() << name << " = static_cast<"
<< type_name(type) << ">(" << t << ");" << endl;
} else {
printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
@@ -4254,6 +4257,9 @@
case t_base_type::TYPE_VOID:
throw "compiler error: cannot serialize void field in a struct: " + name;
break;
+ case t_base_type::TYPE_UUID:
+ out << "writeUUID(" << name << ");";
+ break;
case t_base_type::TYPE_STRING:
if (type->is_binary()) {
out << "writeBinary(" << name << ");";
@@ -4281,7 +4287,7 @@
break;
default:
throw "compiler error: no C++ writer for base type " + t_base_type::t_base_name(tbase)
- + name;
+ + " " + name;
}
} else if (type->is_enum()) {
out << "writeI32(static_cast<int32_t>(" << name << "));";
@@ -4568,6 +4574,9 @@
return "int64_t";
case t_base_type::TYPE_DOUBLE:
return "double";
+ case t_base_type::TYPE_UUID:
+ // TODO: discuss possibility of a class TUuid;
+ return "std::string";
default:
throw "compiler error: no C++ base type name for base type " + t_base_type::t_base_name(tbase);
}
@@ -4609,6 +4618,9 @@
case t_base_type::TYPE_VOID:
case t_base_type::TYPE_STRING:
break;
+ case t_base_type::TYPE_UUID:
+ result += " = std::string(\"00000000-0000-0000-0000-000000000000\")";
+ break;
case t_base_type::TYPE_BOOL:
result += " = false";
break;
@@ -4735,6 +4747,8 @@
return "::apache::thrift::protocol::T_I64";
case t_base_type::TYPE_DOUBLE:
return "::apache::thrift::protocol::T_DOUBLE";
+ case t_base_type::TYPE_UUID:
+ return "::apache::thrift::protocol::T_UUID";
default:
break;
}
@@ -4776,6 +4790,7 @@
continue;
case t_base_type::TYPE_VOID:
case t_base_type::TYPE_STRING:
+ case t_base_type::TYPE_UUID:
default:
return false;
}
diff --git a/lib/cpp/CMakeLists.txt b/lib/cpp/CMakeLists.txt
index 6a66e5a..c2f15dd 100644
--- a/lib/cpp/CMakeLists.txt
+++ b/lib/cpp/CMakeLists.txt
@@ -43,6 +43,7 @@
src/thrift/protocol/TJSONProtocol.cpp
src/thrift/protocol/TMultiplexedProtocol.cpp
src/thrift/protocol/TProtocol.cpp
+ src/thrift/protocol/TUuidUtils.cpp
src/thrift/transport/TTransportException.cpp
src/thrift/transport/TFDTransport.cpp
src/thrift/transport/TSimpleFileTransport.cpp
diff --git a/lib/cpp/Makefile.am b/lib/cpp/Makefile.am
index 2499fdb..12b8d82 100644
--- a/lib/cpp/Makefile.am
+++ b/lib/cpp/Makefile.am
@@ -69,6 +69,7 @@
src/thrift/protocol/TBase64Utils.cpp \
src/thrift/protocol/TMultiplexedProtocol.cpp \
src/thrift/protocol/TProtocol.cpp \
+ src/thrift/protocol/TUuidUtils.cpp \
src/thrift/transport/TTransportException.cpp \
src/thrift/transport/TFDTransport.cpp \
src/thrift/transport/TFileTransport.cpp \
diff --git a/lib/cpp/libthrift.vcxproj b/lib/cpp/libthrift.vcxproj
index 0b5e16d..1b413f8 100644
--- a/lib/cpp/libthrift.vcxproj
+++ b/lib/cpp/libthrift.vcxproj
@@ -49,6 +49,7 @@
<ClCompile Include="src\thrift\protocol\TJSONProtocol.cpp" />
<ClCompile Include="src\thrift\protocol\TMultiplexedProtocol.cpp" />
<ClCompile Include="src\thrift\protocol\TProtocol.cpp" />
+ <ClCompile Include="src\thrift\protocol\TUuidUtils.cpp" />
<ClCompile Include="src\thrift\server\TConnectedClient.cpp" />
<ClCompile Include="src\thrift\server\TServer.cpp" />
<ClCompile Include="src\thrift\server\TServerFramework.cpp" />
diff --git a/lib/cpp/libthrift.vcxproj.filters b/lib/cpp/libthrift.vcxproj.filters
index 98426fa..fb94f60 100644
--- a/lib/cpp/libthrift.vcxproj.filters
+++ b/lib/cpp/libthrift.vcxproj.filters
@@ -30,6 +30,9 @@
<ClCompile Include="src\thrift\protocol\TMultiplexedProtocol.cpp">
<Filter>protocol</Filter>
</ClCompile>
+ <ClCompile Include="src\thrift\protocol\TUuidUtils.cpp">
+ <Filter>protocol</Filter>
+ </ClCompile>
<ClCompile Include="src\thrift\transport\TFDTransport.cpp">
<Filter>transport</Filter>
</ClCompile>
diff --git a/lib/cpp/src/thrift/protocol/TBinaryProtocol.h b/lib/cpp/src/thrift/protocol/TBinaryProtocol.h
index 7b829c7..24e51f7 100644
--- a/lib/cpp/src/thrift/protocol/TBinaryProtocol.h
+++ b/lib/cpp/src/thrift/protocol/TBinaryProtocol.h
@@ -119,6 +119,8 @@
inline uint32_t writeBinary(const std::string& str);
+ inline uint32_t writeUUID(const std::string& str);
+
/**
* Reading functions
*/
@@ -166,6 +168,8 @@
inline uint32_t readBinary(std::string& str);
+ inline uint32_t readUUID(std::string& str);
+
int getMinSerializedSize(TType type) override;
void checkReadBytesAvailable(TSet& set) override
diff --git a/lib/cpp/src/thrift/protocol/TBinaryProtocol.tcc b/lib/cpp/src/thrift/protocol/TBinaryProtocol.tcc
index c448e77..6a54ece 100644
--- a/lib/cpp/src/thrift/protocol/TBinaryProtocol.tcc
+++ b/lib/cpp/src/thrift/protocol/TBinaryProtocol.tcc
@@ -21,6 +21,7 @@
#define _THRIFT_PROTOCOL_TBINARYPROTOCOL_TCC_ 1
#include <thrift/protocol/TBinaryProtocol.h>
+#include <thrift/protocol/TUuidUtils.hpp>
#include <thrift/transport/TTransportException.h>
#include <limits>
@@ -193,6 +194,20 @@
return TBinaryProtocolT<Transport_, ByteOrder_>::writeString(str);
}
+template <class Transport_, class ByteOrder_>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeUUID(const std::string& str) {
+ std::string out;
+ const bool encoded = uuid_encode(str, out);
+ if(!encoded)
+ throw TProtocolException(TProtocolException::INVALID_DATA);
+ // This should not happen, but check for now
+ if(out.size() != 16)
+ throw TProtocolException(TProtocolException::UNKNOWN);
+ // TODO: Consider endian swapping, see lib/delphi/src/Thrift.Utils.pas:377
+ this->trans_->write((uint8_t*)out.data(), 16);
+ return 16;
+}
+
/**
* Reading functions
*/
@@ -286,7 +301,7 @@
throw TProtocolException(TProtocolException::SIZE_LIMIT);
}
size = (uint32_t)sizei;
-
+
TMap map(keyType, valType, size);
checkReadBytesAvailable(map);
@@ -429,6 +444,14 @@
}
template <class Transport_, class ByteOrder_>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readUUID(std::string& str) {
+ std::string in;
+ readStringBody(in, 16);
+ uuid_decode(in, str);
+ return 16;
+}
+
+template <class Transport_, class ByteOrder_>
template <typename StrType>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readStringBody(StrType& str, int32_t size) {
uint32_t result = 0;
diff --git a/lib/cpp/src/thrift/protocol/TDebugProtocol.cpp b/lib/cpp/src/thrift/protocol/TDebugProtocol.cpp
index 0e6d4a2..0a2eaed 100644
--- a/lib/cpp/src/thrift/protocol/TDebugProtocol.cpp
+++ b/lib/cpp/src/thrift/protocol/TDebugProtocol.cpp
@@ -18,6 +18,7 @@
*/
#include <thrift/protocol/TDebugProtocol.h>
+#include <thrift/protocol/TUuidUtils.hpp>
#include <thrift/TToString.h>
#include <cassert>
@@ -70,10 +71,8 @@
return "set";
case T_LIST:
return "list";
- case T_UTF8:
- return "utf8";
- case T_UTF16:
- return "utf16";
+ case T_UUID:
+ return "uuid";
default:
return "unknown";
}
@@ -388,6 +387,24 @@
// XXX Hex?
return TDebugProtocol::writeString(str);
}
+
+uint32_t TDebugProtocol::writeUUID(const string& str) {
+ std::string out_raw;
+ uuid_encode(str, out_raw);
+
+ std::string out_encoded;
+ uuid_decode(out_raw, out_encoded);
+
+ size_t size = writePlain("{\n");
+ indentUp();
+ size += writeIndented("[in ] = \"" + str + "\",\n");
+ size += writeIndented("[raw] = ");
+ size += writeString(out_raw);
+ size += writeIndented("[enc] = \"" + out_encoded + "\"\n");
+ indentDown();
+ size += writeIndented("}\n");
+ return size;
+}
}
}
} // apache::thrift::protocol
diff --git a/lib/cpp/src/thrift/protocol/TDebugProtocol.h b/lib/cpp/src/thrift/protocol/TDebugProtocol.h
index 41bb0d4..af89cc5 100644
--- a/lib/cpp/src/thrift/protocol/TDebugProtocol.h
+++ b/lib/cpp/src/thrift/protocol/TDebugProtocol.h
@@ -110,6 +110,8 @@
uint32_t writeBinary(const std::string& str);
+ uint32_t writeUUID(const std::string& str);
+
private:
void indentUp();
void indentDown();
diff --git a/lib/cpp/src/thrift/protocol/TEnum.h b/lib/cpp/src/thrift/protocol/TEnum.h
index 9636785..bbd1247 100644
--- a/lib/cpp/src/thrift/protocol/TEnum.h
+++ b/lib/cpp/src/thrift/protocol/TEnum.h
@@ -18,7 +18,7 @@
*/
#ifndef _THRIFT_ENUM_H_
-#define _THRIFT_ENUM_H_
+#define _THRIFT_ENUM_H_
namespace apache {
namespace thrift {
@@ -46,8 +46,7 @@
T_MAP = 13,
T_SET = 14,
T_LIST = 15,
- T_UTF8 = 16,
- T_UTF16 = 17
+ T_UUID = 16,
};
/**
@@ -63,4 +62,4 @@
}}} // apache::thrift::protocol
-#endif // #define _THRIFT_ENUM_H_
+#endif // #define _THRIFT_ENUM_H_
diff --git a/lib/cpp/src/thrift/protocol/TJSONProtocol.cpp b/lib/cpp/src/thrift/protocol/TJSONProtocol.cpp
index 6e4e8ef..0899f00 100644
--- a/lib/cpp/src/thrift/protocol/TJSONProtocol.cpp
+++ b/lib/cpp/src/thrift/protocol/TJSONProtocol.cpp
@@ -18,6 +18,7 @@
*/
#include <thrift/protocol/TJSONProtocol.h>
+#include <thrift/protocol/TUuidUtils.hpp>
#include <boost/locale.hpp>
@@ -68,6 +69,7 @@
static const std::string kTypeNameMap("map");
static const std::string kTypeNameList("lst");
static const std::string kTypeNameSet("set");
+static const std::string kTypeNameUuid("uid");
static const std::string& getTypeNameForTypeID(TType typeID) {
switch (typeID) {
@@ -93,6 +95,8 @@
return kTypeNameSet;
case T_LIST:
return kTypeNameList;
+ case T_UUID:
+ return kTypeNameUuid;
default:
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, "Unrecognized type");
}
@@ -140,6 +144,9 @@
case 't':
result = T_BOOL;
break;
+ case 'u':
+ result = T_UUID;
+ break;
}
}
if (result == T_STOP) {
@@ -710,6 +717,16 @@
return writeJSONBase64(str);
}
+uint32_t TJSONProtocol::writeUUID(const std::string& str) {
+ std::string out_raw;
+ uuid_encode(str, out_raw);
+
+ std::string out_encoded;
+ uuid_decode(out_raw, out_encoded);
+
+ return writeJSONString(out_encoded);
+}
+
/**
* Reading functions
*/
@@ -1106,6 +1123,10 @@
return readJSONBase64(str);
}
+uint32_t TJSONProtocol::readUUID(std::string& str) {
+ return readJSONString(str);
+}
+
// Return the minimum number of bytes a type will consume on the wire
int TJSONProtocol::getMinSerializedSize(TType type)
{
@@ -1113,7 +1134,7 @@
{
case T_STOP: return 0;
case T_VOID: return 0;
- case T_BOOL: return 1; // written as int
+ case T_BOOL: return 1; // written as int
case T_BYTE: return 1;
case T_DOUBLE: return 1;
case T_I16: return 1;
@@ -1124,6 +1145,7 @@
case T_MAP: return 2; // empty map
case T_SET: return 2; // empty set
case T_LIST: return 2; // empty list
+ case T_UUID: return 16; // empty UUID
default: throw TProtocolException(TProtocolException::UNKNOWN, "unrecognized type code");
}
}
diff --git a/lib/cpp/src/thrift/protocol/TJSONProtocol.h b/lib/cpp/src/thrift/protocol/TJSONProtocol.h
index d01bdf8..069a990 100644
--- a/lib/cpp/src/thrift/protocol/TJSONProtocol.h
+++ b/lib/cpp/src/thrift/protocol/TJSONProtocol.h
@@ -198,6 +198,8 @@
uint32_t writeBinary(const std::string& str);
+ uint32_t writeUUID(const std::string& str);
+
/**
* Reading functions
*/
@@ -245,6 +247,8 @@
uint32_t readBinary(std::string& str);
+ uint32_t readUUID(std::string& str);
+
int getMinSerializedSize(TType type) override;
void checkReadBytesAvailable(TSet& set) override
diff --git a/lib/cpp/src/thrift/protocol/TProtocol.h b/lib/cpp/src/thrift/protocol/TProtocol.h
index 237c1e5..d29df1c 100644
--- a/lib/cpp/src/thrift/protocol/TProtocol.h
+++ b/lib/cpp/src/thrift/protocol/TProtocol.h
@@ -275,6 +275,8 @@
virtual uint32_t writeBinary_virt(const std::string& str) = 0;
+ virtual uint32_t writeUUID_virt(const std::string& str) = 0;
+
uint32_t writeMessageBegin(const std::string& name,
const TMessageType messageType,
const int32_t seqid) {
@@ -382,6 +384,11 @@
return writeBinary_virt(str);
}
+ uint32_t writeUUID(const std::string& str) {
+ T_VIRTUAL_CALL();
+ return writeUUID_virt(str);
+ }
+
/**
* Reading functions
*/
@@ -430,6 +437,8 @@
virtual uint32_t readBinary_virt(std::string& str) = 0;
+ virtual uint32_t readUUID_virt(std::string& str) = 0;
+
uint32_t readMessageBegin(std::string& name, TMessageType& messageType, int32_t& seqid) {
T_VIRTUAL_CALL();
return readMessageBegin_virt(name, messageType, seqid);
@@ -530,6 +539,11 @@
return readBinary_virt(str);
}
+ uint32_t readUUID(std::string& str) {
+ T_VIRTUAL_CALL();
+ return readUUID_virt(str);
+ }
+
/*
* std::vector is specialized for bool, and its elements are individual bits
* rather than bools. We need to define a different version of readBool()
diff --git a/lib/cpp/src/thrift/protocol/TProtocolDecorator.h b/lib/cpp/src/thrift/protocol/TProtocolDecorator.h
index 5258159..9eb1566 100644
--- a/lib/cpp/src/thrift/protocol/TProtocolDecorator.h
+++ b/lib/cpp/src/thrift/protocol/TProtocolDecorator.h
@@ -92,6 +92,7 @@
uint32_t writeDouble_virt(const double dub) override { return protocol->writeDouble(dub); }
uint32_t writeString_virt(const std::string& str) override { return protocol->writeString(str); }
uint32_t writeBinary_virt(const std::string& str) override { return protocol->writeBinary(str); }
+ uint32_t writeUUID_virt(const std::string& str) override { return protocol->writeUUID(str); }
uint32_t readMessageBegin_virt(std::string& name,
TMessageType& messageType,
@@ -140,6 +141,7 @@
uint32_t readString_virt(std::string& str) override { return protocol->readString(str); }
uint32_t readBinary_virt(std::string& str) override { return protocol->readBinary(str); }
+ uint32_t readUUID_virt(std::string& str) override { return protocol->readUUID(str); }
private:
shared_ptr<TProtocol> protocol;
diff --git a/lib/cpp/src/thrift/protocol/TUuidUtils.cpp b/lib/cpp/src/thrift/protocol/TUuidUtils.cpp
new file mode 100644
index 0000000..e1eab22
--- /dev/null
+++ b/lib/cpp/src/thrift/protocol/TUuidUtils.cpp
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+#include <thrift/protocol/TUuidUtils.hpp>
+
+#include <boost/uuid/string_generator.hpp>
+#include <boost/uuid/uuid.hpp>
+#include <boost/uuid/uuid_io.hpp>
+
+namespace apache {
+namespace thrift {
+namespace protocol {
+
+bool uuid_encode(const std::string& in, std::string& out) {
+ static const boost::uuids::string_generator gen;
+ static const std::string empty_uuid(boost::uuids::uuid::static_size(), '\0');
+ out = empty_uuid;
+ if (in.empty()) {
+ return true;
+ }
+ try {
+ const boost::uuids::uuid uuid{gen(in)};
+ std::copy(uuid.begin(), uuid.end(), out.begin());
+ return true;
+ } catch (const std::runtime_error&) {
+ // Invalid string most probably
+ return false;
+ }
+}
+
+void uuid_decode(const std::string& in, std::string& out) {
+ boost::uuids::uuid uuid{};
+ const size_t to_copy = std::min(in.size(), uuid.size());
+ std::copy(in.begin(), in.begin() + to_copy, uuid.begin());
+ out = boost::uuids::to_string(uuid);
+}
+
+}
+}
+} // apache::thrift::protocol
diff --git a/lib/cpp/src/thrift/protocol/TUuidUtils.hpp b/lib/cpp/src/thrift/protocol/TUuidUtils.hpp
new file mode 100644
index 0000000..583147f
--- /dev/null
+++ b/lib/cpp/src/thrift/protocol/TUuidUtils.hpp
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+#ifndef _THRIFT_PROTOCOL_TUUIDUTILS_H_
+#define _THRIFT_PROTOCOL_TUUIDUTILS_H_
+
+#include <string>
+
+namespace apache {
+namespace thrift {
+namespace protocol {
+
+// Encode canonical UUID string to a 16 char representation
+// Supported formats for in:
+// - "hhhhhhhh-hhhh-hhhh-hhhh-hhhhhhhhhhhh"
+// - "{hhhhhhhh-hhhh-hhhh-hhhh-hhhhhhhhhhhh}"
+// - "hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh"
+// - "{hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh}"
+// Returns false if the string was invalid and the value was not encoded.
+bool uuid_encode(const std::string& in, std::string& out);
+
+// Decode 16 char UUID buffer to 36 characted string
+void uuid_decode(const std::string& in, std::string& out);
+
+}
+}
+} // apache::thrift::protocol
+
+#endif // #define _THRIFT_PROTOCOL_TUUIDUTILS_H_
diff --git a/lib/cpp/src/thrift/protocol/TVirtualProtocol.h b/lib/cpp/src/thrift/protocol/TVirtualProtocol.h
index b7fe929..4698081 100644
--- a/lib/cpp/src/thrift/protocol/TVirtualProtocol.h
+++ b/lib/cpp/src/thrift/protocol/TVirtualProtocol.h
@@ -393,6 +393,10 @@
return static_cast<Protocol_*>(this)->writeBinary(str);
}
+ uint32_t writeUUID_virt(const std::string& str) override {
+ return static_cast<Protocol_*>(this)->writeUUID(str);
+ }
+
/**
* Reading functions
*/
@@ -471,6 +475,10 @@
return static_cast<Protocol_*>(this)->readBinary(str);
}
+ uint32_t readUUID_virt(std::string& str) override {
+ return static_cast<Protocol_*>(this)->readUUID(str);
+ }
+
uint32_t skip_virt(TType type) override { return static_cast<Protocol_*>(this)->skip(type); }
/*
diff --git a/lib/cpp/test/Benchmark.cpp b/lib/cpp/test/Benchmark.cpp
index 56adac0..97a5317 100644
--- a/lib/cpp/test/Benchmark.cpp
+++ b/lib/cpp/test/Benchmark.cpp
@@ -66,6 +66,7 @@
ooe.some_characters = "JSON THIS! \"\1";
ooe.zomg_unicode = "\xd7\n\a\t";
ooe.base64 = "\1\2\3\255";
+ ooe.rfc4122_uuid = "{5e2ab188-1726-4e75-a04f-1ed9a6a89c4c}";
int num = 100000;
std::shared_ptr<TMemoryBuffer> buf(new TMemoryBuffer(num*1000));
diff --git a/lib/cpp/test/CMakeLists.txt b/lib/cpp/test/CMakeLists.txt
index 1117cd9..87ed109 100644
--- a/lib/cpp/test/CMakeLists.txt
+++ b/lib/cpp/test/CMakeLists.txt
@@ -360,7 +360,7 @@
)
add_custom_command(OUTPUT gen-cpp/DebugProtoTest_types.cpp gen-cpp/DebugProtoTest_types.h gen-cpp/EmptyService.cpp gen-cpp/EmptyService.h
- COMMAND ${THRIFT_COMPILER} --gen cpp ${PROJECT_SOURCE_DIR}/test/v0.16/DebugProtoTest.thrift
+ COMMAND ${THRIFT_COMPILER} --gen cpp ${PROJECT_SOURCE_DIR}/test/DebugProtoTest.thrift
)
add_custom_command(OUTPUT gen-cpp/EnumTest_types.cpp gen-cpp/EnumTest_types.h
@@ -384,7 +384,7 @@
)
add_custom_command(OUTPUT gen-cpp/SecondService.cpp gen-cpp/ThriftTest_constants.cpp gen-cpp/ThriftTest.cpp gen-cpp/ThriftTest_types.cpp gen-cpp/ThriftTest_types.h
- COMMAND ${THRIFT_COMPILER} --gen cpp ${PROJECT_SOURCE_DIR}/test/v0.16/ThriftTest.thrift
+ COMMAND ${THRIFT_COMPILER} --gen cpp ${PROJECT_SOURCE_DIR}/test/ThriftTest.thrift
)
add_custom_command(OUTPUT gen-cpp/OneWayService.cpp gen-cpp/OneWayTest_types.h gen-cpp/OneWayService.h
diff --git a/lib/cpp/test/DebugProtoTest.cpp b/lib/cpp/test/DebugProtoTest.cpp
index 060f354..cc4e5ff 100644
--- a/lib/cpp/test/DebugProtoTest.cpp
+++ b/lib/cpp/test/DebugProtoTest.cpp
@@ -74,6 +74,11 @@
" [1] = 2,\n"
" [2] = 3,\n"
" },\n"
+ " 15: rfc4122_uuid (uuid) = {\n"
+ " [in ] = \"\",\n"
+ " [raw] = \"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\",\n"
+ " [enc] = \"00000000-0000-0000-0000-000000000000\"\n"
+ " }\n"
"}");
const std::string result(apache::thrift::ThriftDebugString(*ooe));
@@ -98,6 +103,7 @@
"\xb0\xcf\x81\xe2\x84\x8e\x20\xce\x91\x74\x74"
"\xce\xb1\xe2\x85\xbd\xce\xba\xc7\x83\xe2\x80"
"\xbc";
+ n->my_ooe.rfc4122_uuid = "{5e2ab188-1726-4e75-a04f-1ed9a6a89c4c}";
n->my_bonk.type = 31337;
n->my_bonk.message = "I am a bonk... xor!";
}
@@ -141,6 +147,11 @@
" [1] = 2,\n"
" [2] = 3,\n"
" },\n"
+ " 15: rfc4122_uuid (uuid) = {\n"
+ " [in ] = \"{5e2ab188-1726-4e75-a04f-1ed9a6a89c4c}\",\n"
+ " [raw] = \"^*\\xb1\\x88\\x17&Nu\\xa0O\\x1e\\xd9\\xa6\\xa8\\x9cL\",\n"
+ " [enc] = \"5e2ab188-1726-4e75-a04f-1ed9a6a89c4c\"\n"
+ " }\n"
" },\n"
"}");
const std::string result(apache::thrift::ThriftDebugString(*n));
@@ -228,6 +239,11 @@
" [1] = 2,\n"
" [2] = 3,\n"
" },\n"
+ " 15: rfc4122_uuid (uuid) = {\n"
+ " [in ] = \"\",\n"
+ " [raw] = \"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\",\n"
+ " [enc] = \"00000000-0000-0000-0000-000000000000\"\n"
+ " }\n"
" },\n"
" [1] = OneOfEach {\n"
" 01: im_true (bool) = true,\n"
@@ -259,6 +275,11 @@
" [1] = 2,\n"
" [2] = 3,\n"
" },\n"
+ " 15: rfc4122_uuid (uuid) = {\n"
+ " [in ] = \"{5e2ab188-1726-4e75-a04f-1ed9a6a89c4c}\",\n"
+ " [raw] = \"^*\\xb1\\x88\\x17&Nu\\xa0O\\x1e\\xd9\\xa6\\xa8\\x9cL\",\n"
+ " [enc] = \"5e2ab188-1726-4e75-a04f-1ed9a6a89c4c\"\n"
+ " }\n"
" },\n"
" },\n"
" 02: contain (set) = set<list>[3] {\n"
diff --git a/lib/cpp/test/JSONProtoTest.cpp b/lib/cpp/test/JSONProtoTest.cpp
index 082c8a2..fedf99e 100644
--- a/lib/cpp/test/JSONProtoTest.cpp
+++ b/lib/cpp/test/JSONProtoTest.cpp
@@ -48,6 +48,7 @@
ooe->some_characters = "JSON THIS! \"\1";
ooe->zomg_unicode = "\xd7\n\a\t";
ooe->base64 = "\1\2\3\255";
+ ooe->rfc4122_uuid = "00000000-0000-0000-0000-000000000000";
}
BOOST_AUTO_TEST_CASE(test_json_proto_1) {
@@ -59,7 +60,7 @@
"535897931},\"8\":{\"str\":\"JSON THIS! \\\"\\u0001\"},\"9\":{\"str\":\"\xd7\\"
"n\\u0007\\t\"},\"10\":{\"tf\":0},\"11\":{\"str\":\"AQIDrQ\"},\"12\":{\"lst\""
":[\"i8\",3,1,2,3]},\"13\":{\"lst\":[\"i16\",3,1,2,3]},\"14\":{\"lst\":[\"i64"
- "\",3,1,2,3]}}");
+ "\",3,1,2,3]},\"15\":{\"uid\":\"00000000-0000-0000-0000-000000000000\"}}");
const std::string result(apache::thrift::ThriftJSONString(*ooe));
@@ -84,6 +85,7 @@
"\xb0\xcf\x81\xe2\x84\x8e\x20\xce\x91\x74\x74"
"\xce\xb1\xe2\x85\xbd\xce\xba\xc7\x83\xe2\x80"
"\xbc";
+ n->my_ooe.rfc4122_uuid = "5e2ab188-1726-4e75-a04f-1ed9a6a89c4c";
n->my_bonk.type = 31337;
n->my_bonk.message = "I am a bonk... xor!";
}
@@ -98,7 +100,8 @@
"1.6180339887498949},\"8\":{\"str\":\":R (me going \\\"rrrr\\\")\"},\"9\":{"
"\"str\":\"ӀⅮΝ Нοⅿоɡгаρℎ Αttαⅽκǃ‼\"},\"10\":{\"tf\":0},\"11\":{\"str\":\""
"AQIDrQ\"},\"12\":{\"lst\":[\"i8\",3,1,2,3]},\"13\":{\"lst\":[\"i16\",3,1,2"
- ",3]},\"14\":{\"lst\":[\"i64\",3,1,2,3]}}}}"
+ ",3]},\"14\":{\"lst\":[\"i64\",3,1,2,3]},\"15\":{\"uid\":\"5e2ab188-1726-"
+ "4e75-a04f-1ed9a6a89c4c\"}}}}"
);
const std::string result(apache::thrift::ThriftJSONString(*n));
@@ -162,12 +165,14 @@
"},\"7\":{\"dbl\":3.1415926535897931},\"8\":{\"str\":\"JSON THIS! \\\"\\u0001"
"\"},\"9\":{\"str\":\"\xd7\\n\\u0007\\t\"},\"10\":{\"tf\":0},\"11\":{\"str\":"
"\"AQIDrQ\"},\"12\":{\"lst\":[\"i8\",3,1,2,3]},\"13\":{\"lst\":[\"i16\",3,1,2"
- ",3]},\"14\":{\"lst\":[\"i64\",3,1,2,3]}},{\"1\":{\"tf\":1},\"2\":{\"tf\":0},"
+ ",3]},\"14\":{\"lst\":[\"i64\",3,1,2,3]},\"15\":{\"uid\":\"00000000-0000-0000"
+ "-0000-000000000000\"}},{\"1\":{\"tf\":1},\"2\":{\"tf\":0},"
"\"3\":{\"i8\":51},\"4\":{\"i16\":16},\"5\":{\"i32\":32},\"6\":{\"i64\":64},"
"\"7\":{\"dbl\":1.6180339887498949},\"8\":{\"str\":\":R (me going \\\"rrrr\\\""
")\"},\"9\":{\"str\":\"ӀⅮΝ Нοⅿоɡгаρℎ Αttαⅽκǃ‼\"},\"10\":{\"tf\":0},\"11\":{"
"\"str\":\"AQIDrQ\"},\"12\":{\"lst\":[\"i8\",3,1,2,3]},\"13\":{\"lst\":[\"i16"
- "\",3,1,2,3]},\"14\":{\"lst\":[\"i64\",3,1,2,3]}}]},\"2\":{\"set\":[\"lst\",3"
+ "\",3,1,2,3]},\"14\":{\"lst\":[\"i64\",3,1,2,3]},\"15\":{\"uid\":\"5e2ab188-"
+ "1726-4e75-a04f-1ed9a6a89c4c\"}}]},\"2\":{\"set\":[\"lst\",3"
",[\"str\",0],[\"str\",2,\"and a one\",\"and a two\"],[\"str\",3,\"then a one"
", two\",\"three!\",\"FOUR!!\"]]},\"3\":{\"map\":[\"str\",\"lst\",3,{\"nothin"
"g\":[\"rec\",0],\"poe\":[\"rec\",3,{\"1\":{\"i32\":3},\"2\":{\"str\":\"quoth"
@@ -192,6 +197,8 @@
OneOfEach ooe2;
ooe2.read(proto.get());
+ BOOST_TEST_INFO("written: " << *ooe);
+ BOOST_TEST_INFO("read : " << ooe2);
BOOST_CHECK(*ooe == ooe2);
}
@@ -205,6 +212,8 @@
HolyMoley hm2;
hm2.read(proto.get());
+ BOOST_TEST_INFO("written: " << *hm);
+ BOOST_TEST_INFO("read : " << hm2);
BOOST_CHECK(*hm == hm2);
hm2.big[0].a_bite = 0x00;
@@ -230,14 +239,14 @@
);
std::shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer());
- std::shared_ptr<TJSONProtocol> proto(new TJSONProtocol(buffer));
+ std::shared_ptr<TJSONProtocol> proto(new TJSONProtocol(buffer));
dub.write(proto.get());
Doubles dub_1;
dub_1.read(proto.get());
const std::string result(apache::thrift::ThriftJSONString(dub));
const std::string result_1(apache::thrift::ThriftJSONString(dub_1));
-
+
BOOST_CHECK_MESSAGE(!expected_result.compare(result),
"Expected:\n" << expected_result << "\nGotten:\n" << result);
BOOST_CHECK_MESSAGE(!expected_result.compare(result_1),
diff --git a/lib/cpp/test/SpecializationTest.cpp b/lib/cpp/test/SpecializationTest.cpp
index 008837d..0976112 100644
--- a/lib/cpp/test/SpecializationTest.cpp
+++ b/lib/cpp/test/SpecializationTest.cpp
@@ -26,6 +26,7 @@
ooe.some_characters = "JSON THIS! \"\1";
ooe.zomg_unicode = "\xd7\n\a\t";
ooe.base64 = "\1\2\3\255";
+ ooe.rfc4122_uuid = "00000000-0000-0000-0000-000000000000";
Nesting n;
n.my_ooe = ooe;
@@ -89,6 +90,8 @@
OneOfEach ooe2;
ooe2.read(proto.get());
+ BOOST_TEST_INFO("Write: " << ooe);
+ BOOST_TEST_INFO("Read : " << ooe2);
BOOST_CHECK(ooe == ooe2);
hm.write(proto.get());
diff --git a/lib/cpp/test/ToStringTest.cpp b/lib/cpp/test/ToStringTest.cpp
index 736b33c..68c82ad 100644
--- a/lib/cpp/test/ToStringTest.cpp
+++ b/lib/cpp/test/ToStringTest.cpp
@@ -160,4 +160,13 @@
"ListBonks(bonk=[Bonk(message=a, type=0), Bonk(message=b, type=0)])");
}
+BOOST_AUTO_TEST_CASE(generated_uuid_to_string) {
+ thrift::test::CrazyNesting l;
+ l.uuid_field = "{4b686716-5f20-4deb-8ce0-9eaf379e8a3d}";
+
+ BOOST_CHECK_EQUAL(to_string(l),
+ "CrazyNesting(string_field=, set_field=<null>, list_field=[], binary_field=, "
+ "uuid_field={4b686716-5f20-4deb-8ce0-9eaf379e8a3d})");
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/cpp/CMakeLists.txt b/test/cpp/CMakeLists.txt
index f693a27..a6c1fd5 100644
--- a/test/cpp/CMakeLists.txt
+++ b/test/cpp/CMakeLists.txt
@@ -100,7 +100,7 @@
#
add_custom_command(OUTPUT gen-cpp/SecondService.cpp gen-cpp/SecondService.h gen-cpp/ThriftTest.cpp gen-cpp/ThriftTest.h gen-cpp/ThriftTest_types.cpp gen-cpp/ThriftTest_constants.cpp
- COMMAND ${THRIFT_COMPILER} --gen cpp:templates,cob_style -r ${PROJECT_SOURCE_DIR}/test/v0.16/ThriftTest.thrift
+ COMMAND ${THRIFT_COMPILER} --gen cpp:templates,cob_style -r ${PROJECT_SOURCE_DIR}/test/ThriftTest.thrift
)
add_custom_command(OUTPUT gen-cpp/Service.cpp
diff --git a/test/cpp/src/TestClient.cpp b/test/cpp/src/TestClient.cpp
index c4146cc..fd04ed8 100644
--- a/test/cpp/src/TestClient.cpp
+++ b/test/cpp/src/TestClient.cpp
@@ -70,7 +70,7 @@
//
template<typename Proto>
-class TPedanticProtocol : public Proto
+class TPedanticProtocol : public Proto
{
public:
TPedanticProtocol(std::shared_ptr<TTransport>& transport)
@@ -178,6 +178,18 @@
return_code |= ERR_BASETYPES; \
}
+#define UUID_TEST(func, value, expected) \
+ cout << #func "(" << value << ") = "; \
+ try { \
+ if (!print_eq(expected, testClient.func(value))) \
+ return_code |= ERR_BASETYPES; \
+ } catch (TTransportException&) { \
+ throw; \
+ } catch (exception & ex) { \
+ cout << "*** FAILED ***" << endl << ex.what() << endl; \
+ return_code |= ERR_BASETYPES; \
+ }
+
int binary_test(ThriftTestClient& testClient, string::size_type siz);
BOOST_CONSTEXPR_OR_CONST int ERR_BASETYPES = 1;
@@ -638,6 +650,15 @@
if (i > 0) { i *= 2; } else { ++i; }
}
+ /**
+ * UUID TEST
+ */
+ const std::string expected_uuid{"5e2ab188-1726-4e75-a04f-1ed9a6a89c4c"};
+ UUID_TEST(testUuid, std::string{"{5e2ab188-1726-4e75-a04f-1ed9a6a89c4c}"}, expected_uuid);
+ UUID_TEST(testUuid, std::string{"5e2ab188-1726-4e75-a04f-1ed9a6a89c4c"}, expected_uuid);
+ UUID_TEST(testUuid, std::string{"5e2ab18817264e75a04f1ed9a6a89c4c"}, expected_uuid);
+ UUID_TEST(testUuid, std::string{"{5e2ab18817264e75a04f1ed9a6a89c4c}"}, expected_uuid);
+ UUID_TEST(testUuid, std::string{}, std::string{"00000000-0000-0000-0000-000000000000"});
/**
* STRUCT TEST
diff --git a/test/cpp/src/TestServer.cpp b/test/cpp/src/TestServer.cpp
index 65317f8..6c61f40 100644
--- a/test/cpp/src/TestServer.cpp
+++ b/test/cpp/src/TestServer.cpp
@@ -132,6 +132,11 @@
_return = thing;
}
+ std::string testUuid(const std::string thing) override {
+ printf("testUuid(\"{%s}\")\n", thing.c_str());
+ return thing;
+ }
+
void testStruct(Xtruct& out, const Xtruct& thing) override {
printf("testStruct({\"%s\", %d, %d, %" PRId64 "})\n",
thing.string_thing.c_str(),
@@ -442,6 +447,11 @@
cob(res);
}
+ void testUuid(::std::function<void(std::string const& _return)> cob, const std::string thing) override {
+ std::string res = _delegate->testUuid(thing);
+ cob(res);
+ }
+
void testStruct(std::function<void(Xtruct const& _return)> cob, const Xtruct& thing) override {
Xtruct res;
_delegate->testStruct(res, thing);