Skip to content

Commit 74820e0

Browse files
ami7ofacebook-github-bot
authored andcommitted
Add op::encode
Summary: Added `op::encode(Protocol& prot, T value)` to Encode.h, which encodes the given value to the given protocol using the type tag. This handles the adapted type using toThrift(). This will be used in codegen if struct as an annotation UseOpEncode (adding in next diff). Reviewed By: Mizuchi Differential Revision: D39027400 fbshipit-source-id: 2f41b8dd36cbaafc58bc4d0318de01ec9e275beb
1 parent ed48fe4 commit 74820e0

File tree

3 files changed

+344
-1
lines changed

3 files changed

+344
-1
lines changed

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@
2020

2121
namespace apache {
2222
namespace thrift {
23-
namespace op {} // namespace op
23+
namespace op {
24+
25+
// Encodes the given value to the given protocol using the type tag.
26+
// This handles adapted type.
27+
// For example: encode<type::int16_t>(prot, 1);
28+
template <typename Tag>
29+
FOLLY_INLINE_VARIABLE constexpr detail::Encode<Tag> encode{};
30+
31+
} // namespace op
2432
} // namespace thrift
2533
} // namespace apache

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

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,22 @@
1515
*/
1616

1717
#include <folly/portability/GTest.h>
18+
#include <thrift/conformance/cpp2/internal/AnyStructSerializer.h>
19+
#include <thrift/lib/cpp/util/EnumUtils.h>
1820
#include <thrift/lib/cpp2/op/Encode.h>
21+
#include <thrift/lib/cpp2/protocol/Object.h>
22+
#include <thrift/lib/cpp2/type/Tag.h>
23+
#include <thrift/test/AdapterTest.h>
24+
#include <thrift/test/testset/Testset.h>
25+
26+
using namespace ::apache::thrift::conformance;
27+
28+
using detail::protocol_reader_t;
29+
using detail::protocol_writer_t;
1930

2031
namespace apache::thrift::op {
2132
namespace {
33+
using apache::thrift::protocol::asValueStruct;
2234
using apache::thrift::protocol::TType;
2335
using detail::typeTagToTType;
2436

@@ -52,5 +64,154 @@ TEST(EncodeTest, TypeTagToTType) {
5264
(typeTagToTType<type::adapted<void, type::struct_t<void>>>),
5365
TType::T_STRUCT);
5466
}
67+
68+
template <conformance::StandardProtocol Protocol, typename Tag, typename T>
69+
protocol::Value encodeAndParseValue(
70+
T value, TType ttype, bool string_to_binary = true) {
71+
protocol_writer_t<Protocol> writer;
72+
folly::IOBufQueue queue;
73+
writer.setOutput(&queue);
74+
encode<Tag>(writer, value);
75+
protocol_reader_t<Protocol> reader;
76+
auto serialized = queue.move();
77+
reader.setInput(serialized.get());
78+
return protocol::detail::parseValue(reader, ttype, string_to_binary);
79+
}
80+
81+
template <conformance::StandardProtocol Protocol, typename Tag, typename T>
82+
void testEncode(T value, bool string_to_binary = true) {
83+
SCOPED_TRACE(folly::pretty_name<Tag>());
84+
auto result = encodeAndParseValue<Protocol, Tag>(
85+
value, typeTagToTType<Tag>, string_to_binary);
86+
EXPECT_EQ(result, asValueStruct<Tag>(value));
87+
}
88+
89+
template <conformance::StandardProtocol Protocol>
90+
void testEncodeBasicTypes() {
91+
SCOPED_TRACE(apache::thrift::util::enumNameSafe(Protocol));
92+
testEncode<Protocol, type::bool_t>(true);
93+
testEncode<Protocol, type::byte_t>(1);
94+
testEncode<Protocol, type::i16_t>(1);
95+
testEncode<Protocol, type::i32_t>(1);
96+
testEncode<Protocol, type::i64_t>(1);
97+
testEncode<Protocol, type::float_t>(1.5);
98+
testEncode<Protocol, type::double_t>(1.5);
99+
testEncode<Protocol, type::string_t>("foo", false);
100+
testEncode<Protocol, type::binary_t>("foo");
101+
testEncode<Protocol, type::enum_t<int>>(1);
102+
}
103+
104+
template <conformance::StandardProtocol Protocol>
105+
void testEncodeContainers() {
106+
SCOPED_TRACE(apache::thrift::util::enumNameSafe(Protocol));
107+
testEncode<Protocol, type::list<type::enum_t<int>>>(
108+
std::vector<int32_t>{1, 2, 3});
109+
testEncode<Protocol, type::set<type::bool_t>>(std::set<bool>{true, false});
110+
testEncode<Protocol, type::map<type::string_t, type::byte_t>>(
111+
std::map<std::string, int8_t>{{"foo", 1}, {"bar", 2}}, false);
112+
}
113+
114+
template <conformance::StandardProtocol Protocol>
115+
void testEncodeCppType() {
116+
SCOPED_TRACE(apache::thrift::util::enumNameSafe(Protocol));
117+
{
118+
// test cpp_type with primitive type
119+
auto result =
120+
encodeAndParseValue<Protocol, type::cpp_type<int, type::i16_t>>(
121+
1, TType::T_I16);
122+
EXPECT_EQ(result, asValueStruct<type::i16_t>(1));
123+
}
124+
}
125+
126+
// If IsAdapted is true, test op::encode with the given object with
127+
// type::adapted<test::TemplatedTestAdapter, Tag> tag and fromThrift.
128+
template <
129+
conformance::StandardProtocol Protocol,
130+
typename Struct,
131+
typename Tag,
132+
bool IsAdapted = false,
133+
typename T>
134+
void testEncodeObject(T value) {
135+
SCOPED_TRACE(folly::pretty_name<Tag>());
136+
Struct foo;
137+
foo.field_1_ref() = value;
138+
protocol_writer_t<Protocol> w1, w2;
139+
folly::IOBufQueue o1, o2;
140+
w1.setOutput(&o1);
141+
w2.setOutput(&o2);
142+
if constexpr (IsAdapted) {
143+
using AdaptedTag = type::adapted<test::TemplatedTestAdapter, Tag>;
144+
encode<AdaptedTag>(w1, test::TemplatedTestAdapter::fromThrift(foo));
145+
} else {
146+
encode<Tag>(w1, foo);
147+
}
148+
foo.write(&w2);
149+
EXPECT_TRUE(folly::IOBufEqualTo{}(*o1.move(), *o2.move()));
150+
}
151+
152+
template <conformance::StandardProtocol Protocol>
153+
void testEncodeStruct() {
154+
SCOPED_TRACE(apache::thrift::util::enumNameSafe(Protocol));
155+
using Struct =
156+
test::testset::struct_with<type::map<type::string_t, type::i32_t>>;
157+
std::map<std::string, int> mapValues = {{"one", 1}, {"four", 4}, {"two", 2}};
158+
testEncodeObject<Protocol, Struct, type::struct_t<Struct>>(mapValues);
159+
using Union = test::testset::union_with<type::set<type::string_t>>;
160+
std::set<std::string> setValues = {"foo", "bar", "baz"};
161+
testEncodeObject<Protocol, Union, type::union_t<Union>>(setValues);
162+
using Exception = test::testset::exception_with<type::i64_t>;
163+
testEncodeObject<Protocol, Exception, type::exception_t<Exception>>(1);
164+
}
165+
166+
template <conformance::StandardProtocol Protocol>
167+
void testEncodeAdapted() {
168+
SCOPED_TRACE(apache::thrift::util::enumNameSafe(Protocol));
169+
{
170+
// test op::encode with adapted struct
171+
using Struct = test::testset::struct_with<type::i32_t>;
172+
testEncodeObject<Protocol, Struct, type::struct_t<Struct>, true>(1);
173+
}
174+
{
175+
// test op::encode with adapted primitive type
176+
using AdaptedTag = type::adapted<test::TemplatedTestAdapter, type::i16_t>;
177+
auto result = encodeAndParseValue<Protocol, AdaptedTag>(
178+
test::TemplatedTestAdapter::fromThrift(1), TType::T_I16);
179+
EXPECT_EQ(result, asValueStruct<type::i16_t>(1));
180+
}
181+
{
182+
// test op::encode with adapted container
183+
auto value = std::map<std::string, int32_t>{{"foo", 1}, {"bar", 2}};
184+
using Tag = type::map<type::string_t, type::i32_t>;
185+
using AdaptedTag = type::adapted<test::TemplatedTestAdapter, Tag>;
186+
auto result = encodeAndParseValue<Protocol, AdaptedTag>(
187+
test::TemplatedTestAdapter::fromThrift(value), TType::T_MAP, false);
188+
EXPECT_EQ(result, asValueStruct<Tag>(value));
189+
}
190+
}
191+
192+
TEST(EncodeTest, EncodeBasicTypes) {
193+
testEncodeBasicTypes<conformance::StandardProtocol::Binary>();
194+
testEncodeBasicTypes<conformance::StandardProtocol::Compact>();
195+
}
196+
197+
TEST(EncodeTest, EncodeContainers) {
198+
testEncodeContainers<conformance::StandardProtocol::Binary>();
199+
testEncodeContainers<conformance::StandardProtocol::Compact>();
200+
}
201+
202+
TEST(EncodeTest, EncodeStruct) {
203+
testEncodeStruct<conformance::StandardProtocol::Binary>();
204+
testEncodeStruct<conformance::StandardProtocol::Compact>();
205+
}
206+
207+
TEST(EncodeTest, EncodeCppType) {
208+
testEncodeCppType<conformance::StandardProtocol::Binary>();
209+
testEncodeCppType<conformance::StandardProtocol::Compact>();
210+
}
211+
212+
TEST(EncodeTest, EncodeAdapted) {
213+
testEncodeAdapted<conformance::StandardProtocol::Binary>();
214+
testEncodeAdapted<conformance::StandardProtocol::Compact>();
215+
}
55216
} // namespace
56217
} // namespace apache::thrift::op

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

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#pragma once
1818

1919
#include <thrift/lib/cpp/protocol/TType.h>
20+
#include <thrift/lib/cpp2/type/NativeType.h>
2021
#include <thrift/lib/cpp2/type/Tag.h>
2122

2223
namespace apache {
@@ -102,6 +103,179 @@ template <typename Tag>
102103
FOLLY_INLINE_VARIABLE constexpr apache::thrift::protocol::TType typeTagToTType =
103104
detail::TypeTagToTType<Tag>::value;
104105

106+
template <typename>
107+
struct Encode;
108+
109+
template <>
110+
struct Encode<type::bool_t> {
111+
template <typename Protocol>
112+
uint32_t operator()(Protocol& prot, bool t) const {
113+
return prot.writeBool(t);
114+
}
115+
};
116+
117+
template <>
118+
struct Encode<type::byte_t> {
119+
template <typename Protocol>
120+
uint32_t operator()(Protocol& prot, int8_t i) const {
121+
return prot.writeByte(i);
122+
}
123+
};
124+
125+
template <>
126+
struct Encode<type::i16_t> {
127+
template <typename Protocol>
128+
uint32_t operator()(Protocol& prot, int16_t i) const {
129+
return prot.writeI16(i);
130+
}
131+
};
132+
133+
template <>
134+
struct Encode<type::i32_t> {
135+
template <typename Protocol>
136+
uint32_t operator()(Protocol& prot, int32_t i) const {
137+
return prot.writeI32(i);
138+
}
139+
};
140+
141+
template <>
142+
struct Encode<type::i64_t> {
143+
template <typename Protocol>
144+
uint32_t operator()(Protocol& prot, int64_t i) const {
145+
return prot.writeI64(i);
146+
}
147+
};
148+
149+
template <>
150+
struct Encode<type::float_t> {
151+
template <typename Protocol>
152+
uint32_t operator()(Protocol& prot, float i) const {
153+
return prot.writeFloat(i);
154+
}
155+
};
156+
157+
template <>
158+
struct Encode<type::double_t> {
159+
template <typename Protocol>
160+
uint32_t operator()(Protocol& prot, double i) const {
161+
return prot.writeDouble(i);
162+
}
163+
};
164+
165+
template <>
166+
struct Encode<type::string_t> {
167+
template <typename Protocol>
168+
uint32_t operator()(Protocol& prot, const std::string& s) const {
169+
return prot.writeString(s);
170+
}
171+
};
172+
173+
template <>
174+
struct Encode<type::binary_t> {
175+
template <typename Protocol>
176+
uint32_t operator()(Protocol& prot, const std::string& s) const {
177+
return prot.writeBinary(s);
178+
}
179+
};
180+
181+
template <typename T>
182+
struct Encode<type::struct_t<T>> {
183+
template <typename Protocol>
184+
uint32_t operator()(Protocol& prot, const T& s) const {
185+
return s.write(&prot);
186+
}
187+
};
188+
189+
template <typename T>
190+
struct Encode<type::union_t<T>> {
191+
template <typename Protocol>
192+
uint32_t operator()(Protocol& prot, const T& s) const {
193+
return s.write(&prot);
194+
}
195+
};
196+
197+
template <typename T>
198+
struct Encode<type::exception_t<T>> {
199+
template <typename Protocol>
200+
uint32_t operator()(Protocol& prot, const T& s) const {
201+
return s.write(&prot);
202+
}
203+
};
204+
205+
template <typename T>
206+
struct Encode<type::enum_t<T>> {
207+
template <typename Protocol>
208+
uint32_t operator()(Protocol& prot, const T& s) const {
209+
return prot.writeI32(static_cast<int32_t>(s));
210+
}
211+
};
212+
213+
// TODO: add optimization used in protocol_methods.h
214+
template <typename Tag>
215+
struct Encode<type::list<Tag>> {
216+
template <typename Protocol>
217+
uint32_t operator()(
218+
Protocol& prot, const type::native_type<type::list<Tag>>& list) const {
219+
std::size_t xfer = 0;
220+
xfer += prot.writeListBegin(typeTagToTType<Tag>, list.size());
221+
for (const auto& elem : list) {
222+
xfer += Encode<Tag>{}(prot, elem);
223+
}
224+
xfer += prot.writeListEnd();
225+
return xfer;
226+
}
227+
};
228+
229+
template <typename Tag>
230+
struct Encode<type::set<Tag>> {
231+
template <typename Protocol>
232+
uint32_t operator()(
233+
Protocol& prot, const type::native_type<type::set<Tag>>& set) const {
234+
std::size_t xfer = 0;
235+
xfer += prot.writeSetBegin(typeTagToTType<Tag>, set.size());
236+
for (const auto& elem : set) {
237+
xfer += Encode<Tag>{}(prot, elem);
238+
}
239+
xfer += prot.writeSetEnd();
240+
return xfer;
241+
}
242+
};
243+
244+
template <typename Key, typename Value>
245+
struct Encode<type::map<Key, Value>> {
246+
template <typename Protocol>
247+
uint32_t operator()(
248+
Protocol& prot,
249+
const type::native_type<type::map<Key, Value>>& map) const {
250+
std::size_t xfer = 0;
251+
xfer += prot.writeMapBegin(
252+
typeTagToTType<Key>, typeTagToTType<Value>, map.size());
253+
for (const auto& kv : map) {
254+
xfer += Encode<Key>{}(prot, kv.first);
255+
xfer += Encode<Value>{}(prot, kv.second);
256+
}
257+
xfer += prot.writeMapEnd();
258+
return xfer;
259+
}
260+
};
261+
262+
// TODO: Handle cpp_type with containers that cannot use static_cast.
263+
template <typename T, typename Tag>
264+
struct Encode<type::cpp_type<T, Tag>> {
265+
template <typename Protocol>
266+
uint32_t operator()(Protocol& prot, const T& t) const {
267+
return Encode<Tag>{}(prot, static_cast<type::native_type<Tag>>(t));
268+
}
269+
};
270+
271+
template <typename Adapter, typename Tag>
272+
struct Encode<type::adapted<Adapter, Tag>> {
273+
template <typename Protocol, typename U>
274+
uint32_t operator()(Protocol& prot, const U& m) const {
275+
return Encode<Tag>{}(prot, Adapter::toThrift(m));
276+
}
277+
};
278+
105279
} // namespace detail
106280
} // namespace op
107281
} // namespace thrift

0 commit comments

Comments
 (0)