1 /*
2 * Copyright (c) Facebook, Inc. and its affiliates.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #pragma once
18
19 #include <memory>
20 #include <string>
21 #include <string_view>
22 #include <folly/Range.h>
23 #include <thrift/lib/cpp/util/EnumUtils.h>
24 #include <thrift/lib/cpp2/util/ManagedStringView.h>
25 #include <thrift/lib/thrift/gen-cpp2/RpcMetadata_types.h>
26
27 namespace apache::thrift {
28
29 enum class FunctionQualifier {
30 Unspecified,
31 OneWay,
32 Idempotent,
33 ReadOnly,
34 };
35
qualifierToString(FunctionQualifier fq)36 inline std::string_view qualifierToString(FunctionQualifier fq) {
37 switch (fq) {
38 case FunctionQualifier::Unspecified:
39 return "Unspecified";
40 case FunctionQualifier::OneWay:
41 return "OneWay";
42 case FunctionQualifier::Idempotent:
43 return "Idempotent";
44 case FunctionQualifier::ReadOnly:
45 return "ReadOnly";
46 }
47 folly::assume_unreachable();
48 }
49
50 /*
51 * A move-only structure for storing thrift method metadata.
52 * Metadata : method name & function qualifier.
53 * When created from static data, the structure creates a view of the data
54 * When created from temporary data, the structure takes the ownership of
55 * the data by creating a dynamic storage for it.
56 */
57 class MethodMetadata {
58 public:
59 struct Data {
DataData60 Data(std::string name, FunctionQualifier qualifier)
61 : methodName(std::move(name)), functionQualifier(qualifier) {}
62 std::string methodName;
63 FunctionQualifier functionQualifier;
64 };
65
66 MethodMetadata() = delete;
67
MethodMetadata(const MethodMetadata & that)68 MethodMetadata(const MethodMetadata& that) {
69 if (that.isOwning()) {
70 isOwning_ = true;
71 data_ = new Data(*that.data_);
72 } else {
73 isOwning_ = false;
74 data_ = that.data_;
75 }
76 }
77
78 MethodMetadata& operator=(const MethodMetadata& that) {
79 if (that.isOwning()) {
80 if (isOwning()) {
81 *data_ = *that.data_;
82 } else {
83 isOwning_ = true;
84 data_ = new Data(*that.data_);
85 }
86 } else {
87 if (isOwning()) {
88 delete data_;
89 data_ = that.data_;
90 isOwning_ = false;
91 } else {
92 data_ = that.data_;
93 }
94 }
95 return *this;
96 }
97
MethodMetadata(MethodMetadata && that)98 MethodMetadata(MethodMetadata&& that) noexcept
99 : isOwning_(std::exchange(that.isOwning_, false)),
100 data_(std::exchange(that.data_, nullptr)) {}
101
102 MethodMetadata& operator=(MethodMetadata&& that) noexcept {
103 MethodMetadata tmp(std::move(that));
104 swap(*this, tmp);
105 return *this;
106 }
107
~MethodMetadata()108 ~MethodMetadata() noexcept {
109 if (isOwning()) {
110 delete data_;
111 }
112 }
113
MethodMetadata(std::string_view methodName)114 /* implicit */ MethodMetadata(std::string_view methodName)
115 : isOwning_(true),
116 data_(new Data(
117 std::string(methodName), FunctionQualifier::Unspecified)) {}
118
MethodMetadata(std::string && methodName)119 /* implicit */ MethodMetadata(std::string&& methodName)
120 : isOwning_(true),
121 data_(new Data(std::move(methodName), FunctionQualifier::Unspecified)) {
122 }
123
MethodMetadata(const std::string & methodName)124 /* implicit */ MethodMetadata(const std::string& methodName)
125 : isOwning_(true),
126 data_(new Data(methodName, FunctionQualifier::Unspecified)) {}
127
MethodMetadata(const char * methodName)128 /* implicit */ MethodMetadata(const char* methodName)
129 : isOwning_(true),
130 data_(new Data(methodName, FunctionQualifier::Unspecified)) {}
131
MethodMetadata(folly::StringPiece methodName)132 /* implicit */ MethodMetadata(folly::StringPiece methodName)
133 : isOwning_(true),
134 data_(new Data(
135 std::string(methodName), FunctionQualifier::Unspecified)) {}
136
MethodMetadata(const Data & data)137 /* implicit */ MethodMetadata(const Data& data)
138 : isOwning_(true), data_(new Data(data)) {}
139
from_static(Data * mPtr)140 static MethodMetadata from_static(Data* mPtr) {
141 return MethodMetadata(mPtr, NonOwningTag{});
142 }
143
name_managed()144 ManagedStringView name_managed() const& {
145 if (isOwning()) {
146 return ManagedStringView(name_view());
147 } else {
148 return ManagedStringView::from_static(name_view());
149 }
150 }
151
name_managed()152 ManagedStringView name_managed() && {
153 if (isOwning()) {
154 return ManagedStringView(std::move(data_->methodName));
155 } else {
156 return ManagedStringView::from_static(name_view());
157 }
158 }
159
name_str()160 std::string name_str() const& { return data_->methodName; }
161
name_str()162 std::string name_str() && {
163 return isOwning() ? std::move(data_->methodName) : data_->methodName;
164 }
165
name_view()166 std::string_view name_view() const {
167 return std::string_view(data_->methodName);
168 }
169
qualifier()170 FunctionQualifier qualifier() const { return data_->functionQualifier; }
171
isOwning()172 bool isOwning() const { return isOwning_; }
173
174 private:
175 struct NonOwningTag {};
176 struct OwningTag {};
177
MethodMetadata(Data * mPtr,OwningTag)178 MethodMetadata(Data* mPtr, OwningTag)
179 : isOwning_(true), data_(new Data(*mPtr)) {}
180
MethodMetadata(Data * mPtr,NonOwningTag)181 MethodMetadata(Data* mPtr, NonOwningTag) : isOwning_(false), data_(mPtr) {}
182
swap(MethodMetadata & left,MethodMetadata & right)183 friend void swap(MethodMetadata& left, MethodMetadata& right) noexcept {
184 std::swap(left.isOwning_, right.isOwning_);
185 std::swap(left.data_, right.data_);
186 }
187
188 bool isOwning_{false};
189 Data* data_{nullptr};
190 };
191
192 } // namespace apache::thrift
193