1 //
2 // Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 #pragma once
8 
9 /**
10  * \file
11  * Contains the declarations of a base class for all TL-objects and some helper methods
12  */
13 
14 #include <cstddef>
15 #include <cstdint>
16 #include <string>
17 #include <type_traits>
18 #include <utility>
19 
20 namespace td {
21 
22 class TlStorerCalcLength;
23 
24 class TlStorerUnsafe;
25 
26 class TlStorerToString;
27 
28 /**
29  * This class is a base class for all TDLib TL-objects.
30  */
31 class TlObject {
32  public:
33   /**
34    * Returns an identifier, uniquely determining the TL-type of the object.
35    */
36   virtual std::int32_t get_id() const = 0;
37 
38   /**
39    * Appends the object to the storer serializing object, a buffer of fixed length.
40    * \param[in] s Storer to which the object will be appended.
41    */
store(TlStorerUnsafe & s)42   virtual void store(TlStorerUnsafe &s) const {
43   }
44 
45   /**
46    * Appends the object to the storer, calculating the TL-length of the serialized object.
47    * \param[in] s Storer to which the object will be appended.
48    */
store(TlStorerCalcLength & s)49   virtual void store(TlStorerCalcLength &s) const {
50   }
51 
52   /**
53    * Helper function for the to_string method. Appends a string representation of the object to the storer.
54    * \param[in] s Storer to which the object string representation will be appended.
55    * \param[in] field_name Object field_name if applicable.
56    */
57   virtual void store(TlStorerToString &s, const char *field_name) const = 0;
58 
59   /**
60    * Default constructor.
61    */
62   TlObject() = default;
63 
64   /**
65    * Deleted copy constructor.
66    */
67   TlObject(const TlObject &) = delete;
68 
69   /**
70    * Deleted copy assignment operator.
71    */
72   TlObject &operator=(const TlObject &) = delete;
73 
74   /**
75    * Default move constructor.
76    */
77   TlObject(TlObject &&) = default;
78 
79   /**
80    * Default move assignment operator.
81    */
82   TlObject &operator=(TlObject &&) = default;
83 
84   /**
85    * Virtual destructor.
86    */
87   virtual ~TlObject() = default;
88 };
89 
90 /// @cond UNDOCUMENTED
91 namespace tl {
92 
93 template <class T>
94 class unique_ptr {
95  public:
96   using pointer = T *;
97   using element_type = T;
98 
99   unique_ptr() noexcept = default;
100   unique_ptr(const unique_ptr &other) = delete;
101   unique_ptr &operator=(const unique_ptr &other) = delete;
unique_ptr(unique_ptr && other)102   unique_ptr(unique_ptr &&other) noexcept : ptr_(other.release()) {
103   }
104   unique_ptr &operator=(unique_ptr &&other) noexcept {
105     reset(other.release());
106     return *this;
107   }
~unique_ptr()108   ~unique_ptr() {
109     reset();
110   }
111 
unique_ptr(std::nullptr_t)112   unique_ptr(std::nullptr_t) noexcept {
113   }
unique_ptr(T * ptr)114   explicit unique_ptr(T *ptr) noexcept : ptr_(ptr) {
115   }
116   template <class S, class = typename std::enable_if<std::is_base_of<T, S>::value>::type>
unique_ptr(unique_ptr<S> && other)117   unique_ptr(unique_ptr<S> &&other) noexcept : ptr_(static_cast<S *>(other.release())) {
118   }
119   template <class S, class = typename std::enable_if<std::is_base_of<T, S>::value>::type>
120   unique_ptr &operator=(unique_ptr<S> &&other) noexcept {
121     reset(static_cast<T *>(other.release()));
122     return *this;
123   }
124   void reset(T *new_ptr = nullptr) noexcept {
125     static_assert(sizeof(T) > 0, "Can't destroy unique_ptr with incomplete type");
126     delete ptr_;
127     ptr_ = new_ptr;
128   }
release()129   T *release() noexcept {
130     auto res = ptr_;
131     ptr_ = nullptr;
132     return res;
133   }
get()134   T *get() noexcept {
135     return ptr_;
136   }
get()137   const T *get() const noexcept {
138     return ptr_;
139   }
140   T *operator->() noexcept {
141     return ptr_;
142   }
143   const T *operator->() const noexcept {
144     return ptr_;
145   }
146   T &operator*() noexcept {
147     return *ptr_;
148   }
149   const T &operator*() const noexcept {
150     return *ptr_;
151   }
152   explicit operator bool() const noexcept {
153     return ptr_ != nullptr;
154   }
155 
156  private:
157   T *ptr_{nullptr};
158 };
159 
160 template <class T>
161 bool operator==(std::nullptr_t, const unique_ptr<T> &p) {
162   return !p;
163 }
164 template <class T>
165 bool operator==(const unique_ptr<T> &p, std::nullptr_t) {
166   return !p;
167 }
168 template <class T>
169 bool operator!=(std::nullptr_t, const unique_ptr<T> &p) {
170   return static_cast<bool>(p);
171 }
172 template <class T>
173 bool operator!=(const unique_ptr<T> &p, std::nullptr_t) {
174   return static_cast<bool>(p);
175 }
176 
177 }  // namespace tl
178 /// @endcond
179 
180 /**
181  * A smart wrapper to store a pointer to a TL-object.
182  */
183 template <class Type>
184 using tl_object_ptr = tl::unique_ptr<Type>;
185 
186 /**
187  * A function to create a dynamically allocated TL-object. Can be treated as an analogue of std::make_unique.
188  * Usage example:
189  * \code
190  * auto get_authorization_state_request = td::make_tl_object<td::td_api::getAuthorizationState>();
191  * auto message_text = td::make_tl_object<td::td_api::formattedText>("Hello, world!!!",
192  *                     td::td_api::array<td::tl_object_ptr<td::td_api::textEntity>>());
193  * auto send_message_request = td::make_tl_object<td::td_api::sendMessage>(chat_id, 0, 0, nullptr, nullptr,
194  *      td::make_tl_object<td::td_api::inputMessageText>(std::move(message_text), false, true));
195  * \endcode
196  *
197  * \tparam Type Type of the TL-object to construct.
198  * \param[in] args Arguments to pass to the object constructor.
199  * \return Wrapped pointer to the created TL-object.
200  */
201 template <class Type, class... Args>
make_tl_object(Args &&...args)202 tl_object_ptr<Type> make_tl_object(Args &&... args) {
203   return tl_object_ptr<Type>(new Type(std::forward<Args>(args)...));
204 }
205 
206 /**
207  * A function to downcast a wrapped pointer to a TL-object to a pointer to its subclass.
208  * Casting an object to an incorrect type will lead to undefined behaviour.
209  * Examples of usage:
210  * \code
211  * td::tl_object_ptr<td::td_api::callState> call_state = ...;
212  * switch (call_state->get_id()) {
213  *   case td::td_api::callStatePending::ID: {
214  *     auto state = td::move_tl_object_as<td::td_api::callStatePending>(call_state);
215  *     // use state
216  *     break;
217  *   }
218  *   case td::td_api::callStateExchangingKeys::ID: {
219  *     // no additional fields, so cast isn't needed
220  *     break;
221  *   }
222  *   case td::td_api::callStateReady::ID: {
223  *     auto state = td::move_tl_object_as<td::td_api::callStateReady>(call_state);
224  *     // use state
225  *     break;
226  *   }
227  *   case td::td_api::callStateHangingUp::ID: {
228  *     // no additional fields, so cast isn't needed
229  *     break;
230  *   }
231  *   case td::td_api::callStateDiscarded::ID: {
232  *     auto state = td::move_tl_object_as<td::td_api::callStateDiscarded>(call_state);
233  *     // use state
234  *     break;
235  *   }
236  *   case td::td_api::callStateError::ID: {
237  *     auto state = td::move_tl_object_as<td::td_api::callStateError>(call_state);
238  *     // use state
239  *     break;
240  *   }
241  *   default:
242  *     assert(false);
243  * }
244  * \endcode
245  *
246  * \tparam ToT Type of a TL-object to move to.
247  * \tparam FromT Type of a TL-object to move from, this is auto-deduced.
248  * \param[in] from Wrapped pointer to a TL-object.
249  */
250 template <class ToT, class FromT>
move_tl_object_as(tl_object_ptr<FromT> & from)251 tl_object_ptr<ToT> move_tl_object_as(tl_object_ptr<FromT> &from) {
252   return tl_object_ptr<ToT>(static_cast<ToT *>(from.release()));
253 }
254 
255 /**
256  * \overload
257  */
258 template <class ToT, class FromT>
move_tl_object_as(tl_object_ptr<FromT> && from)259 tl_object_ptr<ToT> move_tl_object_as(tl_object_ptr<FromT> &&from) {
260   return tl_object_ptr<ToT>(static_cast<ToT *>(from.release()));
261 }
262 
263 }  // namespace td
264