Skip to content

Commit 53f62a0

Browse files
ami7ofacebook-github-bot
authored andcommitted
op::decode for other types
Summary: Added `op::decode(Protocol& prot, T& value)` for containers, structs, and adapted types. It calls fromThrift to handle adapted type. This will be used in codegen if struct as an annotation UseOpEncode (adding in next diff). Reviewed By: iahs Differential Revision: D39062398 fbshipit-source-id: ac133e0b62e9e1069ba75c88ca83c19151c20638
1 parent ab92bee commit 53f62a0

File tree

2 files changed

+267
-7
lines changed

2 files changed

+267
-7
lines changed

third-party/thrift/src/thrift/lib/cpp2/op/EncodeTest.cpp

Lines changed: 138 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -214,20 +214,33 @@ TEST(EncodeTest, EncodeAdapted) {
214214
testEncodeAdapted<conformance::StandardProtocol::Compact>();
215215
}
216216

217-
template <conformance::StandardProtocol Protocol, typename Tag, typename T>
218-
void testDecode(T value) {
219-
SCOPED_TRACE(folly::pretty_name<Tag>());
217+
// Encodes the given value with EncodeTag, and decodes the result with DecodeTag
218+
// to DecodeT type using the Protocol.
219+
template <
220+
conformance::StandardProtocol Protocol,
221+
typename EncodeTag,
222+
typename DecodeTag,
223+
typename DecodeT,
224+
typename EncodeT>
225+
DecodeT encodeAndDecode(EncodeT value) {
220226
protocol_writer_t<Protocol> writer;
221227
folly::IOBufQueue queue;
222228
writer.setOutput(&queue);
223-
encode<Tag>(writer, value);
229+
encode<EncodeTag>(writer, value);
224230

225231
protocol_reader_t<Protocol> reader;
226232
auto serialized = queue.move();
227233
reader.setInput(serialized.get());
228-
T result;
229-
decode<Tag>(reader, result);
230-
EXPECT_EQ(result, value);
234+
DecodeT result;
235+
decode<DecodeTag>(reader, result);
236+
return result;
237+
}
238+
239+
template <conformance::StandardProtocol Protocol, typename Tag, typename T>
240+
void testDecode(T value) {
241+
SCOPED_TRACE(folly::pretty_name<Tag>());
242+
EXPECT_EQ(
243+
(encodeAndDecode<Protocol, Tag, Tag, decltype(value)>(value)), value);
231244
}
232245

233246
template <conformance::StandardProtocol Protocol>
@@ -246,10 +259,128 @@ void testDecodeBasicTypes() {
246259
testDecode<Protocol, type::enum_t<MyEnum>>(MyEnum::value);
247260
}
248261

262+
template <conformance::StandardProtocol Protocol>
263+
void testDecodeContainers() {
264+
SCOPED_TRACE(apache::thrift::util::enumNameSafe(Protocol));
265+
testDecode<Protocol, type::list<type::enum_t<int>>>(
266+
std::vector<int32_t>{1, 2, 3});
267+
testDecode<Protocol, type::list<type::bool_t>>(
268+
std::vector<bool>{true, false, true});
269+
testDecode<Protocol, type::set<type::bool_t>>(std::set<bool>{true, false});
270+
testDecode<Protocol, type::map<type::string_t, type::byte_t>>(
271+
std::map<std::string, int8_t>{
272+
{std::string("foo"), 1}, {std::string("foo"), 2}});
273+
274+
// Test if it skips when value type doesn't match.
275+
{
276+
auto result = encodeAndDecode<
277+
Protocol,
278+
type::list<type::i32_t>,
279+
type::list<type::string_t>,
280+
std::vector<std::string>>(std::vector<int32_t>{1, 2, 3});
281+
EXPECT_TRUE(result.empty());
282+
}
283+
{
284+
auto result = encodeAndDecode<
285+
Protocol,
286+
type::set<type::i32_t>,
287+
type::set<type::i64_t>,
288+
std::set<int64_t>>(std::set<int32_t>{1, 2, 3});
289+
EXPECT_TRUE(result.empty());
290+
}
291+
{
292+
auto result = encodeAndDecode<
293+
Protocol,
294+
type::map<type::i32_t, type::bool_t>,
295+
type::map<type::string_t, type::bool_t>,
296+
std::map<std::string, bool>>(
297+
std::map<int32_t, bool>{{1, true}, {2, false}});
298+
EXPECT_TRUE(result.empty());
299+
}
300+
{
301+
auto result = encodeAndDecode<
302+
Protocol,
303+
type::map<type::string_t, type::bool_t>,
304+
type::map<type::string_t, type::i32_t>,
305+
std::map<std::string, int32_t>>(
306+
std::map<std::string, bool>{{"1", true}, {"2", false}});
307+
EXPECT_TRUE(result.empty());
308+
}
309+
}
310+
311+
template <
312+
conformance::StandardProtocol Protocol,
313+
typename Struct,
314+
typename Tag,
315+
bool IsAdapted = false,
316+
typename T>
317+
void testDecodeObject(T value) {
318+
Struct s;
319+
s.field_1_ref() = value;
320+
if constexpr (IsAdapted) {
321+
using AdaptedTag = type::adapted<test::TemplatedTestAdapter, Tag>;
322+
testDecode<Protocol, AdaptedTag>(test::TemplatedTestAdapter::fromThrift(s));
323+
} else {
324+
testDecode<Protocol, Tag>(s);
325+
}
326+
}
327+
328+
template <conformance::StandardProtocol Protocol>
329+
void testDecodeStruct() {
330+
SCOPED_TRACE(apache::thrift::util::enumNameSafe(Protocol));
331+
using Struct =
332+
test::testset::struct_with<type::map<type::string_t, type::i32_t>>;
333+
std::map<std::string, int> mapValues = {{"one", 1}, {"four", 4}, {"two", 2}};
334+
testDecodeObject<Protocol, Struct, type::struct_t<Struct>>(mapValues);
335+
using Union = test::testset::union_with<type::set<type::string_t>>;
336+
std::set<std::string> setValues = {"foo", "bar", "baz"};
337+
testDecodeObject<Protocol, Union, type::union_t<Union>>(setValues);
338+
using Exception = test::testset::exception_with<type::i64_t>;
339+
testDecodeObject<Protocol, Exception, type::exception_t<Exception>>(1);
340+
}
341+
342+
template <conformance::StandardProtocol Protocol>
343+
void testDecodeCppType() {
344+
SCOPED_TRACE(apache::thrift::util::enumNameSafe(Protocol));
345+
testDecode<Protocol, type::cpp_type<int, type::i16_t>>(1);
346+
}
347+
348+
template <conformance::StandardProtocol Protocol>
349+
void testDecodeAdapted() {
350+
SCOPED_TRACE(apache::thrift::util::enumNameSafe(Protocol));
351+
using AdaptedTag = type::adapted<test::TemplatedTestAdapter, type::string_t>;
352+
testDecode<Protocol, AdaptedTag>(
353+
test::TemplatedTestAdapter::fromThrift(std::string()));
354+
using Struct = test::testset::struct_with<type::i32_t>;
355+
testDecodeObject<Protocol, Struct, type::struct_t<Struct>, true>(1);
356+
using Union = test::testset::union_with<type::i32_t>;
357+
testDecodeObject<Protocol, Union, type::union_t<Union>, true>(1);
358+
}
359+
249360
TEST(DecodeTest, DecodeBasicTypes) {
250361
testDecodeBasicTypes<conformance::StandardProtocol::Binary>();
251362
testDecodeBasicTypes<conformance::StandardProtocol::Compact>();
252363
}
253364

365+
TEST(DecodeTest, DecodeContainers) {
366+
testDecodeContainers<conformance::StandardProtocol::Binary>();
367+
testDecodeContainers<conformance::StandardProtocol::Compact>();
368+
}
369+
370+
TEST(DecodeTest, DecodeStruct) {
371+
testDecodeStruct<conformance::StandardProtocol::Binary>();
372+
testDecodeStruct<conformance::StandardProtocol::Compact>();
373+
}
374+
375+
TEST(DecodeTest, DecodeCppType) {
376+
testDecodeCppType<conformance::StandardProtocol::Binary>();
377+
testDecodeCppType<conformance::StandardProtocol::Compact>();
378+
}
379+
380+
TEST(DecodeTest, DecodeAdapted) {
381+
testDecodeAdapted<conformance::StandardProtocol::Binary>();
382+
testDecodeAdapted<conformance::StandardProtocol::Compact>();
383+
}
384+
254385
} // namespace
255386
} // namespace apache::thrift::op

third-party/thrift/src/thrift/lib/cpp2/op/detail/Encode.h

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
#include <utility>
2020
#include <thrift/lib/cpp/protocol/TType.h>
21+
#include <thrift/lib/cpp2/protocol/detail/protocol_methods.h>
2122
#include <thrift/lib/cpp2/type/NativeType.h>
2223
#include <thrift/lib/cpp2/type/Tag.h>
2324

@@ -286,6 +287,13 @@ struct Decode<type::bool_t> {
286287
void operator()(Protocol& prot, bool& b) const {
287288
prot.readBool(b);
288289
}
290+
291+
template <typename Protocol>
292+
void operator()(Protocol& prot, std::vector<bool>::reference t) const {
293+
bool b;
294+
prot.readBool(b);
295+
t = b;
296+
}
289297
};
290298

291299
template <>
@@ -352,6 +360,30 @@ struct Decode<type::binary_t> {
352360
}
353361
};
354362

363+
template <typename T>
364+
struct Decode<type::struct_t<T>> {
365+
template <typename Protocol>
366+
void operator()(Protocol& prot, T& s) const {
367+
s.read(&prot);
368+
}
369+
};
370+
371+
template <typename T>
372+
struct Decode<type::union_t<T>> {
373+
template <typename Protocol>
374+
void operator()(Protocol& prot, T& s) const {
375+
s.read(&prot);
376+
}
377+
};
378+
379+
template <typename T>
380+
struct Decode<type::exception_t<T>> {
381+
template <typename Protocol>
382+
void operator()(Protocol& prot, T& s) const {
383+
s.read(&prot);
384+
}
385+
};
386+
355387
template <typename T>
356388
struct Decode<type::enum_t<T>> {
357389
template <typename Protocol>
@@ -362,6 +394,103 @@ struct Decode<type::enum_t<T>> {
362394
}
363395
};
364396

397+
// TODO: add optimization used in protocol_methods.h
398+
template <typename Tag>
399+
struct Decode<type::list<Tag>> {
400+
using ListType = type::native_type<type::list<Tag>>;
401+
template <typename Protocol>
402+
void operator()(Protocol& prot, ListType& list) const {
403+
TType t;
404+
uint32_t s;
405+
prot.readListBegin(t, s);
406+
apache::thrift::detail::pm::reserve_if_possible(&list, s);
407+
if (typeTagToTType<Tag> == t) {
408+
while (s--) {
409+
auto&& elem = apache::thrift::detail::pm::emplace_back_default(list);
410+
Decode<Tag>{}(prot, elem);
411+
}
412+
} else {
413+
while (s--) {
414+
prot.skip(t);
415+
}
416+
}
417+
prot.readListEnd();
418+
}
419+
};
420+
421+
template <typename Tag>
422+
struct Decode<type::set<Tag>> {
423+
using SetType = type::native_type<type::set<Tag>>;
424+
template <typename Protocol>
425+
void operator()(Protocol& prot, SetType& set) const {
426+
TType t;
427+
uint32_t s;
428+
prot.readSetBegin(t, s);
429+
apache::thrift::detail::pm::reserve_if_possible(&set, s);
430+
if (typeTagToTType<Tag> == t) {
431+
while (s--) {
432+
typename SetType::value_type value;
433+
Decode<Tag>{}(prot, value);
434+
set.emplace_hint(set.end(), std::move(value));
435+
}
436+
} else {
437+
while (s--) {
438+
prot.skip(t);
439+
}
440+
}
441+
prot.readSetEnd();
442+
}
443+
};
444+
445+
template <typename Key, typename Value>
446+
struct Decode<type::map<Key, Value>> {
447+
using MapType = type::native_type<type::map<Key, Value>>;
448+
template <typename Protocol>
449+
void operator()(Protocol& prot, MapType& map) const {
450+
TType keyType, valueType;
451+
uint32_t s;
452+
prot.readMapBegin(keyType, valueType, s);
453+
apache::thrift::detail::pm::reserve_if_possible(&map, s);
454+
if (typeTagToTType<Key> == keyType && typeTagToTType<Value> == valueType) {
455+
while (s--) {
456+
typename MapType::key_type key;
457+
Decode<Key>{}(prot, key);
458+
auto iter = map.emplace_hint(
459+
map.end(), std::move(key), typename MapType::mapped_type{});
460+
Decode<Value>{}(prot, iter->second);
461+
}
462+
} else {
463+
while (s--) {
464+
prot.skip(keyType);
465+
prot.skip(valueType);
466+
}
467+
}
468+
prot.readMapEnd();
469+
}
470+
};
471+
472+
// TODO: Handle cpp_type with containers that cannot use static_cast.
473+
template <typename T, typename Tag>
474+
struct Decode<type::cpp_type<T, Tag>> {
475+
template <typename Protocol>
476+
void operator()(Protocol& prot, T& t) const {
477+
type::native_type<Tag> u;
478+
Decode<Tag>{}(prot, u);
479+
t = static_cast<T>(u);
480+
}
481+
};
482+
483+
// TODO: Use inplace adapter deserialization as optimization.
484+
template <typename Adapter, typename Tag>
485+
struct Decode<type::adapted<Adapter, Tag>> {
486+
template <typename Protocol, typename U>
487+
void operator()(Protocol& prot, U& m) const {
488+
type::native_type<Tag> orig;
489+
Decode<Tag>{}(prot, orig);
490+
m = Adapter::fromThrift(std::move(orig));
491+
}
492+
};
493+
365494
} // namespace detail
366495
} // namespace op
367496
} // namespace thrift

0 commit comments

Comments
 (0)