uvcc
libuv C++ bindings
request-stream.hpp
1 
2 #ifndef UVCC_REQUEST_STREAM__HPP
3 #define UVCC_REQUEST_STREAM__HPP
4 
5 #include "uvcc/utility.hpp"
6 #include "uvcc/request-base.hpp"
7 #include "uvcc/handle-stream.hpp"
8 #include "uvcc/buffer.hpp"
9 
10 #include <uv.h>
11 
12 #include <functional> // function
13 #include <type_traits> // enable_if_t
14 
15 
16 namespace uv
17 {
18 
19 
20 /*! \ingroup doxy_group__request
21  \brief Stream connect request type.
22  \sa libuv API documentation: [`uv_stream_t` — Stream handle](http://docs.libuv.org/en/v1.x/stream.html#uv-stream-t-stream-handle),\n
23  [`uv_tcp_t` — TCP handle](http://docs.libuv.org/en/v1.x/tcp.html#uv-tcp-t-tcp-handle),\n
24  [`uv_pipe_t` — Pipe handle](http://docs.libuv.org/en/v1.x/pipe.html#uv-pipe-t-pipe-handle). */
25 class connect : public request
26 {
27  //! \cond
28  friend class request::instance< connect >;
29  //! \endcond
30 
31 public: /*types*/
32  using uv_t = ::uv_connect_t;
33  using on_request_t = std::function< void(connect _request) >;
34  /*!< \brief The function type of the callback called after connection is done.
35  \sa libuv API documentation: [`uv_connect_cb`](http://docs.libuv.org/en/v1.x/stream.html#c.uv_connect_cb). */
36 
37 private: /*types*/
38  using instance = request::instance< connect >;
39 
40 protected: /*constructors*/
41  //! \cond
42  explicit connect(uv_t *_uv_req) : request(reinterpret_cast< request::uv_t* >(_uv_req)) {}
43  //! \endcond
44 
45 public: /*constructors*/
46  ~connect() = default;
47  connect()
48  {
49  uv_req = instance::create();
50  static_cast< uv_t* >(uv_req)->type = UV_CONNECT;
51  }
52 
53  connect(const connect&) = default;
54  connect& operator =(const connect&) = default;
55 
56  connect(connect&&) noexcept = default;
57  connect& operator =(connect&&) noexcept = default;
58 
59 private: /*functions*/
60  template< typename = void > static void connect_cb(::uv_connect_t*, int);
61 
62 public: /*interface*/
63  on_request_t& on_request() const noexcept { return instance::from(uv_req)->request_cb_storage.value(); }
64 
65  /*! \brief The stream which this connect request has been running on. */
66  stream handle() const noexcept { return stream(static_cast< uv_t* >(uv_req)->handle); }
67 
68  /*! \brief Run the request for `uv::tcp` stream.
69  \sa libuv API documentation: [`uv_tcp_connect()`](http://docs.libuv.org/en/v1.x/tcp.html#c.uv_tcp_connect). */
70  template<
71  typename _T_,
73  >
74  int run(tcp &_tcp, const _T_ &_sockaddr)
75  {
76  tcp::instance::from(_tcp.uv_handle)->ref();
77  instance::from(uv_req)->ref();
78 
79  uv_status(0);
80  auto uv_ret = ::uv_tcp_connect(
81  static_cast< uv_t* >(uv_req), static_cast< tcp::uv_t* >(_tcp),
82  reinterpret_cast< const ::sockaddr* >(&_sockaddr),
83  connect_cb
84  );
85  if (uv_ret < 0)
86  {
87  uv_status(uv_ret);
88  tcp::instance::from(_tcp.uv_handle)->unref();
89  instance::from(uv_req)->unref();
90  }
91 
92  return uv_ret;
93  }
94  /*! \brief Run the request for `uv::pipe` stream.
95  \sa libuv API documentation: [`uv_pipe_connect()`](http://docs.libuv.org/en/v1.x/pipe.html#c.uv_pipe_connect). */
96  void run(pipe &_pipe, const char *_name)
97  {
98  pipe::instance::from(_pipe.uv_handle)->ref();
99  instance::from(uv_req)->ref();
100  ::uv_pipe_connect(static_cast< uv_t* >(uv_req), static_cast< pipe::uv_t* >(_pipe), _name, connect_cb);
101  }
102 
103 public: /*conversion operators*/
104  explicit operator const uv_t*() const noexcept { return static_cast< const uv_t* >(uv_req); }
105  explicit operator uv_t*() noexcept { return static_cast< uv_t* >(uv_req); }
106 };
107 
108 template< typename >
109 void connect::connect_cb(::uv_connect_t *_uv_req, int _status)
110 {
111  auto instance_ptr = instance::from(_uv_req);
112  instance_ptr->uv_error = _status;
113 
114  ref_guard< stream::instance > unref_handle(*stream::instance::from(_uv_req->handle), adopt_ref);
115  ref_guard< instance > unref_req(*instance_ptr, adopt_ref);
116 
117  auto &connect_cb = instance_ptr->request_cb_storage.value();
118  if (connect_cb) connect_cb(connect(_uv_req));
119 }
120 
121 
122 
123 /*! \ingroup doxy_group__request
124  \brief Stream write request type.
125  \sa libuv API documentation: [`uv_stream_t` — Stream handle](http://docs.libuv.org/en/v1.x/stream.html#uv-stream-t-stream-handle). */
126 class write : public request
127 {
128  //! \cond
129  friend class request::instance< write >;
130  friend class output;
131  //! \endcond
132 
133 public: /*types*/
134  using uv_t = ::uv_write_t;
135  using on_request_t = std::function< void(write _request, buffer _buffer) >;
136  /*!< \brief The function type of the callback called after data was written on a stream.
137  \sa libuv API documentation: [`uv_write_cb`](http://docs.libuv.org/en/v1.x/stream.html#c.uv_write_cb). */
138 
139 protected: /*types*/
140  //! \cond internals
141  //! \addtogroup doxy_group__internals
142  //! \{
143  struct properties : request::properties
144  {
145  buffer::uv_t *uv_buf = nullptr;
146  };
147  //! \}
148  //! \endcond
149 
150 private: /*types*/
151  using instance = request::instance< write >;
152 
153 protected: /*constructors*/
154  //! \cond
155  explicit write(uv_t *_uv_req) : request(reinterpret_cast< request::uv_t* >(_uv_req)) {}
156  //! \endcond
157 
158 public: /*constructors*/
159  ~write() = default;
160  write()
161  {
162  uv_req = instance::create();
163  static_cast< uv_t* >(uv_req)->type = UV_WRITE;
164  }
165 
166  write(const write&) = default;
167  write& operator =(const write&) = default;
168 
169  write(write&&) noexcept = default;
170  write& operator =(write&&) noexcept = default;
171 
172 private: /*functions*/
173  template< typename = void > static void write_cb(::uv_write_t*, int);
174  template< typename = void > static void write2_cb(::uv_write_t*, int);
175 
176 public: /*interface*/
177  on_request_t& on_request() const noexcept { return instance::from(uv_req)->request_cb_storage.value(); }
178 
179  /*! \brief The stream which this write request has been running on. */
180  stream handle() const noexcept { return stream(static_cast< uv_t* >(uv_req)->handle); }
181  /*! \brief The handle of the stream to be sent over a pipe using this write request. */
182  stream send_handle() const noexcept { return stream(static_cast< uv_t* >(uv_req)->send_handle); }
183 
184  /*! \brief Run the request.
185  \sa libuv API documentation: [`uv_write()`](http://docs.libuv.org/en/v1.x/stream.html#c.uv_write). */
186  int run(stream &_stream, const buffer &_buf)
187  {
188  auto instance_ptr = instance::from(uv_req);
189 
190  stream::instance::from(_stream.uv_handle)->ref();
191  buffer::instance::from(_buf.uv_buf)->ref();
192  instance_ptr->ref();
193 
194  // instance_ptr->properties() = { _buf.uv_buf };
195  {
196  auto &properties = instance_ptr->properties();
197  properties.uv_buf = _buf.uv_buf;
198  }
199 
200  uv_status(0);
201  auto uv_ret = ::uv_write(
202  static_cast< uv_t* >(uv_req), static_cast< stream::uv_t* >(_stream),
203  static_cast< const buffer::uv_t* >(_buf), _buf.count(),
204  write_cb
205  );
206  if (uv_ret < 0)
207  {
208  uv_status(uv_ret);
209  stream::instance::from(_stream.uv_handle)->unref();
210  buffer::instance::from(_buf.uv_buf)->unref();
211  instance_ptr->unref();
212  }
213 
214  return uv_ret;
215  }
216  /*! \brief The overload for sending handles over a pipe.
217  \sa libuv API documentation: [`uv_write2()`](http://docs.libuv.org/en/v1.x/stream.html#c.uv_write2). */
218  int run(pipe &_pipe, const buffer &_buf, stream &_send_handle)
219  {
220  auto instance_ptr = instance::from(uv_req);
221 
222  pipe::instance::from(_pipe.uv_handle)->ref();
223  buffer::instance::from(_buf.uv_buf)->ref();
224  stream::instance::from(_send_handle.uv_handle)->ref();
225  instance_ptr->ref();
226 
227  // instance_ptr->properties() = { _buf.uv_buf };
228  {
229  auto &properties = instance_ptr->properties();
230  properties.uv_buf = _buf.uv_buf;
231  }
232 
233  uv_status(0);
234  auto uv_ret = ::uv_write2(
235  static_cast< uv_t* >(uv_req), static_cast< stream::uv_t* >(_pipe),
236  static_cast< const buffer::uv_t* >(_buf), _buf.count(),
237  static_cast< stream::uv_t* >(_send_handle),
238  write2_cb
239  );
240  if (uv_ret < 0)
241  {
242  uv_status(uv_ret);
243  pipe::instance::from(_pipe.uv_handle)->unref();
244  buffer::instance::from(_buf.uv_buf)->unref();
245  stream::instance::from(_send_handle.uv_handle)->unref();
246  instance_ptr->unref();
247  }
248 
249  return uv_ret;
250  }
251 
252  /*! \details The wrapper for a corresponding libuv function.
253  \note It tries to execute and complete immediately and does not call the request callback.
254  \sa libuv API documentation: [`uv_try_write()`](http://docs.libuv.org/en/v1.x/stream.html#c.uv_try_write). */
255  int try_write(stream &_stream, const buffer &_buf)
256  {
257  return uv_status(
258  ::uv_try_write(static_cast< stream::uv_t* >(_stream), static_cast< const buffer::uv_t* >(_buf), _buf.count())
259  );
260  }
261 
262 public: /*conversion operators*/
263  explicit operator const uv_t*() const noexcept { return static_cast< const uv_t* >(uv_req); }
264  explicit operator uv_t*() noexcept { return static_cast< uv_t* >(uv_req); }
265 };
266 
267 template< typename >
268 void write::write_cb(::uv_write_t *_uv_req, int _status)
269 {
270  auto instance_ptr = instance::from(_uv_req);
271  instance_ptr->uv_error = _status;
272 
273  ref_guard< stream::instance > unref_handle(*stream::instance::from(_uv_req->handle), adopt_ref);
274  ref_guard< instance > unref_req(*instance_ptr, adopt_ref);
275 
276  auto &write_cb = instance_ptr->request_cb_storage.value();
277  if (write_cb)
278  write_cb(write(_uv_req), buffer(instance_ptr->properties().uv_buf, adopt_ref));
279  else
280  buffer::instance::from(instance_ptr->properties().uv_buf)->unref();
281 }
282 template< typename >
283 void write::write2_cb(::uv_write_t *_uv_req, int _status)
284 {
285  ref_guard< stream::instance > unref_send_handle(*stream::instance::from(_uv_req->send_handle), adopt_ref);
286  write_cb(_uv_req, _status);
287 }
288 
289 
290 
291 /*! \ingroup doxy_group__request
292  \brief Stream shutdown request type.
293  \sa libuv API documentation: [`uv_stream_t` — Stream handle](http://docs.libuv.org/en/v1.x/stream.html#uv-stream-t-stream-handle). */
294 class shutdown : public request
295 {
296  //! \cond
297  friend class request::instance< shutdown >;
298  //! \endcond
299 
300 public: /*types*/
301  using uv_t = ::uv_shutdown_t;
302  using on_request_t = std::function< void(shutdown _request) >;
303  /*!< \brief The function type of the callback called after shutdown is done.
304  \sa libuv API documentation: [`uv_shutdown_cb`](http://docs.libuv.org/en/v1.x/stream.html#c.uv_shutdown_cb). */
305 
306 private: /*types*/
307  using instance = request::instance< shutdown >;
308 
309 protected: /*constructors*/
310  //! \cond
311  explicit shutdown(uv_t *_uv_req) : request(reinterpret_cast< request::uv_t* >(_uv_req)) {}
312  //! \endcond
313 
314 public: /*constructors*/
315  ~shutdown() = default;
316  shutdown()
317  {
318  uv_req = instance::create();
319  static_cast< uv_t* >(uv_req)->type = UV_SHUTDOWN;
320  }
321 
322  shutdown(const shutdown&) = default;
323  shutdown& operator =(const shutdown&) = default;
324 
325  shutdown(shutdown&&) noexcept = default;
326  shutdown& operator =(shutdown&&) noexcept = default;
327 
328 private: /*functions*/
329  template< typename = void > static void shutdown_cb(::uv_shutdown_t*, int);
330 
331 public: /*interface*/
332  on_request_t& on_request() const noexcept { return instance::from(uv_req)->request_cb_storage.value(); }
333 
334  /*! \brief The stream which this shutdown request has been running on. */
335  stream handle() const noexcept { return stream(static_cast< uv_t* >(uv_req)->handle); }
336 
337  /*! \brief Run the request. */
338  int run(stream &_stream)
339  {
340  stream::instance::from(_stream.uv_handle)->ref();
341  instance::from(uv_req)->ref();
342 
343  uv_status(0);
344  auto uv_ret = ::uv_shutdown(static_cast< uv_t* >(uv_req), static_cast< stream::uv_t* >(_stream), shutdown_cb);
345  if (uv_ret < 0)
346  {
347  uv_status(uv_ret);
348  stream::instance::from(_stream.uv_handle)->unref();
349  instance::from(uv_req)->unref();
350  }
351 
352  return uv_ret;
353  }
354 
355 public: /*conversion operators*/
356  explicit operator const uv_t*() const noexcept { return static_cast< const uv_t* >(uv_req); }
357  explicit operator uv_t*() noexcept { return static_cast< uv_t* >(uv_req); }
358 };
359 
360 template< typename >
361 void shutdown::shutdown_cb(::uv_shutdown_t *_uv_req, int _status)
362 {
363  auto instance_ptr = instance::from(_uv_req);
364  instance_ptr->uv_error = _status;
365 
366  ref_guard< stream::instance > unref_handle(*stream::instance::from(_uv_req->handle), adopt_ref);
367  ref_guard< instance > unref_req(*instance_ptr, adopt_ref);
368 
369  auto &shutdown_cb = instance_ptr->request_cb_storage.value();
370  if (shutdown_cb) shutdown_cb(shutdown(_uv_req));
371 }
372 
373 
374 }
375 
376 
377 #endif
Namespace for all uvcc definitions.
Definition: buffer.hpp:17
operator bool() const noexcept
Equivalent to (base() != nullptr).
Definition: buffer.hpp:248
Stream handle.
The base class for the libuv requests.
Stream connect request type.
int run(stream &_stream, const buffer &_buf)
Run the request.
int run(stream &_stream)
Run the request.
int run(pipe &_pipe, const buffer &_buf, stream &_send_handle)
The overload for sending handles over a pipe.
Stream shutdown request type.
int try_write(stream &_stream, const buffer &_buf)
void run(pipe &_pipe, const char *_name)
Run the request for uv::pipe stream.
int run(tcp &_tcp, const _T_ &_sockaddr)
Run the request for uv::tcp stream.
stream handle() const noexcept
The stream which this shutdown request has been running on.
Stream write request type.
A scoped reference counting guard.
Definition: utility.hpp:280
Pipe handle.
stream send_handle() const noexcept
The handle of the stream to be sent over a pipe using this write request.
TCP handle.
stream handle() const noexcept
The stream which this connect request has been running on.
stream handle() const noexcept
The stream which this write request has been running on.