forked from facebook/fbthrift
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support indirection in C++ static reflection
Summary: [Thrift] Support indirection in C++ static reflection. Indirection is done with a type alias with special annotations: ``` typedef i32 (cpp.type = 'CppTypeWrappingI32', cpp.indirection = '.chain().of.member().accesses') WrappedI32 struct HasOneIntegralField { 1: WrappedI32 integral_field, } ``` Previously, `reflected_struct_data_member</*...*/>::getter` had no way to see the wrapped object. And code using it had no way to know, supposing the field type is a wrapper, how to access the wrapped object. Here, we change the `getter` to see through any wrappers to access the wrapped object directly. However, this leaves reflection without any way to access the wrapper object. Tradeoffs. Reviewed By: juchem Differential Revision: D4406389 fbshipit-source-id: 0904e9fdefb55f1e0c1a48899d76c1d76659b8c8
- Loading branch information
1 parent
1b74346
commit 6804932
Showing
8 changed files
with
287 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
cpp_include "thrift/test/fatal_reflection_indirection_types.h" | ||
|
||
namespace cpp2 reflection_indirection | ||
|
||
typedef i32 (cpp.type = 'CppFakeI32') FakeI32 | ||
typedef i32 (cpp.type = 'CppHasANumber', cpp.indirection = '.number') HasANumber | ||
typedef i32 (cpp.type = 'CppHasAResult', cpp.indirection = '.foo().result()') | ||
HasAResult | ||
|
||
struct struct_with_indirections { | ||
1: i32 real, | ||
2: FakeI32 fake, | ||
3: HasANumber number, | ||
4: HasAResult result, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
/* | ||
* Copyright 2017 Facebook, Inc. | ||
* | ||
* 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. | ||
*/ | ||
|
||
#include "thrift/test/gen-cpp2/fatal_reflection_indirection_fatal.h" | ||
|
||
#include <gtest/gtest.h> | ||
|
||
#include <folly/Utility.h> | ||
#include <folly/Traits.h> | ||
#include <thrift/lib/cpp2/fatal/internal/test_helpers.h> | ||
|
||
namespace { | ||
|
||
class FatalReflectionIndirectionTest : public testing::Test {}; | ||
} | ||
|
||
using type = reflection_indirection::struct_with_indirections; | ||
using info = apache::thrift::reflect_struct<type>; | ||
|
||
TEST_F(FatalReflectionIndirectionTest, sanity_check_no_indirection) { | ||
type obj; | ||
obj.real = 12; | ||
EXPECT_EQ(12, obj.real); | ||
} | ||
|
||
TEST_F(FatalReflectionIndirectionTest, simple_alias_no_indirection) { | ||
type obj; | ||
obj.fake = 15; | ||
EXPECT_EQ(15, obj.fake); | ||
} | ||
|
||
TEST_F(FatalReflectionIndirectionTest, indirection_via_single_member_field) { | ||
using getter = info::member::number::getter; | ||
EXPECT_SAME< | ||
std::int32_t &, | ||
decltype(getter::ref(std::declval<type &>())) | ||
>(); | ||
EXPECT_SAME< | ||
std::int32_t &&, | ||
decltype(getter::ref(std::declval<type &&>())) | ||
>(); | ||
EXPECT_SAME< | ||
std::int32_t const&, | ||
decltype(getter::ref(std::declval<type const&>())) | ||
>(); | ||
|
||
type obj; | ||
obj.number.number = -43; | ||
EXPECT_EQ(-43, getter::ref(obj)); | ||
} | ||
|
||
TEST_F(FatalReflectionIndirectionTest, indirection_via_chained_member_funcs) { | ||
using getter = info::member::result::getter; | ||
EXPECT_SAME< | ||
std::int32_t &, | ||
decltype(getter::ref(std::declval<type &>())) | ||
>(); | ||
EXPECT_SAME< | ||
std::int32_t &&, | ||
decltype(getter::ref(std::declval<type &&>())) | ||
>(); | ||
EXPECT_SAME< | ||
std::int32_t const&, | ||
decltype(getter::ref(std::declval<type const&>())) | ||
>(); | ||
|
||
type obj; | ||
obj.result.foo().result() = -2; | ||
EXPECT_EQ(-2, getter::ref(obj)); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
/* | ||
* Copyright 2017 Facebook, Inc. | ||
* | ||
* 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. | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include <cstdint> | ||
|
||
namespace reflection_indirection { | ||
|
||
using CppFakeI32 = std::int32_t; | ||
|
||
struct CppHasANumber { | ||
std::int32_t number{}; | ||
CppHasANumber() {} | ||
explicit CppHasANumber(std::int32_t number_) : number(number_) {} | ||
bool operator==(CppHasANumber that) const { return number == that.number; } | ||
bool operator!=(CppHasANumber that) const { return number != that.number; } | ||
}; | ||
|
||
class CppHasAResult { | ||
public: | ||
class Foo { | ||
public: | ||
explicit Foo(std::int32_t& obj) : obj_(obj) {} | ||
auto& result() & { return obj_; } | ||
auto&& result() && { return std::move(obj_); } | ||
auto const& result() const& { return obj_; } | ||
private: | ||
std::int32_t& obj_; | ||
}; | ||
|
||
CppHasAResult() {} | ||
explicit CppHasAResult(std::int32_t result) : result_(result) {} | ||
CppHasAResult(CppHasAResult const& that) : result_(that.result_) {} | ||
CppHasAResult& operator=(CppHasAResult const& that) { | ||
this->~CppHasAResult(); | ||
return *::new (this) CppHasAResult(that); | ||
} | ||
|
||
bool operator==(CppHasAResult that) const { return result_ == that.result_; } | ||
bool operator!=(CppHasAResult that) const { return result_ != that.result_; } | ||
|
||
Foo& foo() & { return foo_; } | ||
Foo&& foo() && { return static_cast<Foo&&>(foo_); } | ||
Foo const& foo() const& { return foo_; } | ||
|
||
private: | ||
std::int32_t result_{}; | ||
Foo foo_{result_}; | ||
}; | ||
} |