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