uvcc
libuv C++ bindings
request-io.hpp
1 
2 #ifndef UVCC_REQUEST_IO__HPP
3 #define UVCC_REQUEST_IO__HPP
4 
5 #include "uvcc/utility.hpp"
6 #include "uvcc/request-base.hpp"
7 #include "uvcc/handle-io.hpp"
8 #include "uvcc/request-fs.hpp"
9 #include "uvcc/request-stream.hpp"
10 #include "uvcc/request-udp.hpp"
11 #include "uvcc/buffer.hpp"
12 
13 #include <cstring> // memset()
14 #include <uv.h>
15 
16 #include <functional> // function
17 
18 
19 namespace uv
20 {
21 
22 
23 /*! \ingroup doxy_group__request
24  \brief Generic write/send request type for I/O endpoints (files, TCP/UDP sockets, pipes, TTYs).
25  \details Virtually it appears to be a one of the request:
26  - `uv::fs::write`
27  - `uv::write`
28  - `uv::udp_send`
29  .
30  depending on the actual type of the `io` argument passed to the `run()` member function. */
31 class output : public request
32 {
33  //! \cond
34  friend class request::instance< output >;
35  //! \endcond
36 
37 public: /*types*/
38  using uv_t = union {
39  fs::write::uv_t uv_file_write_req;
40  write::uv_t uv_stream_write_req;
41  udp_send::uv_t uv_udp_send_req;
42  };
43  using on_request_t = std::function< void(output _request, buffer _buffer) >;
44  /*!< \brief The function type of the callback called after data was written/sent to I/O endpoint.
45  \sa `fs::write::on_request_t`,\n `write::on_request_t`,\n `udp_send::on_request_t`. */
46 
47 protected: /*types*/
48  //! \cond internals
49  //! \addtogroup doxy_group__internals
50  //! \{
51  struct properties // it shall not be derived from `request::properties`
52  {
53  union request_properties
54  {
55  fs::write::properties file_write_properties;
56  write::properties stream_write_properties;
57  udp_send::properties udp_send_properties;
58 
59  ~request_properties() {}
60  request_properties() { std::memset(this, 0, sizeof(*this)); }
61  };
62 
63  request_properties property_storage; // it must be the first field to align with property storage of the actual request type
64  ::uv_req_t *uv_req = nullptr;
65  int64_t offset = 0;
66 
67  ~properties()
68  {
69  if (uv_req) switch (uv_req->type)
70  {
71  case UV_WRITE:
72  property_storage.stream_write_properties.~properties();
73  break;
74  case UV_UDP_SEND:
75  property_storage.udp_send_properties.~properties();
76  break;
77  case UV_FS:
78  property_storage.file_write_properties.~properties();
79  break;
80  default:
81  break;
82  }
83  }
84  };
85  //! \}
86  //! \endcond
87 
88 private: /*types*/
89  using instance = request::instance< output >;
90 
91 protected: /*constructors*/
92  //! \cond
93  explicit output(uv_t *_uv_req) : request(reinterpret_cast< request::uv_t* >(_uv_req)) {}
94  //! \endcond
95 
96 public: /*constructors*/
97  ~output() = default;
98  output()
99  {
100  uv_req = instance::create();
101  static_cast< ::uv_req_t* >(uv_req)->type = UV_REQ;
102  instance::from(uv_req)->properties().uv_req = static_cast< ::uv_req_t* >(uv_req);
103  }
104 
105  output(const output&) = default;
106  output& operator =(const output&) = default;
107 
108  output(output&&) noexcept = default;
109  output& operator =(output&&) noexcept = default;
110 
111 public: /*interface*/
112  on_request_t& on_request() const noexcept { return instance::from(uv_req)->request_cb_storage.value(); }
113 
114  /*! \brief The I/O endpoint handle where this output request has been taking place. */
115  io handle() const noexcept
116  {
117  switch (static_cast< ::uv_req_t* >(uv_req)->type)
118  {
119  case UV_WRITE:
120  return reinterpret_cast< const write* >(this)->handle();
121  case UV_UDP_SEND:
122  return reinterpret_cast< const udp_send* >(this)->handle();
123  case UV_FS:
124  return reinterpret_cast< const fs::write* >(this)->handle();
125  default:
126  io ret;
127  ret.uv_status(UV_EBADF);
128  return ret;
129  }
130  }
131 
132  /*! \brief The offset value specified for `run()` call by which this output request has been set going. */
133  int64_t offset() const noexcept { return instance::from(uv_req)->properties().offset; }
134 
135  /*! \brief Run the request with interpreting arguments as additional parameters for actual write/send
136  request performed depending on what I/O endpoint the `_io` argument actually represents.
137  \details
138  The `output` request instance is static-casted to the corresponding write/send request for that endpoint and
139  the following actual call is performed:
140  `_io` endpoint type | Actual output function
141  :--------------------------------|:-----------------------
142  `uv::file` | `fs::write::run(static_cast< uv::file& >(_io), _buf, _offset)`
143  one of the `uv::stream` subtype | `write::run(static_cast< uv::stream& >(_io), _buf)`
144  `uv::udp` | `udp_send::run(static_cast< uv::udp& >(_io), _buf, *static_cast< const udp::io_info* >(_info)->peer)`
145 
146  \note Employing this function can be practical within a `io::on_read_t` callback <em>when the type of the I/O
147  endpoint that the output request is going to be run on is of the same type, as the one the `io::on_read_t` callback
148  is called for</em> because the `_offset` and `_info` arguments are interpreted in the same way as when they have been
149  passed into the `io::on_read_t` callback but for determining supplemental parameters for output operation.
150  In any case the `output` request can be static-casted to the desired _request_ type corresponding to the output
151  I/O endpoint and then the one of the _request_`::run()` available functions can be used. */
152  int run(io &_io, const buffer &_buf, int64_t _offset = -1, void *_info = nullptr)
153  {
154  switch (_io.type())
155  {
156  case UV_NAMED_PIPE:
157  case UV_TCP:
158  case UV_TTY:
159  static_cast< write::uv_t* >(uv_req)->type = UV_WRITE;
160  instance::from(uv_req)->properties().offset = _offset;
161  return reinterpret_cast< write* >(this)->run(static_cast< stream& >(_io), _buf);
162  case UV_UDP:
163  static_cast< udp_send::uv_t* >(uv_req)->type = UV_UDP_SEND;
164  instance::from(uv_req)->properties().offset = _offset;
165  return _info ?
166  reinterpret_cast< udp_send* >(this)->run(
167  static_cast< udp& >(_io), _buf,
168  *static_cast< const udp::io_info* >(_info)->peer
169  )
170  :
171  uv_status(UV_EINVAL);
172  case UV_FILE:
173  static_cast< fs::uv_t* >(uv_req)->type = UV_FS;
174  static_cast< fs::uv_t* >(uv_req)->fs_type = UV_FS_WRITE;
175  instance::from(uv_req)->properties().offset = _offset;
176  return reinterpret_cast< fs::write* >(this)->run(static_cast< file& >(_io), _buf, _offset);
177  default:
178  return uv_status(UV_EBADF);
179  }
180  }
181 
182  /*! \brief Same as `run()`, but won’t queue an output request if it can’t be completed immediately.
183  \details Depending on the actual run-time type of the `_io` argument, the function appears to be an alias
184  to the one of the following functon:
185  - `fs::write::try_write()`, or
186  - `write::try_write()`, or
187  - `udp_send::try_send()`.
188  . */
189  int try_output(io &_io, const buffer &_buf, int64_t _offset = -1, void *_info = nullptr)
190  {
191  switch (_io.type())
192  {
193  case UV_NAMED_PIPE:
194  case UV_TCP:
195  case UV_TTY:
196  static_cast< write::uv_t* >(uv_req)->type = UV_WRITE;
197  return reinterpret_cast< write* >(this)->try_write(static_cast< stream& >(_io), _buf);
198  case UV_UDP:
199  static_cast< udp_send::uv_t* >(uv_req)->type = UV_UDP_SEND;
200  return _info ?
201  reinterpret_cast< udp_send* >(this)->try_send(
202  static_cast< udp& >(_io), _buf,
203  *static_cast< const udp::io_info* >(_info)->peer
204  )
205  :
206  uv_status(UV_EINVAL);
207  case UV_FILE:
208  static_cast< fs::uv_t* >(uv_req)->type = UV_FS;
209  static_cast< fs::uv_t* >(uv_req)->fs_type = UV_FS_WRITE;
210  return reinterpret_cast< fs::write* >(this)->try_write(static_cast< file& >(_io), _buf, _offset);
211  default:
212  return uv_status(UV_EBADF);
213  }
214  }
215 
216 public: /*conversion operators*/
217  explicit operator const fs::write&() const noexcept { return *reinterpret_cast< const fs::write* >(this); }
218  explicit operator fs::write&() noexcept { return *reinterpret_cast< fs::write* >(this); }
219 
220  explicit operator const write&() const noexcept { return *reinterpret_cast< const write* >(this); }
221  explicit operator write&() noexcept { return *reinterpret_cast< write* >(this); }
222 
223  explicit operator const udp_send&() const noexcept { return *reinterpret_cast< const udp_send* >(this); }
224  explicit operator udp_send&() noexcept { return *reinterpret_cast< udp_send* >(this); }
225 };
226 
227 
228 }
229 
230 
231 #endif
Namespace for all uvcc definitions.
Definition: buffer.hpp:17
operator bool() const noexcept
Equivalent to (base() != nullptr).
Definition: buffer.hpp:248
Stream handle.
UDP send request type.
Definition: request-udp.hpp:24
The base class for the libuv requests.
The open file handle.
Definition: handle-fs.hpp:29
file handle() const noexcept
The file which this write request has been running on.
Definition: request-fs.hpp:471
int run(stream &_stream, const buffer &_buf)
Run the request.
::uv_handle_type type() const noexcept
The tag indicating the libuv type of the handle.
udp handle() const noexcept
The UDP handle where this send request has been taking place.
Definition: request-udp.hpp:78
The base calss for filesystem requests.
Definition: request-fs.hpp:40
int try_write(stream &_stream, const buffer &_buf)
int try_output(io &_io, const buffer &_buf, int64_t _offset=-1, void *_info=nullptr)
Same as run(), but won’t queue an output request if it can’t be completed immediately.
Definition: request-io.hpp:189
Stream write request type.
int run(io &_io, const buffer &_buf, int64_t _offset=-1, void *_info=nullptr)
Run the request with interpreting arguments as additional parameters for actual write/send request pe...
Definition: request-io.hpp:152
int try_write(file &_file, const buffer &_buf, int64_t _offset)
Try to execute the request synchronously if it can be completed immediately...
Definition: request-fs.hpp:561
The base class for handles representing I/O endpoints: a file, TCP/UDP socket, pipe, TTY.
Definition: handle-io.hpp:25
Write data to a file.
Definition: request-fs.hpp:416
int run(file &_file, const buffer &_buf, int64_t _offset)
Run the request. Write data to the _file from the buffers described by _buf object.
Definition: request-fs.hpp:483
io handle() const noexcept
The I/O endpoint handle where this output request has been taking place.
Definition: request-io.hpp:115
int64_t offset() const noexcept
The offset value specified for run() call by which this output request has been set going...
Definition: request-io.hpp:133
Generic write/send request type for I/O endpoints (files, TCP/UDP sockets, pipes, TTYs)...
Definition: request-io.hpp:31
stream handle() const noexcept
The stream which this write request has been running on.