Google Cloud Pub/Sub C++ Client  1.34.1
A C++ Client Library for Google Cloud Pub/Sub
message.h
Go to the documentation of this file.
1 // Copyright 2020 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_PUBSUB_MESSAGE_H
16 #define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_PUBSUB_MESSAGE_H
17 
18 #include "google/cloud/pubsub/version.h"
19 #include <google/pubsub/v1/pubsub.pb.h>
20 #include <chrono>
21 #include <iosfwd>
22 #include <map>
23 #include <string>
24 #include <vector>
25 
26 namespace google {
27 namespace cloud {
28 namespace pubsub {
30 class Message;
32 } // namespace pubsub
33 
34 namespace pubsub_internal {
36 ::google::pubsub::v1::PubsubMessage const& ToProto(pubsub::Message const&);
37 ::google::pubsub::v1::PubsubMessage&& ToProto(pubsub::Message&&);
38 pubsub::Message FromProto(::google::pubsub::v1::PubsubMessage);
39 
40 /// Estimate the size of a message.
41 std::size_t MessageSize(pubsub::Message const&);
43 } // namespace pubsub_internal
44 
45 namespace pubsub {
47 class MessageBuilder;
48 
49 /**
50  * Defines the type for message data.
51  *
52  * Inside Google some protobuf fields of type `bytes` are mapped to a different
53  * type than `std::string`. This is the case for message data. We use this
54  * type to automatically detect what is the representation for this field and
55  * use the correct mapping.
56  *
57  * External users of the Cloud Pubsub C++ client library should treat this as
58  * a complicated `typedef` for `std::string`. We have no plans to change the
59  * type in the external version of the C++ client library for the foreseeable
60  * future. In the eventuality that we do decide to change the type, this would
61  * be a reason update the library major version number, and we would give users
62  * time to migrate.
63  *
64  * In other words, external users of the Cloud Pubsub C++ client should simply
65  * write `std::string` where this type appears. For Google projects that must
66  * compile both inside and outside Google, this alias may be convenient.
67  */
68 using PubsubMessageDataType = std::decay<
69  decltype(std::declval<google::pubsub::v1::PubsubMessage>().data())>::type;
70 
71 /**
72  * The C++ representation for a Cloud Pub/Sub messages.
73  *
74  * Cloud Pub/Sub applications communicate to each other using messages. Note
75  * that messages must provide at least some data or some attributes. Use
76  * `MessageBuilder` to create instances of this class.
77  */
78 class Message {
79  public:
80  //@{
81  /// @name accessors
82  PubsubMessageDataType const& data() const& { return proto_.data(); }
83  PubsubMessageDataType&& data() && {
84  return std::move(*proto_.mutable_data());
85  }
86  std::string const& message_id() const { return proto_.message_id(); }
87  std::string const& ordering_key() const { return proto_.ordering_key(); }
88  std::chrono::system_clock::time_point publish_time() const;
89  std::map<std::string, std::string> attributes() const {
90  std::map<std::string, std::string> r;
91  for (auto const& kv : proto_.attributes()) {
92  r.emplace(kv.first, kv.second);
93  }
94  return r;
95  }
96  //@}
97 
98  //@{
99  /// @name Copy and move
100  Message(Message const&) = default;
101  Message& operator=(Message const&) = default;
102  Message(Message&&) = default;
103  Message& operator=(Message&&) = default;
104  //@}
105 
106  //@{
107  /// @name Equality operators
108  /// Compares two messages.
109  friend bool operator==(Message const& a, Message const& b);
110  /// Compares two messages.
111  friend bool operator!=(Message const& a, Message const& b) {
112  return !(a == b);
113  }
114  //@}
115 
116  /// Output in protobuf format, this is intended for debugging
117  friend std::ostream& operator<<(std::ostream& os, Message const& rhs);
118 
119  private:
120  friend Message pubsub_internal::FromProto(
121  ::google::pubsub::v1::PubsubMessage m);
122  friend ::google::pubsub::v1::PubsubMessage const& pubsub_internal::ToProto(
123  Message const& m);
124  friend ::google::pubsub::v1::PubsubMessage&& pubsub_internal::ToProto(
125  Message&& m);
126  friend std::size_t pubsub_internal::MessageSize(Message const&);
127 
128  /// Construct `Message` objects.
129  friend class MessageBuilder;
130 
131  Message() = default;
132 
133  explicit Message(::google::pubsub::v1::PubsubMessage m)
134  : proto_(std::move(m)) {}
135 
136  std::size_t MessageSize() const;
137 
138  google::pubsub::v1::PubsubMessage proto_;
139 };
140 
141 /** @relates Message
142  * Constructs `Message` objects.
143  */
145  public:
146  MessageBuilder() = default;
147 
148  /// Creates a new message.
149  Message Build() && { return Message(std::move(proto_)); }
150 
151  /// Sets the message payload to @p data
152  MessageBuilder& SetData(std::string data) & {
153  proto_.set_data(std::move(data));
154  return *this;
155  }
156 
157  /// Sets the message payload to @p data
158  MessageBuilder&& SetData(std::string data) && {
159  SetData(std::move(data));
160  return std::move(*this);
161  }
162 
163  /// Sets the ordering key to @p key
164  MessageBuilder& SetOrderingKey(std::string key) & {
165  proto_.set_ordering_key(std::move(key));
166  return *this;
167  }
168 
169  /// Sets the ordering key to @p key
170  MessageBuilder&& SetOrderingKey(std::string key) && {
171  return std::move(SetOrderingKey(std::move(key)));
172  }
173 
174  /// Inserts an attribute to the message, leaving the message unchanged if @p
175  /// key is already present.
176  MessageBuilder& InsertAttribute(std::string const& key,
177  std::string const& value) & {
178  using value_type =
179  google::protobuf::Map<std::string, std::string>::value_type;
180  proto_.mutable_attributes()->insert(value_type{key, value});
181  return *this;
182  }
183 
184  /// Inserts an attribute to the message, leaving the message unchanged if @p
185  /// key is already present.
186  MessageBuilder&& InsertAttribute(std::string const& key,
187  std::string const& value) && {
188  return std::move(InsertAttribute(key, value));
189  }
190 
191  /// Inserts or sets an attribute on the message.
192  MessageBuilder& SetAttribute(std::string const& key, std::string value) & {
193  (*proto_.mutable_attributes())[key] = std::move(value);
194  return *this;
195  }
196 
197  /// Inserts or sets an attribute on the message.
198  MessageBuilder&& SetAttribute(std::string const& key, std::string value) && {
199  return std::move(SetAttribute(key, std::move(value)));
200  }
201 
202  /// Sets the attributes in the message to the attributes from the range [@p
203  /// begin, @p end)
204  template <typename Iterator>
205  MessageBuilder& SetAttributes(Iterator begin, Iterator end) & {
206  google::protobuf::Map<std::string, std::string> tmp;
207  using value_type =
208  google::protobuf::Map<std::string, std::string>::value_type;
209  for (auto kv = begin; kv != end; ++kv) {
210  using std::get;
211  tmp.insert(value_type(get<0>(*kv), get<1>(*kv)));
212  }
213  proto_.mutable_attributes()->swap(tmp);
214  return *this;
215  }
216 
217  /// Sets the attributes in the message to the attributes from the range [@p
218  /// begin, @p end)
219  template <typename Iterator>
220  MessageBuilder&& SetAttributes(Iterator begin, Iterator end) && {
221  SetAttributes(std::move(begin), std::move(end));
222  return std::move(*this);
223  }
224 
225  /// Sets the attributes in the message to @p v
227  // NOLINTNEXTLINE(performance-unnecessary-value-param)
228  std::vector<std::pair<std::string, std::string>> v) & {
229  using value_type =
230  google::protobuf::Map<std::string, std::string>::value_type;
231  google::protobuf::Map<std::string, std::string> tmp;
232  for (auto& kv : v) {
233  tmp.insert(value_type(std::move(kv.first), std::move(kv.second)));
234  }
235  proto_.mutable_attributes()->swap(tmp);
236  return *this;
237  }
238 
239  /// Sets the attributes in the message to @p v
241  // NOLINTNEXTLINE(performance-unnecessary-value-param)
242  std::vector<std::pair<std::string, std::string>> v) && {
243  SetAttributes(std::move(v));
244  return std::move(*this);
245  }
246 
247  /// Sets the attributes in the message to @p v
248  template <typename Pair>
249  MessageBuilder& SetAttributes(std::vector<Pair> v) & {
250  return SetAttributes(v.begin(), v.end());
251  }
252 
253  /// Sets the attributes in the message to @p v
254  template <typename Pair>
255  MessageBuilder&& SetAttributes(std::vector<Pair> v) && {
256  SetAttributes(std::move(v));
257  return std::move(*this);
258  }
259 
260  private:
261  google::pubsub::v1::PubsubMessage proto_;
262 };
263 
265 } // namespace pubsub
266 
267 namespace pubsub_internal {
269 inline ::google::pubsub::v1::PubsubMessage const& ToProto(
270  pubsub::Message const& m) {
271  return m.proto_;
272 }
273 
274 inline ::google::pubsub::v1::PubsubMessage&& ToProto(pubsub::Message&& m) {
275  return std::move(m.proto_);
276 }
277 
278 inline pubsub::Message FromProto(::google::pubsub::v1::PubsubMessage m) {
279  return pubsub::Message(std::move(m));
280 }
281 
282 inline std::size_t MessageSize(pubsub::Message const& m) {
283  return m.MessageSize();
284 }
285 
286 std::size_t MessageProtoSize(::google::pubsub::v1::PubsubMessage const& m);
287 
289 } // namespace pubsub_internal
290 } // namespace cloud
291 } // namespace google
292 
293 #endif // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_PUBSUB_MESSAGE_H