This commit is contained in:
Michele Caini 2023-03-10 10:52:03 +01:00 committed by GitHub
parent 3636701fc2
commit 70697f4ae9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
90 changed files with 4083 additions and 4938 deletions

View File

@ -3,14 +3,14 @@
#include <uvw.hpp> #include <uvw.hpp>
#include <memory> #include <memory>
void listen(uvw::Loop &loop) { void listen(uvw::loop &loop) {
std::shared_ptr<uvw::TCPHandle> tcp = loop.resource<uvw::TCPHandle>(); std::shared_ptr<uvw::tcp_handle> tcp = loop.resource<uvw::tcp_handle>();
tcp->once<uvw::ListenEvent>([](const uvw::ListenEvent &, uvw::TCPHandle &srv) { tcp->on<uvw::listen_event>([](const uvw::listen_event &, uvw::tcp_handle &srv) {
std::shared_ptr<uvw::TCPHandle> client = srv.loop().resource<uvw::TCPHandle>(); std::shared_ptr<uvw::tcp_handle> client = srv.loop().resource<uvw::tcp_handle>();
client->on<uvw::CloseEvent>([ptr = srv.shared_from_this()](const uvw::CloseEvent &, uvw::TCPHandle &) { ptr->close(); }); client->on<uvw::close_event>([ptr = srv.shared_from_this()](const uvw::close_event &, uvw::tcp_handle &) { ptr->close(); });
client->on<uvw::EndEvent>([](const uvw::EndEvent &, uvw::TCPHandle &client) { client.close(); }); client->on<uvw::end_event>([](const uvw::end_event &, uvw::tcp_handle &client) { client.close(); });
srv.accept(*client); srv.accept(*client);
client->read(); client->read();
@ -20,12 +20,12 @@ void listen(uvw::Loop &loop) {
tcp->listen(); tcp->listen();
} }
void conn(uvw::Loop &loop) { void conn(uvw::loop &loop) {
auto tcp = loop.resource<uvw::TCPHandle>(); auto tcp = loop.resource<uvw::tcp_handle>();
tcp->on<uvw::ErrorEvent>([](const uvw::ErrorEvent &, uvw::TCPHandle &) { /* handle errors */ }); tcp->on<uvw::error_event>([](const uvw::error_event &, uvw::tcp_handle &) { /* handle errors */ });
tcp->once<uvw::ConnectEvent>([](const uvw::ConnectEvent &, uvw::TCPHandle &tcp) { tcp->on<uvw::connect_event>([](const uvw::connect_event &, uvw::tcp_handle &tcp) {
auto dataWrite = std::unique_ptr<char[]>(new char[2]{ 'b', 'c' }); auto dataWrite = std::unique_ptr<char[]>(new char[2]{ 'b', 'c' });
tcp.write(std::move(dataWrite), 2); tcp.write(std::move(dataWrite), 2);
tcp.close(); tcp.close();
@ -36,7 +36,7 @@ void conn(uvw::Loop &loop) {
int main() { int main() {
std::cout << "Getting UVW loop ...\n"; std::cout << "Getting UVW loop ...\n";
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
std::cout << "Staring UVW listener ...\n"; std::cout << "Staring UVW listener ...\n";
listen(*loop); listen(*loop);
std::cout << "Connecting ...\n"; std::cout << "Connecting ...\n";

30
.github/workflows/sanitizer.yml vendored Normal file
View File

@ -0,0 +1,30 @@
name: sanitizer
on: [push, pull_request]
jobs:
clang:
timeout-minutes: 15
strategy:
matrix:
compiler: [clang++]
sanitizer: [ASAN, UBSAN]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Compile tests
working-directory: build
env:
CXX: ${{ matrix.compiler }}
run: |
cmake ${{ matrix.mode }} -DBUILD_TESTING=ON -Dlibuv_buildtests=OFF -DUSE_${{ matrix.sanitizer }}=ON ..
make -j2
- name: Run tests
working-directory: build
env:
CTEST_OUTPUT_ON_FAILURE: 1
run: ctest --timeout 5 -C Debug -j2

View File

@ -15,9 +15,9 @@ endif()
# #
# Project configuration # Project configuration
# #
set(UVW_VERSION_MAJOR 2) set(UVW_VERSION_MAJOR 3)
set(UVW_VERSION_MINOR 12) set(UVW_VERSION_MINOR 0)
set(UVW_VERSION_PATCH 1) set(UVW_VERSION_PATCH 0)
project( project(
uvw uvw
@ -263,4 +263,5 @@ add_custom_target(
AUTHORS AUTHORS
LICENSE LICENSE
README.md README.md
TODO
) )

129
README.md
View File

@ -28,9 +28,8 @@ and still support me today.
[`libuv`](https://github.com/libuv/libuv) written in modern C++.<br/> [`libuv`](https://github.com/libuv/libuv) written in modern C++.<br/>
Now it's finally available also as a compilable static library. Now it's finally available also as a compilable static library.
The basic idea is to hide completely the *C-ish* interface of `libuv` behind a The basic idea is to wrap the *C-ish* interface of `libuv` behind a graceful C++
graceful C++ API. Currently, no `uv_*_t` data structure is actually exposed by API.<br/>
the library.<br/>
Note that `uvw` stays true to the API of `libuv` and it doesn't add anything to Note that `uvw` stays true to the API of `libuv` and it doesn't add anything to
its interface. For the same reasons, users of the library must follow the same its interface. For the same reasons, users of the library must follow the same
rules which are used with `libuv`.<br/> rules which are used with `libuv`.<br/>
@ -43,14 +42,14 @@ closed once it is no longer in use.
#include <uvw.hpp> #include <uvw.hpp>
#include <memory> #include <memory>
void listen(uvw::Loop &loop) { void listen(uvw::loop &loop) {
std::shared_ptr<uvw::TCPHandle> tcp = loop.resource<uvw::TCPHandle>(); std::shared_ptr<uvw::tcp_handle> tcp = loop.resource<uvw::tcp_handle>();
tcp->once<uvw::ListenEvent>([](const uvw::ListenEvent &, uvw::TCPHandle &srv) { tcp->once<uvw::listen_event>([](const uvw::listen_event &, uvw::tcp_handle &srv) {
std::shared_ptr<uvw::TCPHandle> client = srv.loop().resource<uvw::TCPHandle>(); std::shared_ptr<uvw::tcp_handle> client = srv.parent().resource<uvw::tcp_handle>();
client->on<uvw::CloseEvent>([ptr = srv.shared_from_this()](const uvw::CloseEvent &, uvw::TCPHandle &) { ptr->close(); }); client->on<uvw::close_event>([ptr = srv.shared_from_this()](const uvw::close_event &, uvw::tcp_handle &) { ptr->close(); });
client->on<uvw::EndEvent>([](const uvw::EndEvent &, uvw::TCPHandle &client) { client.close(); }); client->on<uvw::end_event>([](const uvw::end_event &, uvw::tcp_handle &client) { client.close(); });
srv.accept(*client); srv.accept(*client);
client->read(); client->read();
@ -60,12 +59,12 @@ void listen(uvw::Loop &loop) {
tcp->listen(); tcp->listen();
} }
void conn(uvw::Loop &loop) { void conn(uvw::loop &loop) {
auto tcp = loop.resource<uvw::TCPHandle>(); auto tcp = loop.resource<uvw::tcp_handle>();
tcp->on<uvw::ErrorEvent>([](const uvw::ErrorEvent &, uvw::TCPHandle &) { /* handle errors */ }); tcp->on<uvw::error_event>([](const uvw::error_event &, uvw::tcp_handle &) { /* handle errors */ });
tcp->once<uvw::ConnectEvent>([](const uvw::ConnectEvent &, uvw::TCPHandle &tcp) { tcp->once<uvw::connect_event>([](const uvw::connect_event &, uvw::tcp_handle &tcp) {
auto dataWrite = std::unique_ptr<char[]>(new char[2]{ 'b', 'c' }); auto dataWrite = std::unique_ptr<char[]>(new char[2]{ 'b', 'c' });
tcp.write(std::move(dataWrite), 2); tcp.write(std::move(dataWrite), 2);
tcp.close(); tcp.close();
@ -75,7 +74,7 @@ void conn(uvw::Loop &loop) {
} }
int main() { int main() {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
listen(*loop); listen(*loop);
conn(*loop); conn(*loop);
loop->run(); loop->run();
@ -229,7 +228,7 @@ For more details, please refer to the
## Handles ## Handles
Initialization is usually performed under the hood and can be even passed over, Initialization is usually performed under the hood and can be even passed over,
as far as handles are created using the `Loop::resource` member function.<br/> as far as handles are created using the `loop::resource` member function.<br/>
On the other side, handles keep themselves alive until one explicitly closes On the other side, handles keep themselves alive until one explicitly closes
them. Because of that, memory usage will grow if users simply forget about a them. Because of that, memory usage will grow if users simply forget about a
handle.<br/> handle.<br/>
@ -239,7 +238,7 @@ as calling the `close` member function on them.
## Requests ## Requests
Usually initializing a request object is not required. Anyway, the recommended Usually initializing a request object is not required. Anyway, the recommended
way to create a request is still through the `Loop::resource` member way to create a request is still through the `loop::resource` member
function.<br/> function.<br/>
Requests will keep themselves alive as long as they are bound to unfinished Requests will keep themselves alive as long as they are bound to unfinished
underlying activities. This means that users don't have to discard a underlying activities. This means that users don't have to discard a
@ -253,7 +252,7 @@ The first thing to do to use `uvw` is to create a loop. In case the default one
is enough, it's easy as doing this: is enough, it's easy as doing this:
```cpp ```cpp
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
``` ```
Note that loop objects don't require being closed explicitly, even if they offer Note that loop objects don't require being closed explicitly, even if they offer
@ -263,7 +262,7 @@ equivalent:
```cpp ```cpp
loop->run(); loop->run();
loop->run<uvw::Loop::Mode::DEFAULT>(); loop->run(uvw::loop::run_mode::DEFAULT);
``` ```
Available modes are: `DEFAULT`, `ONCE`, `NOWAIT`. Please refer to the Available modes are: `DEFAULT`, `ONCE`, `NOWAIT`. Please refer to the
@ -273,23 +272,21 @@ In order to create a resource and to bind it to the given loop, just do the
following: following:
```cpp ```cpp
auto tcp = loop->resource<uvw::TCPHandle>(); auto tcp = loop->resource<uvw::tcp_handle>();
``` ```
The line above will create and initialize a tcp handle, then a shared pointer to The line above creates and initializes a tcp handle, then a shared pointer to
that resource will be returned.<br/> that resource is returned.<br/>
Users should check if pointers have been correctly initialized: in case of Users should check if pointers have been correctly initialized: in case of
errors, they won't be.<br/> errors, they won't be.<br/>
Another way to create a resource is: It also is possible to create uninitialized resources to init later on as:
```cpp ```cpp
auto tcp = TCPHandle::create(loop); auto tcp = loop->uninitialized_resource<uvw::tcp_handle>();
tcp->init(); tcp->init();
``` ```
Pretty annoying indeed. Using a loop is the recommended approach. All resources also accept arbitrary user-data that won't be touched in any
The resources also accept arbitrary user-data that won't be touched in any
case.<br/> case.<br/>
Users can set and get them through the `data` member function as it follows: Users can set and get them through the `data` member function as it follows:
@ -311,12 +308,12 @@ Remember from the previous section that a handle will keep itself alive until
one invokes the `close` member function on it.<br/> one invokes the `close` member function on it.<br/>
To know what are the handles that are still alive and bound to a given loop, To know what are the handles that are still alive and bound to a given loop,
there exists the `walk` member function. It returns handles with their types. there exists the `walk` member function. It returns handles with their types.
Therefore, the use of `Overloaded` is recommended to be able to intercept all Therefore, the use of `overloaded` is recommended to be able to intercept all
types of interest: types of interest:
```cpp ```cpp
handle.loop().walk(uvw::Overloaded{ handle.parent().walk(uvw::overloaded{
[](uvw::TimerHandle &h){ /* application code for timers here */ }, [](uvw::timer_handle &h){ /* application code for timers here */ },
[](auto &&){ /* ignore all other types */ } [](auto &&){ /* ignore all other types */ }
}); });
``` ```
@ -332,58 +329,52 @@ No need to keep track of them.
## The event-based approach ## The event-based approach
`uvw` offers an event-based approach, so resources are small event emitters `uvw` offers an event-based approach where resources are small event emitters to
to which listeners can be attached.<br/> which listeners are attached.<br/>
Attaching a listener to a resource is the recommended way to be notified about Attaching listeners to resources is the recommended way to receive notifications
changes.<br/> about their operations.<br/>
Listeners must be callable objects of type `void(EventType &, ResourceType &)`, Listeners are callable objects of type `void(event_type &, resource_type &)`,
where: where:
* `EventType` is the type of the event for which they have been designed. * `event_type` is the type of the event for which they have been designed.
* `ResourceType` is the type of the resource that has originated the event. * `resource_type` is the type of the resource that has originated the event.
It means that the following function types are all valid: It means that the following function types are all valid:
* `void(EventType &, ResourceType &)` * `void(event_type &, resource_type &)`
* `void(const EventType &, ResourceType &)` * `void(const event_type &, resource_type &)`
* `void(EventType &, const ResourceType &)` * `void(event_type &, const resource_type &)`
* `void(const EventType &, const ResourceType &)` * `void(const event_type &, const resource_type &)`
Please note that there is no need to keep around references to the resources: Please note that there is no need to keep around references to the resources,
they will pass themselves as an argument whenever an event is published. since they pass themselves as an argument whenever an event is published.<br/>
The `on` member function is the way to go to register long-running listeners:
There exist two methods to attach a listener to a resource: ```cpp
resource.on<event_type>(listener)
```
* `resource.once<EventType>(listener)`: the listener will be automatically To know if a listener exists for a given type, the class offers a `has` function
removed after the first event of the given type. template. Similarly, the `reset` function template is be used to reset and thus
* `resource.on<EventType>(listener)`: to be used for long-running listeners. disconnect listeners, if any. A non-template version of `reset` also exists to
clear an emitter as a whole.
Both of them return an object of type `ResourceType::Connection` (as an example, Almost all the resources emit `error_event` in case of errors.<br/>
`TCPHandle::Connection`).<br/>
A connection object can be used later as an argument to the `erase` member
function of the resource to remove the listener.<br/>
There exists also the `clear` member function to drop all the listeners at once.
Note that `clear` should only be invoked on non-active handles. The handles
exploit the same event mechanism made available to users to satisfy pending
requests. Invoking `clear` on an active handle, for example with requests still
in progress, risks leading to memory leaks or unexpected behavior.
Almost all the resources emit `ErrorEvent` in case of errors.<br/>
All the other events are specific for the given resource and documented in the All the other events are specific for the given resource and documented in the
API reference. API reference.
The code below shows how to create a simple tcp server using `uvw`: The code below shows how to create a simple tcp server using `uvw`:
```cpp ```cpp
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto tcp = loop->resource<uvw::TCPHandle>(); auto tcp = loop->resource<uvw::tcp_handle>();
tcp->on<uvw::ErrorEvent>([](const uvw::ErrorEvent &, uvw::TCPHandle &) { /* something went wrong */ }); tcp->on<uvw::error_event>([](const uvw::error_event &, uvw::tcp_handle &) { /* something went wrong */ });
tcp->on<uvw::ListenEvent>([](const uvw::ListenEvent &, uvw::TCPHandle &srv) { tcp->on<uvw::listen_event>([](const uvw::listen_event &, uvw::tcp_handle &srv) {
std::shared_ptr<uvw::TCPHandle> client = srv.loop().resource<uvw::TCPHandle>(); std::shared_ptr<uvw::tcp_handle> client = srv.parent().resource<uvw::tcp_handle>();
client->once<uvw::EndEvent>([](const uvw::EndEvent &, uvw::TCPHandle &client) { client.close(); }); client->on<uvw::end_event>([](const uvw::end_event &, uvw::tcp_handle &client) { client.close(); });
client->on<uvw::DataEvent>([](const uvw::DataEvent &, uvw::TCPHandle &) { /* data received */ }); client->on<uvw::data_event>([](const uvw::data_event &, uvw::tcp_handle &) { /* data received */ });
srv.accept(*client); srv.accept(*client);
client->read(); client->read();
}); });
@ -392,11 +383,7 @@ tcp->bind("127.0.0.1", 4242);
tcp->listen(); tcp->listen();
``` ```
Note also that `uvw::TCPHandle` already supports _IPv6_ out-of-the-box. The Note also that `uvw::tcp_handle` already supports _IPv6_ out-of-the-box.<br/>
statement above is equivalent to `tcp->bind<uvw::IPv4>("127.0.0.1", 4242)`.<br/>
It's sufficient to explicitly specify `uvw::IPv6` as the underlying protocol to
use it.
The API reference is the recommended documentation for further details about The API reference is the recommended documentation for further details about
resources and their methods. resources and their methods.
@ -414,8 +401,8 @@ things.
That being said, _going raw_ is a matter of using the `raw` member functions: That being said, _going raw_ is a matter of using the `raw` member functions:
```cpp ```cpp
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto tcp = loop->resource<uvw::TCPHandle>(); auto tcp = loop->resource<uvw::tcp_handle>();
uv_loop_t *raw = loop->raw(); uv_loop_t *raw = loop->raw();
uv_tcp_t *handle = tcp->raw(); uv_tcp_t *handle = tcp->raw();

5
TODO Normal file
View File

@ -0,0 +1,5 @@
* do not send error events when the return value is enough (still wip)
* also cleanup error event mentions in the doc
* Make all tests pass on all platforms
* add iwyu and clean up everything
* Allocator support

View File

@ -3,6 +3,7 @@
#include "uvw/config.h" #include "uvw/config.h"
#include "uvw/dns.h" #include "uvw/dns.h"
#include "uvw/emitter.h" #include "uvw/emitter.h"
#include "uvw/enum.hpp"
#include "uvw/fs.h" #include "uvw/fs.h"
#include "uvw/fs_event.h" #include "uvw/fs_event.h"
#include "uvw/fs_poll.h" #include "uvw/fs_poll.h"
@ -22,6 +23,6 @@
#include "uvw/timer.h" #include "uvw/timer.h"
#include "uvw/tty.h" #include "uvw/tty.h"
#include "uvw/udp.h" #include "uvw/udp.h"
#include "uvw/underlying_type.hpp"
#include "uvw/util.h" #include "uvw/util.h"
#include "uvw/uv_type.hpp"
#include "uvw/work.h" #include "uvw/work.h"

View File

@ -6,17 +6,17 @@
namespace uvw { namespace uvw {
UVW_INLINE void AsyncHandle::sendCallback(uv_async_t *handle) { UVW_INLINE void async_handle::send_callback(uv_async_t *hndl) {
AsyncHandle &async = *(static_cast<AsyncHandle *>(handle->data)); async_handle &async = *(static_cast<async_handle *>(hndl->data));
async.publish(AsyncEvent{}); async.publish(async_event{});
} }
UVW_INLINE bool AsyncHandle::init() { UVW_INLINE int async_handle::init() {
return initialize(&uv_async_init, &sendCallback); return leak_if(uv_async_init(parent().raw(), raw(), &send_callback));
} }
UVW_INLINE void AsyncHandle::send() { UVW_INLINE int async_handle::send() {
invoke(&uv_async_send, get()); return uv_async_send(raw());
} }
} // namespace uvw } // namespace uvw

View File

@ -7,26 +7,22 @@
namespace uvw { namespace uvw {
/** /*! @brief Async event. */
* @brief AsyncEvent event. struct async_event {};
*
* It will be emitted by AsyncHandle according with its functionalities.
*/
struct AsyncEvent {};
/** /**
* @brief The AsyncHandle handle. * @brief The async handle.
* *
* Async handles allow the user to _wakeup_ the event loop and get an event * Async handles allow the user to _wakeup_ the event loop and get an event
* emitted from another thread. * emitted from another thread.
* *
* To create an `AsyncHandle` through a `Loop`, no arguments are required. * To create an `async_handle` through a `loop`, no arguments are required.
*/ */
class AsyncHandle final: public Handle<AsyncHandle, uv_async_t> { class async_handle final: public handle<async_handle, uv_async_t, async_event> {
static void sendCallback(uv_async_t *handle); static void send_callback(uv_async_t *hndl);
public: public:
using Handle::Handle; using handle::handle;
/** /**
* @brief Initializes the handle. * @brief Initializes the handle.
@ -34,21 +30,23 @@ public:
* Unlike other handle initialization functions, it immediately starts the * Unlike other handle initialization functions, it immediately starts the
* handle. * handle.
* *
* @return True in case of success, false otherwise. * @return Underlying return value.
*/ */
bool init(); int init() final;
/** /**
* @brief Wakeups the event loop and emits the AsyncEvent event. * @brief Wakeups the event loop and emits the async event.
* *
* Its safe to call this function from any thread.<br/> * Its safe to call this function from any thread.<br/>
* An AsyncEvent event will be emitted on the loop thread. * An async event is emitted on the loop thread.
* *
* See the official * See the official
* [documentation](http://docs.libuv.org/en/v1.x/async.html#c.uv_async_send) * [documentation](http://docs.libuv.org/en/v1.x/async.html#c.uv_async_send)
* for further details. * for further details.
*
* @return Underlying return value.
*/ */
void send(); int send();
}; };
} // namespace uvw } // namespace uvw

View File

@ -6,21 +6,21 @@
namespace uvw { namespace uvw {
UVW_INLINE void CheckHandle::startCallback(uv_check_t *handle) { UVW_INLINE void check_handle::start_callback(uv_check_t *hndl) {
CheckHandle &check = *(static_cast<CheckHandle *>(handle->data)); check_handle &check = *(static_cast<check_handle *>(hndl->data));
check.publish(CheckEvent{}); check.publish(check_event{});
} }
UVW_INLINE bool CheckHandle::init() { UVW_INLINE int check_handle::init() {
return initialize(&uv_check_init); return leak_if(uv_check_init(parent().raw(), raw()));
} }
UVW_INLINE void CheckHandle::start() { UVW_INLINE int check_handle::start() {
invoke(&uv_check_start, get(), &startCallback); return uv_check_start(raw(), &start_callback);
} }
UVW_INLINE void CheckHandle::stop() { UVW_INLINE int check_handle::stop() {
invoke(&uv_check_stop, get()); return uv_check_stop(raw());
} }
} // namespace uvw } // namespace uvw

View File

@ -7,45 +7,44 @@
namespace uvw { namespace uvw {
/** /*! @brief Check event. */
* @brief CheckEvent event. struct check_event {};
*
* It will be emitted by CheckHandle according with its functionalities.
*/
struct CheckEvent {};
/** /**
* @brief The CheckHandle handle. * @brief The check handle.
* *
* Check handles will emit a CheckEvent event once per loop iteration, right * Check handles will emit a check event once per loop iteration, right after
* after polling for I/O. * polling for I/O.
* *
* To create a `CheckHandle` through a `Loop`, no arguments are required. * To create a `check_handle` through a `loop`, no arguments are required.
*/ */
class CheckHandle final: public Handle<CheckHandle, uv_check_t> { class check_handle final: public handle<check_handle, uv_check_t, check_event> {
static void startCallback(uv_check_t *handle); static void start_callback(uv_check_t *hndl);
public: public:
using Handle::Handle; using handle::handle;
/** /**
* @brief Initializes the handle. * @brief Initializes the handle.
* @return True in case of success, false otherwise. * @return Underlying return value.
*/ */
bool init(); int init() final;
/** /**
* @brief Starts the handle. * @brief Starts the handle.
* *
* A CheckEvent event will be emitted once per loop iteration, right after * A check event will be emitted once per loop iteration, right after
* polling for I/O. * polling for I/O.
*
* @return Underlying return value.
*/ */
void start(); int start();
/** /**
* @brief Stops the handle. * @brief Stops the handle.
* @return Underlying return value.
*/ */
void stop(); int stop();
}; };
} // namespace uvw } // namespace uvw

View File

@ -6,111 +6,88 @@
namespace uvw { namespace uvw {
UVW_INLINE AddrInfoEvent::AddrInfoEvent(std::unique_ptr<addrinfo, Deleter> addr) UVW_INLINE addr_info_event::addr_info_event(std::unique_ptr<addrinfo, deleter> addr)
: data{std::move(addr)} {} : data{std::move(addr)} {}
UVW_INLINE NameInfoEvent::NameInfoEvent(const char *host, const char *serv) UVW_INLINE name_info_event::name_info_event(const char *host, const char *serv)
: hostname{host}, service{serv} {} : hostname{host}, service{serv} {}
UVW_INLINE void GetAddrInfoReq::addrInfoCallback(uv_getaddrinfo_t *req, int status, addrinfo *res) { UVW_INLINE void get_addr_info_req::addr_info_callback(uv_getaddrinfo_t *req, int status, addrinfo *res) {
if(auto ptr = reserve(req); status) { if(auto ptr = reserve(req); status) {
ptr->publish(ErrorEvent{status}); ptr->publish(error_event{status});
} else { } else {
auto data = std::unique_ptr<addrinfo, void (*)(addrinfo *)>{res, [](addrinfo *addr) { uv_freeaddrinfo(addr); }}; auto data = std::unique_ptr<addrinfo, void (*)(addrinfo *)>{res, [](addrinfo *addr) { uv_freeaddrinfo(addr); }};
ptr->publish(AddrInfoEvent{std::move(data)}); ptr->publish(addr_info_event{std::move(data)});
} }
} }
UVW_INLINE void GetAddrInfoReq::nodeAddrInfo(const char *node, const char *service, addrinfo *hints) { UVW_INLINE int get_addr_info_req::node_addr_info(const char *node, const char *service, addrinfo *hints) {
invoke(&uv_getaddrinfo, parent(), get(), &addrInfoCallback, node, service, hints); return this->leak_if(uv_getaddrinfo(parent().raw(), raw(), &addr_info_callback, node, service, hints));
} }
UVW_INLINE auto GetAddrInfoReq::nodeAddrInfoSync(const char *node, const char *service, addrinfo *hints) { UVW_INLINE auto get_addr_info_req::node_addr_info_sync(const char *node, const char *service, addrinfo *hints) {
auto req = get(); auto req = raw();
auto err = uv_getaddrinfo(parent(), req, nullptr, node, service, hints); auto err = uv_getaddrinfo(parent().raw(), req, nullptr, node, service, hints);
auto data = std::unique_ptr<addrinfo, void (*)(addrinfo *)>{req->addrinfo, [](addrinfo *addr) { uv_freeaddrinfo(addr); }}; auto data = std::unique_ptr<addrinfo, void (*)(addrinfo *)>{req->addrinfo, [](addrinfo *addr) { uv_freeaddrinfo(addr); }};
return std::make_pair(!err, std::move(data)); return std::make_pair(!err, std::move(data));
} }
UVW_INLINE void GetAddrInfoReq::nodeAddrInfo(const std::string &node, addrinfo *hints) { UVW_INLINE int get_addr_info_req::node_addr_info(const std::string &node, addrinfo *hints) {
nodeAddrInfo(node.data(), nullptr, hints); return node_addr_info(node.data(), nullptr, hints);
} }
UVW_INLINE std::pair<bool, std::unique_ptr<addrinfo, GetAddrInfoReq::Deleter>> GetAddrInfoReq::nodeAddrInfoSync(const std::string &node, addrinfo *hints) { UVW_INLINE std::pair<bool, std::unique_ptr<addrinfo, get_addr_info_req::deleter>> get_addr_info_req::node_addr_info_sync(const std::string &node, addrinfo *hints) {
return nodeAddrInfoSync(node.data(), nullptr, hints); return node_addr_info_sync(node.data(), nullptr, hints);
} }
UVW_INLINE void GetAddrInfoReq::serviceAddrInfo(const std::string &service, addrinfo *hints) { UVW_INLINE int get_addr_info_req::service_addr_info(const std::string &service, addrinfo *hints) {
nodeAddrInfo(nullptr, service.data(), hints); return node_addr_info(nullptr, service.data(), hints);
} }
UVW_INLINE std::pair<bool, std::unique_ptr<addrinfo, GetAddrInfoReq::Deleter>> GetAddrInfoReq::serviceAddrInfoSync(const std::string &service, addrinfo *hints) { UVW_INLINE std::pair<bool, std::unique_ptr<addrinfo, get_addr_info_req::deleter>> get_addr_info_req::service_addr_info_sync(const std::string &service, addrinfo *hints) {
return nodeAddrInfoSync(nullptr, service.data(), hints); return node_addr_info_sync(nullptr, service.data(), hints);
} }
UVW_INLINE void GetAddrInfoReq::addrInfo(const std::string &node, const std::string &service, addrinfo *hints) { UVW_INLINE int get_addr_info_req::addr_info(const std::string &node, const std::string &service, addrinfo *hints) {
nodeAddrInfo(node.data(), service.data(), hints); return node_addr_info(node.data(), service.data(), hints);
} }
UVW_INLINE std::pair<bool, std::unique_ptr<addrinfo, GetAddrInfoReq::Deleter>> GetAddrInfoReq::addrInfoSync(const std::string &node, const std::string &service, addrinfo *hints) { UVW_INLINE std::pair<bool, std::unique_ptr<addrinfo, get_addr_info_req::deleter>> get_addr_info_req::addr_info_sync(const std::string &node, const std::string &service, addrinfo *hints) {
return nodeAddrInfoSync(node.data(), service.data(), hints); return node_addr_info_sync(node.data(), service.data(), hints);
} }
UVW_INLINE void GetNameInfoReq::nameInfoCallback(uv_getnameinfo_t *req, int status, const char *hostname, const char *service) { UVW_INLINE void get_name_info_req::name_info_callback(uv_getnameinfo_t *req, int status, const char *hostname, const char *service) {
if(auto ptr = reserve(req); status) { if(auto ptr = reserve(req); status) {
ptr->publish(ErrorEvent{status}); ptr->publish(error_event{status});
} else { } else {
ptr->publish(NameInfoEvent{hostname, service}); ptr->publish(name_info_event{hostname, service});
} }
} }
UVW_INLINE void GetNameInfoReq::nameInfo(const sockaddr &addr, int flags) { UVW_INLINE int get_name_info_req::name_info(const sockaddr &addr, int flags) {
invoke(&uv_getnameinfo, parent(), get(), &nameInfoCallback, &addr, flags); return this->leak_if(uv_getnameinfo(parent().raw(), raw(), &name_info_callback, &addr, flags));
} }
template<typename I> UVW_INLINE int get_name_info_req::name_info(const std::string &ip, unsigned int port, int flags) {
UVW_INLINE void GetNameInfoReq::nameInfo(const std::string &ip, unsigned int port, int flags) { return name_info(details::ip_addr(ip.data(), port), flags);
typename details::IpTraits<I>::Type addr;
details::IpTraits<I>::addrFunc(ip.data(), port, &addr);
nameInfo(reinterpret_cast<const sockaddr &>(addr), flags);
} }
template<typename I> UVW_INLINE int get_name_info_req::name_info(socket_address addr, int flags) {
UVW_INLINE void GetNameInfoReq::nameInfo(Addr addr, int flags) { return name_info(std::move(addr.ip), addr.port, flags);
nameInfo<I>(std::move(addr.ip), addr.port, flags);
} }
UVW_INLINE std::pair<bool, std::pair<const char *, const char *>> GetNameInfoReq::nameInfoSync(const sockaddr &addr, int flags) { UVW_INLINE std::pair<bool, std::pair<const char *, const char *>> get_name_info_req::name_info_sync(const sockaddr &addr, int flags) {
auto req = get(); auto req = raw();
auto err = uv_getnameinfo(parent(), req, nullptr, &addr, flags); auto err = uv_getnameinfo(parent().raw(), req, nullptr, &addr, flags);
return std::make_pair(!err, std::make_pair(req->host, req->service)); return std::make_pair(!err, std::make_pair(req->host, req->service));
} }
template<typename I> UVW_INLINE std::pair<bool, std::pair<const char *, const char *>> get_name_info_req::name_info_sync(const std::string &ip, unsigned int port, int flags) {
UVW_INLINE std::pair<bool, std::pair<const char *, const char *>> GetNameInfoReq::nameInfoSync(const std::string &ip, unsigned int port, int flags) { return name_info_sync(details::ip_addr(ip.data(), port), flags);
typename details::IpTraits<I>::Type addr;
details::IpTraits<I>::addrFunc(ip.data(), port, &addr);
return nameInfoSync(reinterpret_cast<const sockaddr &>(addr), flags);
} }
template<typename I> UVW_INLINE std::pair<bool, std::pair<const char *, const char *>> get_name_info_req::name_info_sync(socket_address addr, int flags) {
UVW_INLINE std::pair<bool, std::pair<const char *, const char *>> GetNameInfoReq::nameInfoSync(Addr addr, int flags) { return name_info_sync(addr.ip, addr.port, flags);
return nameInfoSync<I>(std::move(addr.ip), addr.port, flags);
} }
// explicit instantiations
#ifdef UVW_AS_LIB
template void GetNameInfoReq::nameInfo<IPv4>(const std::string &, unsigned int, int);
template void GetNameInfoReq::nameInfo<IPv6>(const std::string &, unsigned int, int);
template void GetNameInfoReq::nameInfo<IPv4>(Addr, int);
template void GetNameInfoReq::nameInfo<IPv6>(Addr, int);
template std::pair<bool, std::pair<const char *, const char *>> GetNameInfoReq::nameInfoSync<IPv4>(const std::string &, unsigned int, int);
template std::pair<bool, std::pair<const char *, const char *>> GetNameInfoReq::nameInfoSync<IPv6>(const std::string &, unsigned int, int);
template std::pair<bool, std::pair<const char *, const char *>> GetNameInfoReq::nameInfoSync<IPv4>(Addr, int);
template std::pair<bool, std::pair<const char *, const char *>> GetNameInfoReq::nameInfoSync<IPv6>(Addr, int);
#endif // UVW_AS_LIB
} // namespace uvw } // namespace uvw

View File

@ -11,15 +11,11 @@
namespace uvw { namespace uvw {
/** /*! @brief The addrinfo event. */
* @brief AddrInfoEvent event. struct addr_info_event {
* using deleter = void (*)(addrinfo *);
* It will be emitted by GetAddrInfoReq according with its functionalities.
*/
struct AddrInfoEvent {
using Deleter = void (*)(addrinfo *);
AddrInfoEvent(std::unique_ptr<addrinfo, Deleter> addr); addr_info_event(std::unique_ptr<addrinfo, deleter> addr);
/** /**
* @brief An initialized instance of `addrinfo`. * @brief An initialized instance of `addrinfo`.
@ -27,16 +23,12 @@ struct AddrInfoEvent {
* See [getaddrinfo](http://linux.die.net/man/3/getaddrinfo) for further * See [getaddrinfo](http://linux.die.net/man/3/getaddrinfo) for further
* details. * details.
*/ */
std::unique_ptr<addrinfo, Deleter> data; std::unique_ptr<addrinfo, deleter> data;
}; };
/** /*! @brief The nameinfo event. */
* @brief NameInfoEvent event. struct name_info_event {
* name_info_event(const char *host, const char *serv);
* It will be emitted by GetNameInfoReq according with its functionalities.
*/
struct NameInfoEvent {
NameInfoEvent(const char *host, const char *serv);
/** /**
* @brief A valid hostname. * @brief A valid hostname.
@ -56,30 +48,31 @@ struct NameInfoEvent {
}; };
/** /**
* @brief The GetAddrInfoReq request. * @brief The getaddrinfo request.
* *
* Wrapper for [getaddrinfo](http://linux.die.net/man/3/getaddrinfo).<br/> * Wrapper for [getaddrinfo](http://linux.die.net/man/3/getaddrinfo).<br/>
* It offers either asynchronous and synchronous access methods. * It offers either asynchronous and synchronous access methods.
* *
* To create a `GetAddrInfoReq` through a `Loop`, no arguments are required. * To create a `get_addr_info_req` through a `loop`, no arguments are required.
*/ */
class GetAddrInfoReq final: public Request<GetAddrInfoReq, uv_getaddrinfo_t> { class get_addr_info_req final: public request<get_addr_info_req, uv_getaddrinfo_t, addr_info_event> {
static void addrInfoCallback(uv_getaddrinfo_t *req, int status, addrinfo *res); static void addr_info_callback(uv_getaddrinfo_t *req, int status, addrinfo *res);
void nodeAddrInfo(const char *node, const char *service, addrinfo *hints = nullptr); int node_addr_info(const char *node, const char *service, addrinfo *hints = nullptr);
auto nodeAddrInfoSync(const char *node, const char *service, addrinfo *hints = nullptr); auto node_addr_info_sync(const char *node, const char *service, addrinfo *hints = nullptr);
public: public:
using Deleter = void (*)(addrinfo *); using deleter = void (*)(addrinfo *);
using Request::Request; using request::request;
/** /**
* @brief Async [getaddrinfo](http://linux.die.net/man/3/getaddrinfo). * @brief Async [getaddrinfo](http://linux.die.net/man/3/getaddrinfo).
* @param node Either a numerical network address or a network hostname. * @param node Either a numerical network address or a network hostname.
* @param hints Optional `addrinfo` data structure with additional address * @param hints Optional `addrinfo` data structure with additional address
* type constraints. * type constraints.
* @return Underlying return value.
*/ */
void nodeAddrInfo(const std::string &node, addrinfo *hints = nullptr); int node_addr_info(const std::string &node, addrinfo *hints = nullptr);
/** /**
* @brief Sync [getaddrinfo](http://linux.die.net/man/3/getaddrinfo). * @brief Sync [getaddrinfo](http://linux.die.net/man/3/getaddrinfo).
@ -90,17 +83,18 @@ public:
* *
* @return A `std::pair` composed as it follows: * @return A `std::pair` composed as it follows:
* * A boolean value that is true in case of success, false otherwise. * * A boolean value that is true in case of success, false otherwise.
* * A `std::unique_ptr<addrinfo, Deleter>` containing the data requested. * * A `std::unique_ptr<addrinfo, deleter>` containing the data requested.
*/ */
std::pair<bool, std::unique_ptr<addrinfo, Deleter>> nodeAddrInfoSync(const std::string &node, addrinfo *hints = nullptr); std::pair<bool, std::unique_ptr<addrinfo, deleter>> node_addr_info_sync(const std::string &node, addrinfo *hints = nullptr);
/** /**
* @brief Async [getaddrinfo](http://linux.die.net/man/3/getaddrinfo). * @brief Async [getaddrinfo](http://linux.die.net/man/3/getaddrinfo).
* @param service Either a service name or a port number as a string. * @param service Either a service name or a port number as a string.
* @param hints Optional `addrinfo` data structure with additional address * @param hints Optional `addrinfo` data structure with additional address
* type constraints. * type constraints.
* @return Underlying return value.
*/ */
void serviceAddrInfo(const std::string &service, addrinfo *hints = nullptr); int service_addr_info(const std::string &service, addrinfo *hints = nullptr);
/** /**
* @brief Sync [getaddrinfo](http://linux.die.net/man/3/getaddrinfo). * @brief Sync [getaddrinfo](http://linux.die.net/man/3/getaddrinfo).
@ -111,9 +105,9 @@ public:
* *
* @return A `std::pair` composed as it follows: * @return A `std::pair` composed as it follows:
* * A boolean value that is true in case of success, false otherwise. * * A boolean value that is true in case of success, false otherwise.
* * A `std::unique_ptr<addrinfo, Deleter>` containing the data requested. * * A `std::unique_ptr<addrinfo, deleter>` containing the data requested.
*/ */
std::pair<bool, std::unique_ptr<addrinfo, Deleter>> serviceAddrInfoSync(const std::string &service, addrinfo *hints = nullptr); std::pair<bool, std::unique_ptr<addrinfo, deleter>> service_addr_info_sync(const std::string &service, addrinfo *hints = nullptr);
/** /**
* @brief Async [getaddrinfo](http://linux.die.net/man/3/getaddrinfo). * @brief Async [getaddrinfo](http://linux.die.net/man/3/getaddrinfo).
@ -121,8 +115,9 @@ public:
* @param service Either a service name or a port number as a string. * @param service Either a service name or a port number as a string.
* @param hints Optional `addrinfo` data structure with additional address * @param hints Optional `addrinfo` data structure with additional address
* type constraints. * type constraints.
* @return Underlying return value.
*/ */
void addrInfo(const std::string &node, const std::string &service, addrinfo *hints = nullptr); int addr_info(const std::string &node, const std::string &service, addrinfo *hints = nullptr);
/** /**
* @brief Sync [getaddrinfo](http://linux.die.net/man/3/getaddrinfo). * @brief Sync [getaddrinfo](http://linux.die.net/man/3/getaddrinfo).
@ -134,48 +129,49 @@ public:
* *
* @return A `std::pair` composed as it follows: * @return A `std::pair` composed as it follows:
* * A boolean value that is true in case of success, false otherwise. * * A boolean value that is true in case of success, false otherwise.
* * A `std::unique_ptr<addrinfo, Deleter>` containing the data requested. * * A `std::unique_ptr<addrinfo, deleter>` containing the data requested.
*/ */
std::pair<bool, std::unique_ptr<addrinfo, Deleter>> addrInfoSync(const std::string &node, const std::string &service, addrinfo *hints = nullptr); std::pair<bool, std::unique_ptr<addrinfo, deleter>> addr_info_sync(const std::string &node, const std::string &service, addrinfo *hints = nullptr);
}; };
/** /**
* @brief The GetNameInfoReq request. * @brief The getnameinfo request.
* *
* Wrapper for [getnameinfo](http://linux.die.net/man/3/getnameinfo).<br/> * Wrapper for [getnameinfo](http://linux.die.net/man/3/getnameinfo).<br/>
* It offers either asynchronous and synchronous access methods. * It offers either asynchronous and synchronous access methods.
* *
* To create a `GetNameInfoReq` through a `Loop`, no arguments are required. * To create a `get_name_info_req` through a `loop`, no arguments are required.
*/ */
class GetNameInfoReq final: public Request<GetNameInfoReq, uv_getnameinfo_t> { class get_name_info_req final: public request<get_name_info_req, uv_getnameinfo_t, name_info_event> {
static void nameInfoCallback(uv_getnameinfo_t *req, int status, const char *hostname, const char *service); static void name_info_callback(uv_getnameinfo_t *req, int status, const char *hostname, const char *service);
public: public:
using Request::Request; using request::request;
/** /**
* @brief Async [getnameinfo](http://linux.die.net/man/3/getnameinfo). * @brief Async [getnameinfo](http://linux.die.net/man/3/getnameinfo).
* @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure. * @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
* @param flags Optional flags that modify the behavior of `getnameinfo`. * @param flags Optional flags that modify the behavior of `getnameinfo`.
* @return Underlying return value.
*/ */
void nameInfo(const sockaddr &addr, int flags = 0); int name_info(const sockaddr &addr, int flags = 0);
/** /**
* @brief Async [getnameinfo](http://linux.die.net/man/3/getnameinfo). * @brief Async [getnameinfo](http://linux.die.net/man/3/getnameinfo).
* @param ip A valid IP address. * @param ip A valid IP address.
* @param port A valid port number. * @param port A valid port number.
* @param flags Optional flags that modify the behavior of `getnameinfo`. * @param flags Optional flags that modify the behavior of `getnameinfo`.
* @return Underlying return value.
*/ */
template<typename I = IPv4> int name_info(const std::string &ip, unsigned int port, int flags = 0);
void nameInfo(const std::string &ip, unsigned int port, int flags = 0);
/** /**
* @brief Async [getnameinfo](http://linux.die.net/man/3/getnameinfo). * @brief Async [getnameinfo](http://linux.die.net/man/3/getnameinfo).
* @param addr A valid instance of Addr. * @param addr A valid instance of socket_address.
* @param flags Optional flags that modify the behavior of `getnameinfo`. * @param flags Optional flags that modify the behavior of `getnameinfo`.
* @return Underlying return value.
*/ */
template<typename I = IPv4> int name_info(socket_address addr, int flags = 0);
void nameInfo(Addr addr, int flags = 0);
/** /**
* @brief Sync [getnameinfo](http://linux.die.net/man/3/getnameinfo). * @brief Sync [getnameinfo](http://linux.die.net/man/3/getnameinfo).
@ -189,7 +185,7 @@ public:
* * A `const char *` containing a valid hostname. * * A `const char *` containing a valid hostname.
* * A `const char *` containing a valid service name. * * A `const char *` containing a valid service name.
*/ */
std::pair<bool, std::pair<const char *, const char *>> nameInfoSync(const sockaddr &addr, int flags = 0); std::pair<bool, std::pair<const char *, const char *>> name_info_sync(const sockaddr &addr, int flags = 0);
/** /**
* @brief Sync [getnameinfo](http://linux.die.net/man/3/getnameinfo). * @brief Sync [getnameinfo](http://linux.die.net/man/3/getnameinfo).
@ -204,13 +200,12 @@ public:
* * A `const char *` containing a valid hostname. * * A `const char *` containing a valid hostname.
* * A `const char *` containing a valid service name. * * A `const char *` containing a valid service name.
*/ */
template<typename I = IPv4> std::pair<bool, std::pair<const char *, const char *>> name_info_sync(const std::string &ip, unsigned int port, int flags = 0);
std::pair<bool, std::pair<const char *, const char *>> nameInfoSync(const std::string &ip, unsigned int port, int flags = 0);
/** /**
* @brief Sync [getnameinfo](http://linux.die.net/man/3/getnameinfo). * @brief Sync [getnameinfo](http://linux.die.net/man/3/getnameinfo).
* *
* @param addr A valid instance of Addr. * @param addr A valid instance of socket_address.
* @param flags Optional flags that modify the behavior of `getnameinfo`. * @param flags Optional flags that modify the behavior of `getnameinfo`.
* *
* @return A `std::pair` composed as it follows: * @return A `std::pair` composed as it follows:
@ -219,35 +214,9 @@ public:
* * A `const char *` containing a valid hostname. * * A `const char *` containing a valid hostname.
* * A `const char *` containing a valid service name. * * A `const char *` containing a valid service name.
*/ */
template<typename I = IPv4> std::pair<bool, std::pair<const char *, const char *>> name_info_sync(socket_address addr, int flags = 0);
std::pair<bool, std::pair<const char *, const char *>> nameInfoSync(Addr addr, int flags = 0);
}; };
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
// (extern) explicit instantiations
#ifdef UVW_AS_LIB
extern template void GetNameInfoReq::nameInfo<IPv4>(const std::string &, unsigned int, int);
extern template void GetNameInfoReq::nameInfo<IPv6>(const std::string &, unsigned int, int);
extern template void GetNameInfoReq::nameInfo<IPv4>(Addr, int);
extern template void GetNameInfoReq::nameInfo<IPv6>(Addr, int);
extern template std::pair<bool, std::pair<const char *, const char *>> GetNameInfoReq::nameInfoSync<IPv4>(const std::string &, unsigned int, int);
extern template std::pair<bool, std::pair<const char *, const char *>> GetNameInfoReq::nameInfoSync<IPv6>(const std::string &, unsigned int, int);
extern template std::pair<bool, std::pair<const char *, const char *>> GetNameInfoReq::nameInfoSync<IPv4>(Addr, int);
extern template std::pair<bool, std::pair<const char *, const char *>> GetNameInfoReq::nameInfoSync<IPv6>(Addr, int);
#endif // UVW_AS_LIB
/**
* Internal details not to be documented.
* @endcond
*/
} // namespace uvw } // namespace uvw
#ifndef UVW_AS_LIB #ifndef UVW_AS_LIB

View File

@ -6,23 +6,23 @@
namespace uvw { namespace uvw {
UVW_INLINE int ErrorEvent::translate(int sys) noexcept { UVW_INLINE int error_event::translate(int sys) noexcept {
return uv_translate_sys_error(sys); return uv_translate_sys_error(sys);
} }
UVW_INLINE const char *ErrorEvent::what() const noexcept { UVW_INLINE const char *error_event::what() const noexcept {
return uv_strerror(ec); return uv_strerror(ec);
} }
UVW_INLINE const char *ErrorEvent::name() const noexcept { UVW_INLINE const char *error_event::name() const noexcept {
return uv_err_name(ec); return uv_err_name(ec);
} }
UVW_INLINE int ErrorEvent::code() const noexcept { UVW_INLINE int error_event::code() const noexcept {
return ec; return ec;
} }
UVW_INLINE ErrorEvent::operator bool() const noexcept { UVW_INLINE error_event::operator bool() const noexcept {
return ec < 0; return ec < 0;
} }

View File

@ -1,7 +1,6 @@
#ifndef UVW_EMITTER_INCLUDE_H #ifndef UVW_EMITTER_INCLUDE_H
#define UVW_EMITTER_INCLUDE_H #define UVW_EMITTER_INCLUDE_H
#include <algorithm>
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
#include <functional> #include <functional>
@ -11,18 +10,19 @@
#include <unordered_map> #include <unordered_map>
#include <utility> #include <utility>
#include <uv.h> #include <uv.h>
#include "config.h"
#include "type_info.hpp" #include "type_info.hpp"
namespace uvw { namespace uvw {
/** /**
* @brief The ErrorEvent event. * @brief Error event.
* *
* Custom wrapper around error constants of `libuv`. * Custom wrapper around error constants of `libuv`.
*/ */
struct ErrorEvent { struct error_event {
template<typename U, typename = std::enable_if_t<std::is_integral_v<U>>> template<typename U, typename = std::enable_if_t<std::is_integral_v<U>>>
explicit ErrorEvent(U val) noexcept explicit error_event(U val) noexcept
: ec{static_cast<int>(val)} {} : ec{static_cast<int>(val)} {}
/** /**
@ -79,215 +79,75 @@ private:
* Almost everything in `uvw` is an event emitter.<br/> * Almost everything in `uvw` is an event emitter.<br/>
* This is the base class from which resources and loops inherit. * This is the base class from which resources and loops inherit.
*/ */
template<typename T> template<typename T, typename... E>
class Emitter { class emitter {
struct BaseHandler { public:
virtual ~BaseHandler() noexcept = default; template<typename U>
virtual bool empty() const noexcept = 0; using listener_t = std::function<void(U &, T &)>;
virtual void clear() noexcept = 0;
};
template<typename E> private:
struct Handler final: BaseHandler { template<typename U>
using Listener = std::function<void(E &, T &)>; const auto &handler() const noexcept {
using Element = std::pair<bool, Listener>; return std::get<listener_t<U>>(handlers);
using ListenerList = std::list<Element>; }
using Connection = typename ListenerList::iterator;
bool empty() const noexcept override { template<typename U>
auto pred = [](auto &&element) { return element.first; }; auto &handler() noexcept {
return std::get<listener_t<U>>(handlers);
return std::all_of(onceL.cbegin(), onceL.cend(), pred) && std::all_of(onL.cbegin(), onL.cend(), pred);
}
void clear() noexcept override {
if(publishing) {
auto func = [](auto &&element) { element.first = true; };
std::for_each(onceL.begin(), onceL.end(), func);
std::for_each(onL.begin(), onL.end(), func);
} else {
onceL.clear();
onL.clear();
}
}
Connection once(Listener f) {
return onceL.emplace(onceL.cend(), false, std::move(f));
}
Connection on(Listener f) {
return onL.emplace(onL.cend(), false, std::move(f));
}
void erase(Connection conn) noexcept {
conn->first = true;
if(!publishing) {
auto pred = [](auto &&element) { return element.first; };
onceL.remove_if(pred);
onL.remove_if(pred);
}
}
void publish(E event, T &ref) {
ListenerList currentL;
onceL.swap(currentL);
auto func = [&event, &ref](auto &&element) {
return element.first ? void() : element.second(event, ref);
};
publishing = true;
std::for_each(onL.rbegin(), onL.rend(), func);
std::for_each(currentL.rbegin(), currentL.rend(), func);
publishing = false;
onL.remove_if([](auto &&element) { return element.first; });
}
private:
bool publishing{false};
ListenerList onceL{};
ListenerList onL{};
};
template<typename E>
Handler<E> &handler() noexcept {
auto id = type<E>();
if(!handlers.count(id)) {
handlers[id] = std::make_unique<Handler<E>>();
}
return static_cast<Handler<E> &>(*handlers.at(id));
} }
protected: protected:
template<typename E> template<typename U>
void publish(E event) { void publish(U event) {
handler<E>().publish(std::move(event), *static_cast<T *>(this)); if(auto &listener = handler<U>(); listener) {
listener(event, *static_cast<T *>(this));
}
} }
public: public:
template<typename E> virtual ~emitter() noexcept {
using Listener = typename Handler<E>::Listener; static_assert(std::is_base_of_v<emitter<T, E...>, T>);
/**
* @brief Connection type for a given event type.
*
* Given an event type `E`, `Connection<E>` is the type of the connection
* object returned by the event emitter whenever a listener for the given
* type is registered.
*/
template<typename E>
struct Connection: private Handler<E>::Connection {
template<typename>
friend class Emitter;
Connection() = default;
Connection(const Connection &) = default;
Connection(Connection &&) = default;
Connection(typename Handler<E>::Connection conn)
: Handler<E>::Connection{std::move(conn)} {}
Connection &operator=(const Connection &) = default;
Connection &operator=(Connection &&) = default;
};
virtual ~Emitter() noexcept {
static_assert(std::is_base_of_v<Emitter<T>, T>);
} }
/** /**
* @brief Registers a long-lived listener with the event emitter. * @brief Registers a long-lived listener with the event emitter.
* *
* This method can be used to register a listener that is meant to be * This method is used to register a listener with the emitter.<br/>
* invoked more than once for the given event type.<br/> * A listener is usually defined as a callable object assignable to a
* The Connection object returned by the method can be freely discarded. It
* can be used later to disconnect the listener, if needed.
*
* Listener is usually defined as a callable object assignable to a
* `std::function<void(const E &, T &)`, where `E` is the type of the event * `std::function<void(const E &, T &)`, where `E` is the type of the event
* and `T` is the type of the resource. * and `T` is the type of the resource.
* *
* @param f A valid listener to be registered. * @param f A valid listener to be registered.
* @return Connection object to be used later to disconnect the listener.
*/ */
template<typename E> template<typename U>
Connection<E> on(Listener<E> f) { void on(listener_t<U> f) {
return handler<E>().on(std::move(f)); handler<U>() = std::move(f);
}
/*! @brief Disconnects the listener for the given event type. */
template<typename U>
void reset() noexcept {
handler<U>() = nullptr;
}
/*! @brief Disconnects all listeners. */
void reset() noexcept {
reset<error_event>();
(reset<E>(), ...);
} }
/** /**
* @brief Registers a short-lived listener with the event emitter. * @brief Checks if there is a listener registered for the specific event.
* * @return True if there is a listener registered for the specific event,
* This method can be used to register a listener that is meant to be
* invoked only once for the given event type.<br/>
* The Connection object returned by the method can be freely discarded. It
* can be used later to disconnect the listener, if needed.
*
* Listener is usually defined as a callable object assignable to a
* `std::function<void(const E &, T &)`, where `E` is the type of the event
* and `T` is the type of the resource.
*
* @param f A valid listener to be registered.
* @return Connection object to be used later to disconnect the listener.
*/
template<typename E>
Connection<E> once(Listener<E> f) {
return handler<E>().once(std::move(f));
}
/**
* @brief Disconnects a listener from the event emitter.
* @param conn A valid Connection object
*/
template<typename E>
void erase(Connection<E> conn) noexcept {
handler<E>().erase(std::move(conn));
}
/**
* @brief Disconnects all the listeners for the given event type.
*/
template<typename E>
void clear() noexcept {
handler<E>().clear();
}
/**
* @brief Disconnects all the listeners.
*/
void clear() noexcept {
std::for_each(handlers.begin(), handlers.end(), [](auto &&hdlr) { if(hdlr.second) { hdlr.second->clear(); } });
}
/**
* @brief Checks if there are listeners registered for the specific event.
* @return True if there are no listeners registered for the specific event,
* false otherwise. * false otherwise.
*/ */
template<typename E> template<typename U>
bool empty() const noexcept { bool has() const noexcept {
auto id = type<E>(); return static_cast<bool>(handler<U>());
return (!handlers.count(id) || static_cast<Handler<E> &>(*handlers.at(id)).empty());
}
/**
* @brief Checks if there are listeners registered with the event emitter.
* @return True if there are no listeners registered with the event emitter,
* false otherwise.
*/
bool empty() const noexcept {
return std::all_of(handlers.cbegin(), handlers.cend(), [](auto &&hdlr) { return !hdlr.second || hdlr.second->empty(); });
} }
private: private:
std::unordered_map<std::uint32_t, std::unique_ptr<BaseHandler>> handlers{}; std::tuple<listener_t<error_event>, listener_t<E>...> handlers{};
}; };
} // namespace uvw } // namespace uvw

76
src/uvw/enum.hpp Normal file
View File

@ -0,0 +1,76 @@
#ifndef UVW_ENUM_INCLUDE_HPP
#define UVW_ENUM_INCLUDE_HPP
#include <type_traits>
#include "config.h"
/**
* @brief Operator available for enums for which bitmask support is enabled.
* @tparam Type Enum class type.
* @param lhs The first value to use.
* @param rhs The second value to use.
* @return The result of invoking the operator on the underlying types of the
* two values provided.
*/
template<typename Type>
[[nodiscard]] constexpr std::enable_if_t<std::is_enum_v<Type>, decltype(Type::_UVW_ENUM)>
operator|(const Type lhs, const Type rhs) noexcept {
return static_cast<Type>(static_cast<std::underlying_type_t<Type>>(lhs) | static_cast<std::underlying_type_t<Type>>(rhs));
}
/*! @copydoc operator| */
template<typename Type>
[[nodiscard]] constexpr std::enable_if_t<std::is_enum_v<Type>, decltype(Type::_UVW_ENUM)>
operator&(const Type lhs, const Type rhs) noexcept {
return static_cast<Type>(static_cast<std::underlying_type_t<Type>>(lhs) & static_cast<std::underlying_type_t<Type>>(rhs));
}
/*! @copydoc operator| */
template<typename Type>
[[nodiscard]] constexpr std::enable_if_t<std::is_enum_v<Type>, decltype(Type::_UVW_ENUM)>
operator^(const Type lhs, const Type rhs) noexcept {
return static_cast<Type>(static_cast<std::underlying_type_t<Type>>(lhs) ^ static_cast<std::underlying_type_t<Type>>(rhs));
}
/**
* @brief Operator available for enums for which bitmask support is enabled.
* @tparam Type Enum class type.
* @param value The value to use.
* @return The result of invoking the operator on the underlying types of the
* value provided.
*/
template<typename Type>
[[nodiscard]] constexpr std::enable_if_t<std::is_enum_v<Type>, decltype(Type::_UVW_ENUM)>
operator~(const Type value) noexcept {
return static_cast<Type>(~static_cast<std::underlying_type_t<Type>>(value));
}
/*! @copydoc operator~ */
template<typename Type>
[[nodiscard]] constexpr std::enable_if_t<std::is_enum_v<Type>, decltype(Type::_UVW_ENUM, bool{})>
operator!(const Type value) noexcept {
return !static_cast<std::underlying_type_t<Type>>(value);
}
/*! @copydoc operator| */
template<typename Type>
constexpr std::enable_if_t<std::is_enum_v<Type>, decltype(Type::_UVW_ENUM) &>
operator|=(Type &lhs, const Type rhs) noexcept {
return (lhs = (lhs | rhs));
}
/*! @copydoc operator| */
template<typename Type>
constexpr std::enable_if_t<std::is_enum_v<Type>, decltype(Type::_UVW_ENUM) &>
operator&=(Type &lhs, const Type rhs) noexcept {
return (lhs = (lhs & rhs));
}
/*! @copydoc operator| */
template<typename Type>
constexpr std::enable_if_t<std::is_enum_v<Type>, decltype(Type::_UVW_ENUM) &>
operator^=(Type &lhs, const Type rhs) noexcept {
return (lhs = (lhs ^ rhs));
}
#endif

View File

@ -6,50 +6,46 @@
namespace uvw { namespace uvw {
UVW_INLINE void FileReq::fsOpenCallback(uv_fs_t *req) { UVW_INLINE void file_req::fs_open_callback(uv_fs_t *req) {
auto ptr = reserve(req); if(auto ptr = reserve(req); req->result < 0) {
ptr->publish(error_event{req->result});
if(req->result < 0) {
ptr->publish(ErrorEvent{req->result});
} else { } else {
ptr->file = static_cast<uv_file>(req->result); ptr->file = static_cast<uv_file>(req->result);
ptr->publish(FsEvent<Type::OPEN>{req->path}); ptr->publish(fs_event{*req});
} }
} }
UVW_INLINE void FileReq::fsCloseCallback(uv_fs_t *req) { UVW_INLINE void file_req::fs_close_callback(uv_fs_t *req) {
auto ptr = reserve(req); if(auto ptr = reserve(req); req->result < 0) {
ptr->publish(error_event{req->result});
if(req->result < 0) {
ptr->publish(ErrorEvent{req->result});
} else { } else {
ptr->file = BAD_FD; ptr->file = BAD_FD;
ptr->publish(FsEvent<Type::CLOSE>{req->path}); ptr->publish(fs_event{*req});
} }
} }
UVW_INLINE void FileReq::fsReadCallback(uv_fs_t *req) { UVW_INLINE void file_req::fs_read_callback(uv_fs_t *req) {
auto ptr = reserve(req); if(auto ptr = reserve(req); req->result < 0) {
ptr->publish(error_event{req->result});
if(req->result < 0) {
ptr->publish(ErrorEvent{req->result});
} else { } else {
ptr->publish(FsEvent<Type::READ>{req->path, std::move(ptr->current), static_cast<std::size_t>(req->result)}); ptr->publish(fs_event{*req, std::move(ptr->current)});
} }
} }
UVW_INLINE FileReq::~FileReq() noexcept { UVW_INLINE file_req::~file_req() noexcept {
uv_fs_req_cleanup(get()); uv_fs_req_cleanup(raw());
} }
UVW_INLINE void FileReq::close() { UVW_INLINE void file_req::close() {
cleanupAndInvoke(&uv_fs_close, parent(), get(), file, &fsCloseCallback); uv_fs_req_cleanup(this->raw());
uv_fs_close(parent().raw(), raw(), file, &fs_close_callback);
} }
UVW_INLINE bool FileReq::closeSync() { UVW_INLINE bool file_req::close_sync() {
auto req = get(); auto req = raw();
cleanupAndInvokeSync(&uv_fs_close, parent(), req, file); uv_fs_req_cleanup(this->raw());
uv_fs_close(parent().raw(), req, file, nullptr);
if(req->result >= 0) { if(req->result >= 0) {
file = BAD_FD; file = BAD_FD;
@ -58,14 +54,16 @@ UVW_INLINE bool FileReq::closeSync() {
return !(req->result < 0); return !(req->result < 0);
} }
UVW_INLINE void FileReq::open(const std::string &path, Flags<FileOpen> flags, int mode) { UVW_INLINE void file_req::open(const std::string &path, file_open_flags flags, int mode) {
cleanupAndInvoke(&uv_fs_open, parent(), get(), path.data(), flags, mode, &fsOpenCallback); uv_fs_req_cleanup(this->raw());
uv_fs_open(parent().raw(), raw(), path.data(), static_cast<int>(flags), mode, &fs_open_callback);
} }
UVW_INLINE bool FileReq::openSync(const std::string &path, Flags<FileOpen> flags, int mode) { UVW_INLINE bool file_req::open_sync(const std::string &path, file_open_flags flags, int mode) {
auto req = get(); auto req = raw();
cleanupAndInvokeSync(&uv_fs_open, parent(), req, path.data(), flags, mode); uv_fs_req_cleanup(this->raw());
uv_fs_open(parent().raw(), req, path.data(), static_cast<int>(flags), mode, nullptr);
if(req->result >= 0) { if(req->result >= 0) {
file = static_cast<uv_file>(req->result); file = static_cast<uv_file>(req->result);
@ -74,191 +72,199 @@ UVW_INLINE bool FileReq::openSync(const std::string &path, Flags<FileOpen> flags
return !(req->result < 0); return !(req->result < 0);
} }
UVW_INLINE void FileReq::read(int64_t offset, unsigned int len) { UVW_INLINE void file_req::read(int64_t offset, unsigned int len) {
current = std::unique_ptr<char[]>{new char[len]}; current = std::unique_ptr<char[]>{new char[len]};
buffer = uv_buf_init(current.get(), len); buffer = uv_buf_init(current.get(), len);
uv_buf_t bufs[] = {buffer}; uv_buf_t bufs[] = {buffer};
cleanupAndInvoke(&uv_fs_read, parent(), get(), file, bufs, 1, offset, &fsReadCallback); uv_fs_req_cleanup(this->raw());
uv_fs_read(parent().raw(), raw(), file, bufs, 1, offset, &fs_read_callback);
} }
UVW_INLINE std::pair<bool, std::pair<std::unique_ptr<const char[]>, std::size_t>> FileReq::readSync(int64_t offset, unsigned int len) { UVW_INLINE std::pair<bool, std::pair<std::unique_ptr<const char[]>, std::size_t>> file_req::read_sync(int64_t offset, unsigned int len) {
current = std::unique_ptr<char[]>{new char[len]}; current = std::unique_ptr<char[]>{new char[len]};
buffer = uv_buf_init(current.get(), len); buffer = uv_buf_init(current.get(), len);
uv_buf_t bufs[] = {buffer}; uv_buf_t bufs[] = {buffer};
auto req = get(); auto req = raw();
cleanupAndInvokeSync(&uv_fs_read, parent(), req, file, bufs, 1, offset); uv_fs_req_cleanup(this->raw());
uv_fs_read(parent().raw(), req, file, bufs, 1, offset, nullptr);
bool err = req->result < 0; bool err = req->result < 0;
return std::make_pair(!err, std::make_pair(std::move(current), err ? 0 : std::size_t(req->result))); return std::make_pair(!err, std::make_pair(std::move(current), err ? 0 : std::size_t(req->result)));
} }
UVW_INLINE void FileReq::write(std::unique_ptr<char[]> buf, unsigned int len, int64_t offset) { UVW_INLINE void file_req::write(std::unique_ptr<char[]> buf, unsigned int len, int64_t offset) {
current = std::move(buf); current = std::move(buf);
uv_buf_t bufs[] = {uv_buf_init(current.get(), len)}; uv_buf_t bufs[] = {uv_buf_init(current.get(), len)};
cleanupAndInvoke(&uv_fs_write, parent(), get(), file, bufs, 1, offset, &fsResultCallback<Type::WRITE>); uv_fs_req_cleanup(this->raw());
uv_fs_write(parent().raw(), raw(), file, bufs, 1, offset, &fs_request_callback);
} }
UVW_INLINE void FileReq::write(char *buf, unsigned int len, int64_t offset) { UVW_INLINE void file_req::write(char *buf, unsigned int len, int64_t offset) {
uv_buf_t bufs[] = {uv_buf_init(buf, len)}; uv_buf_t bufs[] = {uv_buf_init(buf, len)};
cleanupAndInvoke(&uv_fs_write, parent(), get(), file, bufs, 1, offset, &fsResultCallback<Type::WRITE>); uv_fs_req_cleanup(this->raw());
uv_fs_write(parent().raw(), raw(), file, bufs, 1, offset, &fs_request_callback);
} }
UVW_INLINE std::pair<bool, std::size_t> FileReq::writeSync(std::unique_ptr<char[]> buf, unsigned int len, int64_t offset) { UVW_INLINE std::pair<bool, std::size_t> file_req::write_sync(std::unique_ptr<char[]> buf, unsigned int len, int64_t offset) {
current = std::move(buf); current = std::move(buf);
uv_buf_t bufs[] = {uv_buf_init(current.get(), len)}; uv_buf_t bufs[] = {uv_buf_init(current.get(), len)};
auto req = get(); auto req = raw();
cleanupAndInvokeSync(&uv_fs_write, parent(), req, file, bufs, 1, offset); uv_fs_req_cleanup(this->raw());
uv_fs_write(parent().raw(), req, file, bufs, 1, offset, nullptr);
bool err = req->result < 0; bool err = req->result < 0;
return std::make_pair(!err, err ? 0 : std::size_t(req->result)); return std::make_pair(!err, err ? 0 : std::size_t(req->result));
} }
UVW_INLINE void FileReq::stat() { UVW_INLINE void file_req::stat() {
cleanupAndInvoke(&uv_fs_fstat, parent(), get(), file, &fsStatCallback<Type::FSTAT>); uv_fs_req_cleanup(this->raw());
uv_fs_fstat(parent().raw(), raw(), file, &fs_request_callback);
} }
UVW_INLINE std::pair<bool, Stat> FileReq::statSync() { UVW_INLINE std::pair<bool, file_info> file_req::stat_sync() {
auto req = get(); auto req = raw();
cleanupAndInvokeSync(&uv_fs_fstat, parent(), req, file); uv_fs_req_cleanup(this->raw());
uv_fs_fstat(parent().raw(), req, file, nullptr);
return std::make_pair(!(req->result < 0), req->statbuf); return std::make_pair(!(req->result < 0), req->statbuf);
} }
UVW_INLINE void FileReq::sync() { UVW_INLINE void file_req::sync() {
cleanupAndInvoke(&uv_fs_fsync, parent(), get(), file, &fsGenericCallback<Type::FSYNC>); uv_fs_req_cleanup(this->raw());
uv_fs_fsync(parent().raw(), raw(), file, &fs_request_callback);
} }
UVW_INLINE bool FileReq::syncSync() { UVW_INLINE bool file_req::sync_sync() {
auto req = get(); auto req = raw();
cleanupAndInvokeSync(&uv_fs_fsync, parent(), req, file); uv_fs_req_cleanup(this->raw());
uv_fs_fsync(parent().raw(), req, file, nullptr);
return !(req->result < 0); return !(req->result < 0);
} }
UVW_INLINE void FileReq::datasync() { UVW_INLINE void file_req::datasync() {
cleanupAndInvoke(&uv_fs_fdatasync, parent(), get(), file, &fsGenericCallback<Type::FDATASYNC>); uv_fs_req_cleanup(this->raw());
uv_fs_fdatasync(parent().raw(), raw(), file, &fs_request_callback);
} }
UVW_INLINE bool FileReq::datasyncSync() { UVW_INLINE bool file_req::datasync_sync() {
auto req = get(); auto req = raw();
cleanupAndInvokeSync(&uv_fs_fdatasync, parent(), req, file); uv_fs_req_cleanup(this->raw());
uv_fs_fdatasync(parent().raw(), req, file, nullptr);
return !(req->result < 0); return !(req->result < 0);
} }
UVW_INLINE void FileReq::truncate(int64_t offset) { UVW_INLINE void file_req::truncate(int64_t offset) {
cleanupAndInvoke(&uv_fs_ftruncate, parent(), get(), file, offset, &fsGenericCallback<Type::FTRUNCATE>); uv_fs_req_cleanup(this->raw());
uv_fs_ftruncate(parent().raw(), raw(), file, offset, &fs_request_callback);
} }
UVW_INLINE bool FileReq::truncateSync(int64_t offset) { UVW_INLINE bool file_req::truncate_sync(int64_t offset) {
auto req = get(); auto req = raw();
cleanupAndInvokeSync(&uv_fs_ftruncate, parent(), req, file, offset); uv_fs_req_cleanup(this->raw());
uv_fs_ftruncate(parent().raw(), req, file, offset, nullptr);
return !(req->result < 0); return !(req->result < 0);
} }
UVW_INLINE void FileReq::sendfile(FileHandle out, int64_t offset, std::size_t length) { UVW_INLINE void file_req::sendfile(file_handle out, int64_t offset, std::size_t length) {
cleanupAndInvoke(&uv_fs_sendfile, parent(), get(), out, file, offset, length, &fsResultCallback<Type::SENDFILE>); uv_fs_req_cleanup(this->raw());
uv_fs_sendfile(parent().raw(), raw(), out, file, offset, length, &fs_request_callback);
} }
UVW_INLINE std::pair<bool, std::size_t> FileReq::sendfileSync(FileHandle out, int64_t offset, std::size_t length) { UVW_INLINE std::pair<bool, std::size_t> file_req::sendfile_sync(file_handle out, int64_t offset, std::size_t length) {
auto req = get(); auto req = raw();
cleanupAndInvokeSync(&uv_fs_sendfile, parent(), req, out, file, offset, length); uv_fs_req_cleanup(this->raw());
uv_fs_sendfile(parent().raw(), req, out, file, offset, length, nullptr);
bool err = req->result < 0; bool err = req->result < 0;
return std::make_pair(!err, err ? 0 : std::size_t(req->result)); return std::make_pair(!err, err ? 0 : std::size_t(req->result));
} }
UVW_INLINE void FileReq::chmod(int mode) { UVW_INLINE void file_req::chmod(int mode) {
cleanupAndInvoke(&uv_fs_fchmod, parent(), get(), file, mode, &fsGenericCallback<Type::FCHMOD>); uv_fs_req_cleanup(this->raw());
uv_fs_fchmod(parent().raw(), raw(), file, mode, &fs_request_callback);
} }
UVW_INLINE bool FileReq::chmodSync(int mode) { UVW_INLINE bool file_req::chmod_sync(int mode) {
auto req = get(); auto req = raw();
cleanupAndInvokeSync(&uv_fs_fchmod, parent(), req, file, mode); uv_fs_req_cleanup(this->raw());
uv_fs_fchmod(parent().raw(), req, file, mode, nullptr);
return !(req->result < 0); return !(req->result < 0);
} }
UVW_INLINE void FileReq::futime(FsRequest::Time atime, FsRequest::Time mtime) { UVW_INLINE void file_req::futime(fs_request::time atime, fs_request::time mtime) {
cleanupAndInvoke(&uv_fs_futime, parent(), get(), file, atime.count(), mtime.count(), &fsGenericCallback<Type::FUTIME>); uv_fs_req_cleanup(this->raw());
uv_fs_futime(parent().raw(), raw(), file, atime.count(), mtime.count(), &fs_request_callback);
} }
UVW_INLINE bool FileReq::futimeSync(FsRequest::Time atime, FsRequest::Time mtime) { UVW_INLINE bool file_req::futime_sync(fs_request::time atime, fs_request::time mtime) {
auto req = get(); auto req = raw();
cleanupAndInvokeSync(&uv_fs_futime, parent(), req, file, atime.count(), mtime.count()); uv_fs_req_cleanup(this->raw());
uv_fs_futime(parent().raw(), req, file, atime.count(), mtime.count(), nullptr);
return !(req->result < 0); return !(req->result < 0);
} }
UVW_INLINE void FileReq::chown(Uid uid, Gid gid) { UVW_INLINE void file_req::chown(uid_type uid, gid_type gid) {
cleanupAndInvoke(&uv_fs_fchown, parent(), get(), file, uid, gid, &fsGenericCallback<Type::FCHOWN>); uv_fs_req_cleanup(this->raw());
uv_fs_fchown(parent().raw(), raw(), file, uid, gid, &fs_request_callback);
} }
UVW_INLINE bool FileReq::chownSync(Uid uid, Gid gid) { UVW_INLINE bool file_req::chown_sync(uid_type uid, gid_type gid) {
auto req = get(); auto req = raw();
cleanupAndInvokeSync(&uv_fs_fchown, parent(), req, file, uid, gid); uv_fs_req_cleanup(this->raw());
uv_fs_fchown(parent().raw(), req, file, uid, gid, nullptr);
return !(req->result < 0); return !(req->result < 0);
} }
UVW_INLINE FileReq::operator FileHandle() const noexcept { UVW_INLINE file_req::operator file_handle() const noexcept {
return file; return file;
} }
UVW_INLINE void FsReq::fsReadlinkCallback(uv_fs_t *req) { UVW_INLINE fs_req::~fs_req() noexcept {
auto ptr = reserve(req); uv_fs_req_cleanup(raw());
if(req->result < 0) {
ptr->publish(ErrorEvent{req->result});
} else {
ptr->publish(FsEvent<Type::READLINK>{req->path, static_cast<char *>(req->ptr), static_cast<std::size_t>(req->result)});
}
} }
UVW_INLINE void FsReq::fsReaddirCallback(uv_fs_t *req) { UVW_INLINE void fs_req::unlink(const std::string &path) {
auto ptr = reserve(req); uv_fs_req_cleanup(this->raw());
uv_fs_unlink(parent().raw(), raw(), path.data(), &fs_request_callback);
if(req->result < 0) {
ptr->publish(ErrorEvent{req->result});
} else {
auto *dir = static_cast<uv_dir_t *>(req->ptr);
ptr->publish(FsEvent<Type::READDIR>{dir->dirents[0].name, static_cast<EntryType>(dir->dirents[0].type), !req->result});
}
} }
UVW_INLINE FsReq::~FsReq() noexcept { UVW_INLINE bool fs_req::unlink_sync(const std::string &path) {
uv_fs_req_cleanup(get()); auto req = raw();
} uv_fs_req_cleanup(this->raw());
uv_fs_unlink(parent().raw(), req, path.data(), nullptr);
UVW_INLINE void FsReq::unlink(const std::string &path) {
cleanupAndInvoke(&uv_fs_unlink, parent(), get(), path.data(), &fsGenericCallback<Type::UNLINK>);
}
UVW_INLINE bool FsReq::unlinkSync(const std::string &path) {
auto req = get();
cleanupAndInvokeSync(&uv_fs_unlink, parent(), req, path.data());
return !(req->result < 0); return !(req->result < 0);
} }
UVW_INLINE void FsReq::mkdir(const std::string &path, int mode) { UVW_INLINE void fs_req::mkdir(const std::string &path, int mode) {
cleanupAndInvoke(&uv_fs_mkdir, parent(), get(), path.data(), mode, &fsGenericCallback<Type::MKDIR>); uv_fs_req_cleanup(this->raw());
uv_fs_mkdir(parent().raw(), raw(), path.data(), mode, &fs_request_callback);
} }
UVW_INLINE bool FsReq::mkdirSync(const std::string &path, int mode) { UVW_INLINE bool fs_req::mkdir_sync(const std::string &path, int mode) {
auto req = get(); auto req = raw();
cleanupAndInvokeSync(&uv_fs_mkdir, parent(), req, path.data(), mode); uv_fs_req_cleanup(this->raw());
uv_fs_mkdir(parent().raw(), req, path.data(), mode, nullptr);
return !(req->result < 0); return !(req->result < 0);
} }
UVW_INLINE void FsReq::mkdtemp(const std::string &tpl) { UVW_INLINE void fs_req::mkdtemp(const std::string &tpl) {
cleanupAndInvoke(&uv_fs_mkdtemp, parent(), get(), tpl.data(), &fsGenericCallback<Type::MKDTEMP>); uv_fs_req_cleanup(this->raw());
uv_fs_mkdtemp(parent().raw(), raw(), tpl.data(), &fs_request_callback);
} }
UVW_INLINE std::pair<bool, const char *> FsReq::mkdtempSync(const std::string &tpl) { UVW_INLINE std::pair<bool, const char *> fs_req::mkdtemp_sync(const std::string &tpl) {
auto req = get(); auto req = raw();
cleanupAndInvokeSync(&uv_fs_mkdtemp, parent(), req, tpl.data()); uv_fs_req_cleanup(this->raw());
uv_fs_mkdtemp(parent().raw(), req, tpl.data(), nullptr);
return std::make_pair(!(req->result < 0), req->path); return std::make_pair(!(req->result < 0), req->path);
} }
UVW_INLINE void FsReq::mkstemp(const std::string &tpl) { UVW_INLINE void fs_req::mkstemp(const std::string &tpl) {
cleanupAndInvoke(&uv_fs_mkstemp, parent(), get(), tpl.data(), &fsResultCallback<Type::MKSTEMP>); uv_fs_req_cleanup(this->raw());
uv_fs_mkstemp(parent().raw(), raw(), tpl.data(), &fs_request_callback);
} }
UVW_INLINE std::pair<bool, std::pair<std::string, std::size_t>> FsReq::mkstempSync(const std::string &tpl) { UVW_INLINE std::pair<bool, std::pair<std::string, std::size_t>> fs_req::mkstemp_sync(const std::string &tpl) {
std::pair<bool, std::pair<std::string, std::size_t>> ret{false, {}}; std::pair<bool, std::pair<std::string, std::size_t>> ret{false, {}};
auto req = get(); auto req = raw();
cleanupAndInvokeSync(&uv_fs_mkdtemp, parent(), req, tpl.data()); uv_fs_req_cleanup(this->raw());
uv_fs_mkstemp(parent().raw(), req, tpl.data(), nullptr);
ret.first = !(req->result < 0); ret.first = !(req->result < 0);
if(ret.first) { if(ret.first) {
@ -269,46 +275,51 @@ UVW_INLINE std::pair<bool, std::pair<std::string, std::size_t>> FsReq::mkstempSy
return ret; return ret;
} }
UVW_INLINE void FsReq::lutime(const std::string &path, Time atime, Time mtime) { UVW_INLINE void fs_req::lutime(const std::string &path, time atime, time mtime) {
cleanupAndInvoke(&uv_fs_lutime, parent(), get(), path.data(), atime.count(), mtime.count(), &fsGenericCallback<Type::LUTIME>); uv_fs_req_cleanup(this->raw());
uv_fs_lutime(parent().raw(), raw(), path.data(), atime.count(), mtime.count(), &fs_request_callback);
} }
UVW_INLINE bool FsReq::lutimeSync(const std::string &path, Time atime, Time mtime) { UVW_INLINE bool fs_req::lutime_sync(const std::string &path, time atime, time mtime) {
auto req = get(); auto req = raw();
cleanupAndInvokeSync(&uv_fs_lutime, parent(), req, path.data(), atime.count(), mtime.count()); uv_fs_req_cleanup(this->raw());
uv_fs_lutime(parent().raw(), req, path.data(), atime.count(), mtime.count(), nullptr);
return !(req->result < 0); return !(req->result < 0);
} }
UVW_INLINE void FsReq::rmdir(const std::string &path) { UVW_INLINE void fs_req::rmdir(const std::string &path) {
cleanupAndInvoke(&uv_fs_rmdir, parent(), get(), path.data(), &fsGenericCallback<Type::RMDIR>); uv_fs_req_cleanup(this->raw());
uv_fs_rmdir(parent().raw(), raw(), path.data(), &fs_request_callback);
} }
UVW_INLINE bool FsReq::rmdirSync(const std::string &path) { UVW_INLINE bool fs_req::rmdir_sync(const std::string &path) {
auto req = get(); auto req = raw();
cleanupAndInvokeSync(&uv_fs_rmdir, parent(), req, path.data()); uv_fs_req_cleanup(this->raw());
uv_fs_rmdir(parent().raw(), req, path.data(), nullptr);
return !(req->result < 0); return !(req->result < 0);
} }
UVW_INLINE void FsReq::scandir(const std::string &path, int flags) { UVW_INLINE void fs_req::scandir(const std::string &path, int flags) {
cleanupAndInvoke(&uv_fs_scandir, parent(), get(), path.data(), flags, &fsResultCallback<Type::SCANDIR>); uv_fs_req_cleanup(this->raw());
uv_fs_scandir(parent().raw(), raw(), path.data(), flags, &fs_request_callback);
} }
UVW_INLINE std::pair<bool, std::size_t> FsReq::scandirSync(const std::string &path, int flags) { UVW_INLINE std::pair<bool, std::size_t> fs_req::scandir_sync(const std::string &path, int flags) {
auto req = get(); auto req = raw();
cleanupAndInvokeSync(&uv_fs_scandir, parent(), req, path.data(), flags); uv_fs_req_cleanup(this->raw());
uv_fs_scandir(parent().raw(), req, path.data(), flags, nullptr);
bool err = req->result < 0; bool err = req->result < 0;
return std::make_pair(!err, err ? 0 : std::size_t(req->result)); return std::make_pair(!err, err ? 0 : std::size_t(req->result));
} }
UVW_INLINE std::pair<bool, std::pair<FsReq::EntryType, const char *>> FsReq::scandirNext() { UVW_INLINE std::pair<bool, std::pair<fs_req::entry_type, const char *>> fs_req::scandir_next() {
std::pair<bool, std::pair<EntryType, const char *>> ret{false, {EntryType::UNKNOWN, nullptr}}; std::pair<bool, std::pair<entry_type, const char *>> ret{false, {entry_type::UNKNOWN, nullptr}};
// we cannot use cleanupAndInvokeSync because of the return value of uv_fs_scandir_next uv_fs_req_cleanup(raw());
uv_fs_req_cleanup(get()); auto res = uv_fs_scandir_next(raw(), dirents);
auto res = uv_fs_scandir_next(get(), dirents);
if(UV_EOF != res) { if(UV_EOF != res) {
ret.second.first = static_cast<EntryType>(dirents[0].type); ret.second.first = static_cast<entry_type>(dirents[0].type);
ret.second.second = dirents[0].name; ret.second.second = dirents[0].name;
ret.first = true; ret.first = true;
} }
@ -316,192 +327,226 @@ UVW_INLINE std::pair<bool, std::pair<FsReq::EntryType, const char *>> FsReq::sca
return ret; return ret;
} }
UVW_INLINE void FsReq::stat(const std::string &path) { UVW_INLINE void fs_req::stat(const std::string &path) {
cleanupAndInvoke(&uv_fs_stat, parent(), get(), path.data(), &fsStatCallback<Type::STAT>); uv_fs_req_cleanup(this->raw());
uv_fs_stat(parent().raw(), raw(), path.data(), &fs_request_callback);
} }
UVW_INLINE std::pair<bool, Stat> FsReq::statSync(const std::string &path) { UVW_INLINE std::pair<bool, file_info> fs_req::stat_sync(const std::string &path) {
auto req = get(); auto req = raw();
cleanupAndInvokeSync(&uv_fs_stat, parent(), req, path.data()); uv_fs_req_cleanup(this->raw());
uv_fs_stat(parent().raw(), req, path.data(), nullptr);
return std::make_pair(!(req->result < 0), req->statbuf); return std::make_pair(!(req->result < 0), req->statbuf);
} }
UVW_INLINE void FsReq::lstat(const std::string &path) { UVW_INLINE void fs_req::lstat(const std::string &path) {
cleanupAndInvoke(&uv_fs_lstat, parent(), get(), path.data(), &fsStatCallback<Type::LSTAT>); uv_fs_req_cleanup(this->raw());
uv_fs_lstat(parent().raw(), raw(), path.data(), &fs_request_callback);
} }
UVW_INLINE std::pair<bool, Stat> FsReq::lstatSync(const std::string &path) { UVW_INLINE std::pair<bool, file_info> fs_req::lstat_sync(const std::string &path) {
auto req = get(); auto req = raw();
cleanupAndInvokeSync(&uv_fs_lstat, parent(), req, path.data()); uv_fs_req_cleanup(this->raw());
uv_fs_lstat(parent().raw(), req, path.data(), nullptr);
return std::make_pair(!(req->result < 0), req->statbuf); return std::make_pair(!(req->result < 0), req->statbuf);
} }
UVW_INLINE void FsReq::statfs(const std::string &path) { UVW_INLINE void fs_req::statfs(const std::string &path) {
cleanupAndInvoke(&uv_fs_statfs, parent(), get(), path.data(), &fsStatfsCallback); uv_fs_req_cleanup(this->raw());
uv_fs_statfs(parent().raw(), raw(), path.data(), &fs_request_callback);
} }
UVW_INLINE std::pair<bool, Statfs> FsReq::statfsSync(const std::string &path) { UVW_INLINE std::pair<bool, fs_info> fs_req::statfs_sync(const std::string &path) {
auto req = get(); auto req = raw();
cleanupAndInvokeSync(&uv_fs_statfs, parent(), req, path.data()); uv_fs_req_cleanup(this->raw());
uv_fs_statfs(parent().raw(), req, path.data(), nullptr);
return std::make_pair(!(req->result < 0), *static_cast<uv_statfs_t *>(req->ptr)); return std::make_pair(!(req->result < 0), *static_cast<uv_statfs_t *>(req->ptr));
} }
UVW_INLINE void FsReq::rename(const std::string &old, const std::string &path) { UVW_INLINE void fs_req::rename(const std::string &old, const std::string &path) {
cleanupAndInvoke(&uv_fs_rename, parent(), get(), old.data(), path.data(), &fsGenericCallback<Type::RENAME>); uv_fs_req_cleanup(this->raw());
uv_fs_rename(parent().raw(), raw(), old.data(), path.data(), &fs_request_callback);
} }
UVW_INLINE bool FsReq::renameSync(const std::string &old, const std::string &path) { UVW_INLINE bool fs_req::rename_sync(const std::string &old, const std::string &path) {
auto req = get(); auto req = raw();
cleanupAndInvokeSync(&uv_fs_rename, parent(), req, old.data(), path.data()); uv_fs_req_cleanup(this->raw());
uv_fs_rename(parent().raw(), req, old.data(), path.data(), nullptr);
return !(req->result < 0); return !(req->result < 0);
} }
UVW_INLINE void FsReq::copyfile(const std::string &old, const std::string &path, Flags<CopyFile> flags) { UVW_INLINE void fs_req::copyfile(const std::string &old, const std::string &path, copy_file_flags flags) {
cleanupAndInvoke(&uv_fs_copyfile, parent(), get(), old.data(), path.data(), flags, &fsGenericCallback<Type::COPYFILE>); uv_fs_req_cleanup(this->raw());
uv_fs_copyfile(parent().raw(), raw(), old.data(), path.data(), static_cast<int>(flags), &fs_request_callback);
} }
UVW_INLINE bool FsReq::copyfileSync(const std::string &old, const std::string &path, Flags<CopyFile> flags) { UVW_INLINE bool fs_req::copyfile_sync(const std::string &old, const std::string &path, copy_file_flags flags) {
auto req = get(); auto req = raw();
cleanupAndInvokeSync(&uv_fs_copyfile, parent(), get(), old.data(), path.data(), flags); uv_fs_req_cleanup(this->raw());
uv_fs_copyfile(parent().raw(), raw(), old.data(), path.data(), static_cast<int>(flags), nullptr);
return !(req->result < 0); return !(req->result < 0);
} }
UVW_INLINE void FsReq::access(const std::string &path, int mode) { UVW_INLINE void fs_req::access(const std::string &path, int mode) {
cleanupAndInvoke(&uv_fs_access, parent(), get(), path.data(), mode, &fsGenericCallback<Type::ACCESS>); uv_fs_req_cleanup(this->raw());
uv_fs_access(parent().raw(), raw(), path.data(), mode, &fs_request_callback);
} }
UVW_INLINE bool FsReq::accessSync(const std::string &path, int mode) { UVW_INLINE bool fs_req::access_sync(const std::string &path, int mode) {
auto req = get(); auto req = raw();
cleanupAndInvokeSync(&uv_fs_access, parent(), req, path.data(), mode); uv_fs_req_cleanup(this->raw());
uv_fs_access(parent().raw(), req, path.data(), mode, nullptr);
return !(req->result < 0); return !(req->result < 0);
} }
UVW_INLINE void FsReq::chmod(const std::string &path, int mode) { UVW_INLINE void fs_req::chmod(const std::string &path, int mode) {
cleanupAndInvoke(&uv_fs_chmod, parent(), get(), path.data(), mode, &fsGenericCallback<Type::CHMOD>); uv_fs_req_cleanup(this->raw());
uv_fs_chmod(parent().raw(), raw(), path.data(), mode, &fs_request_callback);
} }
UVW_INLINE bool FsReq::chmodSync(const std::string &path, int mode) { UVW_INLINE bool fs_req::chmod_sync(const std::string &path, int mode) {
auto req = get(); auto req = raw();
cleanupAndInvokeSync(&uv_fs_chmod, parent(), req, path.data(), mode); uv_fs_req_cleanup(this->raw());
uv_fs_chmod(parent().raw(), req, path.data(), mode, nullptr);
return !(req->result < 0); return !(req->result < 0);
} }
UVW_INLINE void FsReq::utime(const std::string &path, FsRequest::Time atime, FsRequest::Time mtime) { UVW_INLINE void fs_req::utime(const std::string &path, fs_request::time atime, fs_request::time mtime) {
cleanupAndInvoke(&uv_fs_utime, parent(), get(), path.data(), atime.count(), mtime.count(), &fsGenericCallback<Type::UTIME>); uv_fs_req_cleanup(this->raw());
uv_fs_utime(parent().raw(), raw(), path.data(), atime.count(), mtime.count(), &fs_request_callback);
} }
UVW_INLINE bool FsReq::utimeSync(const std::string &path, FsRequest::Time atime, FsRequest::Time mtime) { UVW_INLINE bool fs_req::utime_sync(const std::string &path, fs_request::time atime, fs_request::time mtime) {
auto req = get(); auto req = raw();
cleanupAndInvokeSync(&uv_fs_utime, parent(), req, path.data(), atime.count(), mtime.count()); uv_fs_req_cleanup(this->raw());
uv_fs_utime(parent().raw(), req, path.data(), atime.count(), mtime.count(), nullptr);
return !(req->result < 0); return !(req->result < 0);
} }
UVW_INLINE void FsReq::link(const std::string &old, const std::string &path) { UVW_INLINE void fs_req::link(const std::string &old, const std::string &path) {
cleanupAndInvoke(&uv_fs_link, parent(), get(), old.data(), path.data(), &fsGenericCallback<Type::LINK>); uv_fs_req_cleanup(this->raw());
uv_fs_link(parent().raw(), raw(), old.data(), path.data(), &fs_request_callback);
} }
UVW_INLINE bool FsReq::linkSync(const std::string &old, const std::string &path) { UVW_INLINE bool fs_req::link_sync(const std::string &old, const std::string &path) {
auto req = get(); auto req = raw();
cleanupAndInvokeSync(&uv_fs_link, parent(), req, old.data(), path.data()); uv_fs_req_cleanup(this->raw());
uv_fs_link(parent().raw(), req, old.data(), path.data(), nullptr);
return !(req->result < 0); return !(req->result < 0);
} }
UVW_INLINE void FsReq::symlink(const std::string &old, const std::string &path, Flags<SymLink> flags) { UVW_INLINE void fs_req::symlink(const std::string &old, const std::string &path, symlink_flags flags) {
cleanupAndInvoke(&uv_fs_symlink, parent(), get(), old.data(), path.data(), flags, &fsGenericCallback<Type::SYMLINK>); uv_fs_req_cleanup(this->raw());
uv_fs_symlink(parent().raw(), raw(), old.data(), path.data(), static_cast<int>(flags), &fs_request_callback);
} }
UVW_INLINE bool FsReq::symlinkSync(const std::string &old, const std::string &path, Flags<SymLink> flags) { UVW_INLINE bool fs_req::symlink_sync(const std::string &old, const std::string &path, symlink_flags flags) {
auto req = get(); auto req = raw();
cleanupAndInvokeSync(&uv_fs_symlink, parent(), req, old.data(), path.data(), flags); uv_fs_req_cleanup(this->raw());
uv_fs_symlink(parent().raw(), req, old.data(), path.data(), static_cast<int>(flags), nullptr);
return !(req->result < 0); return !(req->result < 0);
} }
UVW_INLINE void FsReq::readlink(const std::string &path) { UVW_INLINE void fs_req::readlink(const std::string &path) {
cleanupAndInvoke(&uv_fs_readlink, parent(), get(), path.data(), &fsReadlinkCallback); uv_fs_req_cleanup(this->raw());
uv_fs_readlink(parent().raw(), raw(), path.data(), &fs_request_callback);
} }
UVW_INLINE std::pair<bool, std::pair<const char *, std::size_t>> FsReq::readlinkSync(const std::string &path) { UVW_INLINE std::pair<bool, std::pair<const char *, std::size_t>> fs_req::readlink_sync(const std::string &path) {
auto req = get(); auto req = raw();
cleanupAndInvokeSync(&uv_fs_readlink, parent(), req, path.data()); uv_fs_req_cleanup(this->raw());
uv_fs_readlink(parent().raw(), req, path.data(), nullptr);
bool err = req->result < 0; bool err = req->result < 0;
return std::make_pair(!err, std::make_pair(static_cast<char *>(req->ptr), err ? 0 : std::size_t(req->result))); return std::make_pair(!err, std::make_pair(static_cast<char *>(req->ptr), err ? 0 : std::size_t(req->result)));
} }
UVW_INLINE void FsReq::realpath(const std::string &path) { UVW_INLINE void fs_req::realpath(const std::string &path) {
cleanupAndInvoke(&uv_fs_realpath, parent(), get(), path.data(), &fsGenericCallback<Type::REALPATH>); uv_fs_req_cleanup(this->raw());
uv_fs_realpath(parent().raw(), raw(), path.data(), &fs_request_callback);
} }
UVW_INLINE std::pair<bool, const char *> FsReq::realpathSync(const std::string &path) { UVW_INLINE std::pair<bool, const char *> fs_req::realpath_sync(const std::string &path) {
auto req = get(); auto req = raw();
cleanupAndInvokeSync(&uv_fs_realpath, parent(), req, path.data()); uv_fs_req_cleanup(this->raw());
uv_fs_realpath(parent().raw(), req, path.data(), nullptr);
return std::make_pair(!(req->result < 0), req->path); return std::make_pair(!(req->result < 0), req->path);
} }
UVW_INLINE void FsReq::chown(const std::string &path, Uid uid, Gid gid) { UVW_INLINE void fs_req::chown(const std::string &path, uid_type uid, gid_type gid) {
cleanupAndInvoke(&uv_fs_chown, parent(), get(), path.data(), uid, gid, &fsGenericCallback<Type::CHOWN>); uv_fs_req_cleanup(this->raw());
uv_fs_chown(parent().raw(), raw(), path.data(), uid, gid, &fs_request_callback);
} }
UVW_INLINE bool FsReq::chownSync(const std::string &path, Uid uid, Gid gid) { UVW_INLINE bool fs_req::chown_sync(const std::string &path, uid_type uid, gid_type gid) {
auto req = get(); auto req = raw();
cleanupAndInvokeSync(&uv_fs_chown, parent(), req, path.data(), uid, gid); uv_fs_req_cleanup(this->raw());
uv_fs_chown(parent().raw(), req, path.data(), uid, gid, nullptr);
return !(req->result < 0); return !(req->result < 0);
} }
UVW_INLINE void FsReq::lchown(const std::string &path, Uid uid, Gid gid) { UVW_INLINE void fs_req::lchown(const std::string &path, uid_type uid, gid_type gid) {
cleanupAndInvoke(&uv_fs_lchown, parent(), get(), path.data(), uid, gid, &fsGenericCallback<Type::LCHOWN>); uv_fs_req_cleanup(this->raw());
uv_fs_lchown(parent().raw(), raw(), path.data(), uid, gid, &fs_request_callback);
} }
UVW_INLINE bool FsReq::lchownSync(const std::string &path, Uid uid, Gid gid) { UVW_INLINE bool fs_req::lchown_sync(const std::string &path, uid_type uid, gid_type gid) {
auto req = get(); auto req = raw();
cleanupAndInvokeSync(&uv_fs_lchown, parent(), req, path.data(), uid, gid); uv_fs_req_cleanup(this->raw());
uv_fs_lchown(parent().raw(), req, path.data(), uid, gid, nullptr);
return !(req->result < 0); return !(req->result < 0);
} }
UVW_INLINE void FsReq::opendir(const std::string &path) { UVW_INLINE void fs_req::opendir(const std::string &path) {
cleanupAndInvoke(&uv_fs_opendir, parent(), get(), path.data(), &fsGenericCallback<Type::OPENDIR>); uv_fs_req_cleanup(this->raw());
uv_fs_opendir(parent().raw(), raw(), path.data(), &fs_request_callback);
} }
UVW_INLINE bool FsReq::opendirSync(const std::string &path) { UVW_INLINE bool fs_req::opendir_sync(const std::string &path) {
auto req = get(); auto req = raw();
cleanupAndInvokeSync(&uv_fs_opendir, parent(), req, path.data()); uv_fs_req_cleanup(this->raw());
uv_fs_opendir(parent().raw(), req, path.data(), nullptr);
return !(req->result < 0); return !(req->result < 0);
} }
UVW_INLINE void FsReq::closedir() { UVW_INLINE void fs_req::closedir() {
auto req = get(); auto req = raw();
auto *dir = static_cast<uv_dir_t *>(req->ptr); auto *dir = static_cast<uv_dir_t *>(req->ptr);
cleanupAndInvoke(&uv_fs_closedir, parent(), req, dir, &fsGenericCallback<Type::CLOSEDIR>); uv_fs_req_cleanup(this->raw());
uv_fs_closedir(parent().raw(), req, dir, &fs_request_callback);
} }
UVW_INLINE bool FsReq::closedirSync() { UVW_INLINE bool fs_req::closedir_sync() {
auto req = get(); auto req = raw();
auto *dir = static_cast<uv_dir_t *>(req->ptr); auto *dir = static_cast<uv_dir_t *>(req->ptr);
cleanupAndInvokeSync(&uv_fs_closedir, parent(), req, dir); uv_fs_req_cleanup(this->raw());
uv_fs_closedir(parent().raw(), req, dir, nullptr);
return !(req->result < 0); return !(req->result < 0);
} }
UVW_INLINE void FsReq::readdir() { UVW_INLINE void fs_req::readdir() {
auto req = get(); auto req = raw();
auto *dir = static_cast<uv_dir_t *>(req->ptr); auto *dir = static_cast<uv_dir_t *>(req->ptr);
dir->dirents = dirents; dir->dirents = dirents;
dir->nentries = 1; dir->nentries = 1;
cleanupAndInvoke(&uv_fs_readdir, parent(), req, dir, &fsReaddirCallback); uv_fs_req_cleanup(this->raw());
uv_fs_readdir(parent().raw(), req, dir, &fs_request_callback);
} }
UVW_INLINE std::pair<bool, std::pair<FsReq::EntryType, const char *>> FsReq::readdirSync() { UVW_INLINE std::pair<bool, std::pair<fs_req::entry_type, const char *>> fs_req::readdir_sync() {
auto req = get(); auto req = raw();
auto *dir = static_cast<uv_dir_t *>(req->ptr); auto *dir = static_cast<uv_dir_t *>(req->ptr);
dir->dirents = dirents; dir->dirents = dirents;
dir->nentries = 1; dir->nentries = 1;
cleanupAndInvokeSync(&uv_fs_readdir, parent(), req, dir); uv_fs_req_cleanup(this->raw());
return {req->result != 0, {static_cast<EntryType>(dirents[0].type), dirents[0].name}}; uv_fs_readdir(parent().raw(), req, dir, nullptr);
return {req->result != 0, {static_cast<entry_type>(dirents[0].type), dirents[0].name}};
} }
UVW_INLINE OSFileDescriptor FsHelper::handle(FileHandle file) noexcept { UVW_INLINE os_file_descriptor fs_helper::handle(file_handle file) noexcept {
return uv_get_osfhandle(file); return uv_get_osfhandle(file);
} }
UVW_INLINE FileHandle FsHelper::open(OSFileDescriptor descriptor) noexcept { UVW_INLINE file_handle fs_helper::open(os_file_descriptor descriptor) noexcept {
return uv_open_osfhandle(descriptor); return uv_open_osfhandle(descriptor);
} }

File diff suppressed because it is too large Load Diff

View File

@ -7,37 +7,31 @@
namespace uvw { namespace uvw {
UVW_INLINE FsEventEvent::FsEventEvent(const char *pathname, Flags<details::UVFsEvent> events) UVW_INLINE fs_event_event::fs_event_event(const char *pathname, details::uvw_fs_event events)
: filename{pathname}, flags{std::move(events)} {} : filename{pathname}, flags{std::move(events)} {}
UVW_INLINE void FsEventHandle::startCallback(uv_fs_event_t *handle, const char *filename, int events, int status) { UVW_INLINE void fs_event_handle::start_callback(uv_fs_event_t *hndl, const char *filename, int events, int status) {
FsEventHandle &fsEvent = *(static_cast<FsEventHandle *>(handle->data)); if(fs_event_handle &fsEvent = *(static_cast<fs_event_handle *>(hndl->data)); status) {
fsEvent.publish(error_event{status});
if(status) {
fsEvent.publish(ErrorEvent{status});
} else { } else {
fsEvent.publish(FsEventEvent{filename, static_cast<std::underlying_type_t<details::UVFsEvent>>(events)}); fsEvent.publish(fs_event_event{filename, details::uvw_fs_event(events)});
} }
} }
UVW_INLINE bool FsEventHandle::init() { UVW_INLINE int fs_event_handle::init() {
return initialize(&uv_fs_event_init); return leak_if(uv_fs_event_init(parent().raw(), raw()));
} }
UVW_INLINE void FsEventHandle::start(const std::string &path, Flags<Event> flags) { UVW_INLINE int fs_event_handle::start(const std::string &path, event_flags flags) {
invoke(&uv_fs_event_start, get(), &startCallback, path.data(), flags); return uv_fs_event_start(raw(), &start_callback, path.data(), static_cast<uv_fs_event_flags>(flags));
} }
UVW_INLINE void FsEventHandle::start(const std::string &path, FsEventHandle::Event flag) { UVW_INLINE int fs_event_handle::stop() {
start(std::move(path), Flags<Event>{flag}); return uv_fs_event_stop(raw());
} }
UVW_INLINE void FsEventHandle::stop() { UVW_INLINE std::string fs_event_handle::path() noexcept {
invoke(&uv_fs_event_stop, get()); return details::try_read(&uv_fs_event_getpath, raw());
}
UVW_INLINE std::string FsEventHandle::path() noexcept {
return details::tryRead(&uv_fs_event_getpath, get());
} }
} // namespace uvw } // namespace uvw

View File

@ -4,6 +4,8 @@
#include <string> #include <string>
#include <type_traits> #include <type_traits>
#include <uv.h> #include <uv.h>
#include "config.h"
#include "enum.hpp"
#include "handle.hpp" #include "handle.hpp"
#include "loop.h" #include "loop.h"
#include "util.h" #include "util.h"
@ -12,26 +14,23 @@ namespace uvw {
namespace details { namespace details {
enum class UVFsEventFlags : std::underlying_type_t<uv_fs_event_flags> { enum class uvw_fs_event_flags : std::underlying_type_t<uv_fs_event_flags> {
WATCH_ENTRY = UV_FS_EVENT_WATCH_ENTRY, WATCH_ENTRY = UV_FS_EVENT_WATCH_ENTRY,
STAT = UV_FS_EVENT_STAT, STAT = UV_FS_EVENT_STAT,
RECURSIVE = UV_FS_EVENT_RECURSIVE RECURSIVE = UV_FS_EVENT_RECURSIVE,
_UVW_ENUM = 0
}; };
enum class UVFsEvent : std::underlying_type_t<uv_fs_event> { enum class uvw_fs_event : std::underlying_type_t<uv_fs_event> {
RENAME = UV_RENAME, RENAME = UV_RENAME,
CHANGE = UV_CHANGE CHANGE = UV_CHANGE
}; };
} // namespace details } // namespace details
/** /*! @brief Fs event event. */
* @brief FsEventEvent event. struct fs_event_event {
* fs_event_event(const char *pathname, details::uvw_fs_event events);
* It will be emitted by FsEventHandle according with its functionalities.
*/
struct FsEventEvent {
FsEventEvent(const char *pathname, Flags<details::UVFsEvent> events);
/** /**
* @brief The path to the file being monitored. * @brief The path to the file being monitored.
@ -46,82 +45,64 @@ struct FsEventEvent {
* *
* Available flags are: * Available flags are:
* *
* * `FsEventHandle::Watch::RENAME` * * `fs_event_handle::watch::RENAME`
* * `FsEventHandle::Watch::CHANGE` * * `fs_event_handle::watch::CHANGE`
*/ */
Flags<details::UVFsEvent> flags; details::uvw_fs_event flags;
}; };
/** /**
* @brief The FsEventHandle handle. * @brief The fs event handle.
* *
* These handles allow the user to monitor a given path for changes, for * These handles allow the user to monitor a given path for changes, for
* example, if the file was renamed or there was a generic change in it. The * example, if the file was renamed or there was a generic change in it. The
* best backend for the job on each platform is chosen by the handle. * best backend for the job on each platform is chosen by the handle.
* *
* To create a `FsEventHandle` through a `Loop`, no arguments are required. * To create a `fs_event_handle` through a `loop`, no arguments are required.
* *
* See the official * See the official
* [documentation](http://docs.libuv.org/en/v1.x/fs_event.html) * [documentation](http://docs.libuv.org/en/v1.x/fs_event.html)
* for further details. * for further details.
*/ */
class FsEventHandle final: public Handle<FsEventHandle, uv_fs_event_t> { class fs_event_handle final: public handle<fs_event_handle, uv_fs_event_t, fs_event_event> {
static void startCallback(uv_fs_event_t *handle, const char *filename, int events, int status); static void start_callback(uv_fs_event_t *hndl, const char *filename, int events, int status);
public: public:
using Watch = details::UVFsEvent; using watch = details::uvw_fs_event;
using Event = details::UVFsEventFlags; using event_flags = details::uvw_fs_event_flags;
using Handle::Handle; using handle::handle;
/** /**
* @brief Initializes the handle. * @brief Initializes the handle.
* @return True in case of success, false otherwise. * @return Underlying return value.
*/ */
bool init(); int init() final;
/** /**
* @brief Starts watching the specified path. * @brief Starts watching the specified path.
* *
* It will watch the specified path for changes.<br/> * It will watch the specified path for changes.<br/>
* As soon as a change is observed, a FsEventEvent is emitted by the * As soon as a change is observed, a fs_event_event is emitted by the
* handle.<br> * handle.
* It could happen that ErrorEvent events are emitted while running.
* *
* Available flags are: * Available flags are:
* *
* * `FsEventHandle::Event::WATCH_ENTRY` * * `fs_event_handle::event_flags::WATCH_ENTRY`
* * `FsEventHandle::Event::STAT` * * `fs_event_handle::event_flags::STAT`
* * `FsEventHandle::Event::RECURSIVE` * * `fs_event_handle::event_flags::RECURSIVE`
* *
* @param path The file or directory to be monitored. * @param path The file or directory to be monitored.
* @param flags Additional flags to control the behavior. * @param flags Additional flags to control the behavior.
* @return Underlying return value.
*/ */
void start(const std::string &path, Flags<Event> flags = Flags<Event>{}); int start(const std::string &path, event_flags flags = event_flags::_UVW_ENUM);
/**
* @brief Starts watching the specified path.
*
* It will watch the specified path for changes.<br/>
* As soon as a change is observed, a FsEventEvent is emitted by the
* handle.<br>
* It could happen that ErrorEvent events are emitted while running.
*
* Available flags are:
*
* * `FsEventHandle::Event::WATCH_ENTRY`
* * `FsEventHandle::Event::STAT`
* * `FsEventHandle::Event::RECURSIVE`
*
* @param path The file or directory to be monitored.
* @param flag Additional flag to control the behavior.
*/
void start(const std::string &path, Event flag);
/** /**
* @brief Stops polling the file descriptor. * @brief Stops polling the file descriptor.
* @return Underlying return value.
*/ */
void stop(); int stop();
/** /**
* @brief Gets the path being monitored. * @brief Gets the path being monitored.

View File

@ -3,38 +3,35 @@
#endif #endif
#include <utility> #include <utility>
#include "config.h" #include "config.h"
namespace uvw { namespace uvw {
UVW_INLINE FsPollEvent::FsPollEvent(Stat previous, Stat current) noexcept UVW_INLINE fs_poll_event::fs_poll_event(file_info previous, file_info current) noexcept
: prev{std::move(previous)}, curr{std::move(current)} {} : prev{std::move(previous)}, curr{std::move(current)} {}
UVW_INLINE void FsPollHandle::startCallback(uv_fs_poll_t *handle, int status, const uv_stat_t *prev, const uv_stat_t *curr) { UVW_INLINE void fs_poll_handle::start_callback(uv_fs_poll_t *hndl, int status, const uv_stat_t *prev, const uv_stat_t *curr) {
FsPollHandle &fsPoll = *(static_cast<FsPollHandle *>(handle->data)); if(fs_poll_handle &fsPoll = *(static_cast<fs_poll_handle *>(hndl->data)); status) {
fsPoll.publish(error_event{status});
if(status) {
fsPoll.publish(ErrorEvent{status});
} else { } else {
fsPoll.publish(FsPollEvent{*prev, *curr}); fsPoll.publish(fs_poll_event{*prev, *curr});
} }
} }
UVW_INLINE bool FsPollHandle::init() { UVW_INLINE int fs_poll_handle::init() {
return initialize(&uv_fs_poll_init); return leak_if(uv_fs_poll_init(parent().raw(), raw()));
} }
UVW_INLINE void FsPollHandle::start(const std::string &file, FsPollHandle::Time interval) { UVW_INLINE int fs_poll_handle::start(const std::string &file, fs_poll_handle::time interval) {
invoke(&uv_fs_poll_start, get(), &startCallback, file.data(), interval.count()); return uv_fs_poll_start(raw(), &start_callback, file.data(), interval.count());
} }
UVW_INLINE void FsPollHandle::stop() { UVW_INLINE int fs_poll_handle::stop() {
invoke(&uv_fs_poll_stop, get()); return uv_fs_poll_stop(raw());
} }
UVW_INLINE std::string FsPollHandle::path() noexcept { UVW_INLINE std::string fs_poll_handle::path() noexcept {
return details::tryRead(&uv_fs_poll_getpath, get()); return details::try_read(&uv_fs_poll_getpath, raw());
} }
} // namespace uvw } // namespace uvw

View File

@ -4,61 +4,60 @@
#include <chrono> #include <chrono>
#include <string> #include <string>
#include <uv.h> #include <uv.h>
#include "config.h"
#include "handle.hpp" #include "handle.hpp"
#include "loop.h" #include "loop.h"
#include "util.h" #include "util.h"
namespace uvw { namespace uvw {
/** /*! @brief Fs pos event. */
* @brief FsPollEvent event. struct fs_poll_event {
* explicit fs_poll_event(file_info previous, file_info current) noexcept;
* It will be emitted by FsPollHandle according with its functionalities.
*/
struct FsPollEvent {
explicit FsPollEvent(Stat previous, Stat current) noexcept;
Stat prev; /*!< The old Stat struct. */ file_info prev; /*!< The old file_info struct. */
Stat curr; /*!< The new Stat struct. */ file_info curr; /*!< The new file_info struct. */
}; };
/** /**
* @brief The FsPollHandle handle. * @brief The fs poll handle.
* *
* It allows the user to monitor a given path for changes. Unlike FsEventHandle * It allows users to monitor a given path for changes. Unlike fs_event_handle,
* handles, FsPollHandle handles use stat to detect when a file has changed so * fs_poll_handle uses stat to detect when a file has changed so it can work on
* they can work on file systems where FsEventHandle handles cant. * file systems where fs_event_handle handles cant.
* *
* To create a `FsPollHandle` through a `Loop`, no arguments are required. * To create a `fs_poll_handle` through a `loop`, no arguments are required.
*/ */
class FsPollHandle final: public Handle<FsPollHandle, uv_fs_poll_t> { class fs_poll_handle final: public handle<fs_poll_handle, uv_fs_poll_t, fs_poll_event> {
static void startCallback(uv_fs_poll_t *handle, int status, const uv_stat_t *prev, const uv_stat_t *curr); static void start_callback(uv_fs_poll_t *hndl, int status, const uv_stat_t *prev, const uv_stat_t *curr);
public: public:
using Time = std::chrono::duration<unsigned int, std::milli>; using time = std::chrono::duration<unsigned int, std::milli>;
using Handle::Handle; using handle::handle;
/** /**
* @brief Initializes the handle. * @brief Initializes the handle.
* @return True in case of success, false otherwise. * @return Underlying return value.
*/ */
bool init(); int init() final;
/** /**
* @brief Starts the handle. * @brief Starts the handle.
* *
* The handle will start emitting FsPollEvent when needed. * The handle will start emitting fs_poll_event when needed.
* *
* @param file The path to the file to be checked. * @param file The path to the file to be checked.
* @param interval Milliseconds between successive checks. * @param interval Milliseconds between successive checks.
* @return Underlying return value.
*/ */
void start(const std::string &file, Time interval); int start(const std::string &file, time interval);
/** /**
* @brief Stops the handle. * @brief Stops the handle.
* @return Underlying return value.
*/ */
void stop(); int stop();
/** /**
* @brief Gets the path being monitored by the handle. * @brief Gets the path being monitored by the handle.

View File

@ -5,59 +5,40 @@
#include <memory> #include <memory>
#include <utility> #include <utility>
#include <uv.h> #include <uv.h>
#include "config.h"
#include "resource.hpp" #include "resource.hpp"
#include "util.h" #include "util.h"
namespace uvw { namespace uvw {
/** /*! @brief Close event. */
* @brief CloseEvent event. struct close_event {};
*
* It will be emitted by the handles according with their functionalities.
*/
struct CloseEvent {};
/** /**
* @brief Handle base class. * @brief Handle base class.
* *
* Base type for all `uvw` handle types. * Base type for all `uvw` handle types.
*/ */
template<typename T, typename U> template<typename T, typename U, typename... E>
class Handle: public Resource<T, U> { class handle: public resource<T, U, close_event, E...> {
protected: protected:
static void closeCallback(uv_handle_t *handle) { static void close_callback(uv_handle_t *hndl) {
Handle<T, U> &ref = *(static_cast<T *>(handle->data)); handle<T, U, E...> &ref = *(static_cast<T *>(hndl->data));
[[maybe_unused]] auto ptr = ref.shared_from_this(); [[maybe_unused]] auto ptr = ref.shared_from_this();
ref.reset(); ref.self_reset();
ref.publish(CloseEvent{}); ref.publish(close_event{});
} }
static void allocCallback(uv_handle_t *, std::size_t suggested, uv_buf_t *buf) { uv_handle_t *as_uv_handle() {
auto size = static_cast<unsigned int>(suggested); return reinterpret_cast<uv_handle_t *>(this->raw());
*buf = uv_buf_init(new char[size], size);
} }
template<typename F, typename... Args> const uv_handle_t *as_uv_handle() const {
bool initialize(F &&f, Args &&...args) { return reinterpret_cast<const uv_handle_t *>(this->raw());
if(!this->self()) {
if(auto err = std::forward<F>(f)(this->parent(), this->get(), std::forward<Args>(args)...); err) {
this->publish(ErrorEvent{err});
} else {
this->leak();
}
}
return this->self();
}
template<typename F, typename... Args>
void invoke(F &&f, Args &&...args) {
auto err = std::forward<F>(f)(std::forward<Args>(args)...);
if(err) { Emitter<T>::publish(ErrorEvent{err}); }
} }
public: public:
using Resource<T, U>::Resource; using resource<T, U, close_event, E...>::resource;
/** /**
* @brief Gets the category of the handle. * @brief Gets the category of the handle.
@ -68,8 +49,8 @@ public:
* *
* @return The actual category of the handle. * @return The actual category of the handle.
*/ */
HandleCategory category() const noexcept { handle_category category() const noexcept {
return HandleCategory{this->template get<uv_handle_t>()->type}; return handle_category{as_uv_handle()->type};
} }
/** /**
@ -77,12 +58,12 @@ public:
* *
* A base handle offers no functionality to promote it to the actual handle * A base handle offers no functionality to promote it to the actual handle
* type. By means of this function, the type of the underlying handle as * type. By means of this function, the type of the underlying handle as
* specified by HandleType is made available to the users. * specified by handle_type is made available to the users.
* *
* @return The actual type of the handle. * @return The actual type of the handle.
*/ */
HandleType type() const noexcept { handle_type type() const noexcept {
return Utilities::guessHandle(category()); return utilities::guess_handle(category());
} }
/** /**
@ -90,22 +71,22 @@ public:
* *
* What _active_ means depends on the type of handle: * What _active_ means depends on the type of handle:
* *
* * An AsyncHandle handle is always active and cannot be deactivated, * * An async_handle handle is always active and cannot be deactivated,
* except by closing it with uv_close(). * except by closing it with uv_close().
* * A PipeHandle, TCPHandle, UDPHandle, etc. handle - basically any handle * * A pipe, tcp, udp, etc. handle - basically any handle that deals with
* that deals with I/O - is active when it is doing something that involves * I/O - is active when it is doing something that involves I/O, like
* I/O, like reading, writing, connecting, accepting new connections, etc. * reading, writing, connecting, accepting new connections, etc.
* * A CheckHandle, IdleHandle, TimerHandle, etc. handle is active when it * * A check, idle, timer, etc. handle is active when it has been started
* has been started with a call to `start()`. * with a call to `start()`.
* *
* Rule of thumb: if a handle of type `FooHandle` has a `start()` member * Rule of thumb: if a handle of type `foo_handle` has a `start()` member
* method, then its active from the moment that method is called. Likewise, * method, then its active from the moment that method is called. Likewise,
* `stop()` deactivates the handle again. * `stop()` deactivates the handle again.
* *
* @return True if the handle is active, false otherwise. * @return True if the handle is active, false otherwise.
*/ */
bool active() const noexcept { bool active() const noexcept {
return !(uv_is_active(this->template get<uv_handle_t>()) == 0); return !!uv_is_active(as_uv_handle());
} }
/** /**
@ -117,21 +98,20 @@ public:
* @return True if the handle is closing or closed, false otherwise. * @return True if the handle is closing or closed, false otherwise.
*/ */
bool closing() const noexcept { bool closing() const noexcept {
return !(uv_is_closing(this->template get<uv_handle_t>()) == 0); return !!uv_is_closing(as_uv_handle());
} }
/** /**
* @brief Request handle to be closed. * @brief Request handle to be closed.
* *
* This **must** be called on each handle before memory is released.<br/> * This **must** be called on each handle before memory is released.<br/>
* In-progress requests are cancelled and this can result in an ErrorEvent * In-progress requests are cancelled and this can result in errors.
* emitted.
* *
* The handle will emit a CloseEvent when finished. * The handle will emit a close event when finished.
*/ */
void close() noexcept { void close() noexcept {
if(!closing()) { if(!closing()) {
uv_close(this->template get<uv_handle_t>(), &Handle<T, U>::closeCallback); uv_close(as_uv_handle(), &handle<T, U, E...>::close_callback);
} }
} }
@ -142,7 +122,7 @@ public:
* calling this function again will have no effect. * calling this function again will have no effect.
*/ */
void reference() noexcept { void reference() noexcept {
uv_ref(this->template get<uv_handle_t>()); uv_ref(as_uv_handle());
} }
/** /**
@ -152,7 +132,7 @@ public:
* this function again will have no effect. * this function again will have no effect.
*/ */
void unreference() noexcept { void unreference() noexcept {
uv_unref(this->template get<uv_handle_t>()); uv_unref(as_uv_handle());
} }
/** /**
@ -160,7 +140,7 @@ public:
* @return True if the handle referenced, false otherwise. * @return True if the handle referenced, false otherwise.
*/ */
bool referenced() const noexcept { bool referenced() const noexcept {
return !(uv_has_ref(this->template get<uv_handle_t>()) == 0); return !!uv_has_ref(as_uv_handle());
} }
/** /**
@ -168,7 +148,7 @@ public:
* @return The size of the underlying handle type. * @return The size of the underlying handle type.
*/ */
std::size_t size() const noexcept { std::size_t size() const noexcept {
return uv_handle_size(this->template get<uv_handle_t>()->type); return uv_handle_size(as_uv_handle()->type);
} }
/** /**
@ -176,16 +156,17 @@ public:
* *
* Gets the size of the send buffer that the operating system uses for the * Gets the size of the send buffer that the operating system uses for the
* socket.<br/> * socket.<br/>
* This function works for TCPHandle, PipeHandle and UDPHandle handles on * This function works for tcp, pipeand udp handles on Unix and for tcp and
* Unix and for TCPHandle and UDPHandle handles on Windows.<br/> * udp handles on Windows.<br/>
* Note that Linux will return double the size of the original set value. * Note that Linux will return double the size of the original set value.
* *
* @return The size of the send buffer, 0 in case of errors. * @return The size of the send buffer, the underlying return value in case
* of errors.
*/ */
int sendBufferSize() { int send_buffer_size() {
int value = 0; int value = 0;
auto err = uv_send_buffer_size(this->template get<uv_handle_t>(), &value); auto err = uv_send_buffer_size(as_uv_handle(), &value);
return err ? 0 : value; return err ? err : value;
} }
/** /**
@ -193,14 +174,14 @@ public:
* *
* Sets the size of the send buffer that the operating system uses for the * Sets the size of the send buffer that the operating system uses for the
* socket.<br/> * socket.<br/>
* This function works for TCPHandle, PipeHandle and UDPHandle handles on * This function works for tcp, pipe and udp handles on Unix and for tcp and
* Unix and for TCPHandle and UDPHandle handles on Windows.<br/> * udp handles on Windows.<br/>
* Note that Linux will set double the size. * Note that Linux will set double the size.
* *
* @return True in case of success, false otherwise. * @return Underlying return value.
*/ */
bool sendBufferSize(int value) { int send_buffer_size(int value) {
return (0 == uv_send_buffer_size(this->template get<uv_handle_t>(), &value)); return uv_send_buffer_size(as_uv_handle(), &value);
} }
/** /**
@ -208,16 +189,17 @@ public:
* *
* Gets the size of the receive buffer that the operating system uses for * Gets the size of the receive buffer that the operating system uses for
* the socket.<br/> * the socket.<br/>
* This function works for TCPHandle, PipeHandle and UDPHandle handles on * This function works for tcp, pipe and udp handles on Unix and for tcp and
* Unix and for TCPHandle and UDPHandle handles on Windows.<br/> * udp handles on Windows.<br/>
* Note that Linux will return double the size of the original set value. * Note that Linux will return double the size of the original set value.
* *
* @return The size of the receive buffer, 0 in case of errors. * @return The size of the receive buffer, the underlying return value in
* case of errors.
*/ */
int recvBufferSize() { int recv_buffer_size() {
int value = 0; int value = 0;
auto err = uv_recv_buffer_size(this->template get<uv_handle_t>(), &value); auto err = uv_recv_buffer_size(as_uv_handle(), &value);
return err ? 0 : value; return err ? err : value;
} }
/** /**
@ -225,14 +207,14 @@ public:
* *
* Sets the size of the receive buffer that the operating system uses for * Sets the size of the receive buffer that the operating system uses for
* the socket.<br/> * the socket.<br/>
* This function works for TCPHandle, PipeHandle and UDPHandle handles on * This function works for tcp, pipe and udp handles on Unix and for tcp and
* Unix and for TCPHandle and UDPHandle handles on Windows.<br/> * udp handles on Windows.<br/>
* Note that Linux will set double the size. * Note that Linux will set double the size.
* *
* @return True in case of success, false otherwise. * @return Underlying return value.
*/ */
bool recvBufferSize(int value) { int recv_buffer_size(int value) {
return (0 == uv_recv_buffer_size(this->template get<uv_handle_t>(), &value)); return uv_recv_buffer_size(as_uv_handle(), &value);
} }
/** /**
@ -240,15 +222,14 @@ public:
* *
* Supported handles: * Supported handles:
* *
* * TCPHandle * * tcp_handle
* * PipeHandle * * pipe_handle
* * TTYHandle * * tty_handle
* * UDPHandle * * udp_handle
* * PollHandle * * poll_handle
* *
* It will emit an ErrorEvent event if invoked on any other handle.<br/> * If invoked on a different handle, one that doesnt have an attached file
* If a handle doesnt have an attached file descriptor yet or the handle * descriptor yet or one which was closed, an invalid value is returned.
* itself has been closed, an ErrorEvent event will be emitted.
* *
* See the official * See the official
* [documentation](http://docs.libuv.org/en/v1.x/handle.html#c.uv_fileno) * [documentation](http://docs.libuv.org/en/v1.x/handle.html#c.uv_fileno)
@ -257,9 +238,9 @@ public:
* @return The file descriptor attached to the hande or a negative value in * @return The file descriptor attached to the hande or a negative value in
* case of errors. * case of errors.
*/ */
OSFileDescriptor fd() const { os_file_descriptor fd() const {
uv_os_fd_t fd; uv_os_fd_t fd;
uv_fileno(this->template get<uv_handle_t>(), &fd); uv_fileno(as_uv_handle(), &fd);
return fd; return fd;
} }
}; };

View File

@ -6,21 +6,21 @@
namespace uvw { namespace uvw {
UVW_INLINE void IdleHandle::startCallback(uv_idle_t *handle) { UVW_INLINE void idle_handle::start_callback(uv_idle_t *hndl) {
IdleHandle &idle = *(static_cast<IdleHandle *>(handle->data)); idle_handle &idle = *(static_cast<idle_handle *>(hndl->data));
idle.publish(IdleEvent{}); idle.publish(idle_event{});
} }
UVW_INLINE bool IdleHandle::init() { UVW_INLINE int idle_handle::init() {
return initialize(&uv_idle_init); return leak_if(uv_idle_init(parent().raw(), raw()));
} }
UVW_INLINE void IdleHandle::start() { UVW_INLINE int idle_handle::start() {
invoke(&uv_idle_start, get(), &startCallback); return uv_idle_start(raw(), &start_callback);
} }
UVW_INLINE void IdleHandle::stop() { UVW_INLINE int idle_handle::stop() {
invoke(&uv_idle_stop, get()); return uv_idle_stop(raw());
} }
} // namespace uvw } // namespace uvw

View File

@ -7,18 +7,14 @@
namespace uvw { namespace uvw {
/** /*! @brief Idle event. */
* @brief IdleEvent event. struct idle_event {};
*
* It will be emitted by IdleHandle according with its functionalities.
*/
struct IdleEvent {};
/** /**
* @brief The IdleHandle handle. * @brief The idle handle.
* *
* Idle handles will emit a IdleEvent event once per loop iteration, right * Idle handles will emit a idle event once per loop iteration, right before the
* before the PrepareHandle handles. * prepare handles.
* *
* The notable difference with prepare handles is that when there are active * The notable difference with prepare handles is that when there are active
* idle handles, the loop will perform a zero timeout poll instead of blocking * idle handles, the loop will perform a zero timeout poll instead of blocking
@ -28,32 +24,36 @@ struct IdleEvent {};
* Despite the name, idle handles will emit events on every loop iteration, not * Despite the name, idle handles will emit events on every loop iteration, not
* when the loop is actually _idle_. * when the loop is actually _idle_.
* *
* To create an `IdleHandle` through a `Loop`, no arguments are required. * To create an `idle_handle` through a `loop`, no arguments are required.
*/ */
class IdleHandle final: public Handle<IdleHandle, uv_idle_t> { class idle_handle final: public handle<idle_handle, uv_idle_t, idle_event> {
static void startCallback(uv_idle_t *handle); static void start_callback(uv_idle_t *hndl);
public: public:
using Handle::Handle; using handle::handle;
/** /**
* @brief Initializes the handle. * @brief Initializes the handle.
* @return True in case of success, false otherwise. * @return Underlying return value.
*/ */
bool init(); int init() final;
/** /**
* @brief Starts the handle. * @brief Starts the handle.
* *
* A IdleEvent event will be emitted once per loop iteration, right before * An idle event will be emitted once per loop iteration, right before
* polling the PrepareHandle handles. * polling the prepare handles.
*
* @return Underlying return value.
*/ */
void start(); int start();
/** /**
* @brief Stops the handle. * @brief Stops the handle.
*
* @return Underlying return value.
*/ */
void stop(); int stop();
}; };
} // namespace uvw } // namespace uvw

View File

@ -3,26 +3,25 @@
#endif #endif
#include <utility> #include <utility>
#include "config.h" #include "config.h"
namespace uvw { namespace uvw {
UVW_INLINE SharedLib::SharedLib(UnderlyingType<SharedLib, uv_lib_t>::ConstructorAccess ca, std::shared_ptr<Loop> ref, const std::string &filename) noexcept UVW_INLINE shared_lib::shared_lib(loop::token token, std::shared_ptr<loop> ref, const std::string &filename) noexcept
: UnderlyingType{ca, std::move(ref)} { : uv_type{token, std::move(ref)} {
opened = (0 == uv_dlopen(filename.data(), get())); opened = (0 == uv_dlopen(filename.data(), raw()));
} }
UVW_INLINE SharedLib::~SharedLib() noexcept { UVW_INLINE shared_lib::~shared_lib() noexcept {
uv_dlclose(get()); uv_dlclose(raw());
} }
UVW_INLINE SharedLib::operator bool() const noexcept { UVW_INLINE shared_lib::operator bool() const noexcept {
return opened; return opened;
} }
UVW_INLINE const char *SharedLib::error() const noexcept { UVW_INLINE const char *shared_lib::error() const noexcept {
return uv_dlerror(get()); return uv_dlerror(raw());
} }
} // namespace uvw } // namespace uvw

View File

@ -5,22 +5,23 @@
#include <string> #include <string>
#include <type_traits> #include <type_traits>
#include <uv.h> #include <uv.h>
#include "config.h"
#include "loop.h" #include "loop.h"
#include "underlying_type.hpp" #include "uv_type.hpp"
namespace uvw { namespace uvw {
/** /**
* @brief The SharedLib class. * @brief The shared lib class.
* *
* `uvw` provides cross platform utilities for loading shared libraries and * `uvw` provides cross platform utilities for loading shared libraries and
* retrieving symbols from them, by means of the API offered by `libuv`. * retrieving symbols from them, by means of the API offered by `libuv`.
*/ */
class SharedLib final: public UnderlyingType<SharedLib, uv_lib_t> { class shared_lib final: public uv_type<uv_lib_t> {
public: public:
explicit SharedLib(ConstructorAccess ca, std::shared_ptr<Loop> ref, const std::string &filename) noexcept; explicit shared_lib(loop::token token, std::shared_ptr<loop> ref, const std::string &filename) noexcept;
~SharedLib() noexcept; ~shared_lib() noexcept;
/** /**
* @brief Checks if the library has been correctly opened. * @brief Checks if the library has been correctly opened.
@ -41,7 +42,7 @@ public:
F *sym(const std::string &name) { F *sym(const std::string &name) {
static_assert(std::is_function_v<F>); static_assert(std::is_function_v<F>);
F *func; F *func;
auto err = uv_dlsym(get(), name.data(), reinterpret_cast<void **>(&func)); auto err = uv_dlsym(raw(), name.data(), reinterpret_cast<void **>(&func));
if(err) { func = nullptr; } if(err) { func = nullptr; }
return func; return func;
} }

View File

@ -6,120 +6,110 @@
namespace uvw { namespace uvw {
UVW_INLINE Loop::Loop(std::unique_ptr<uv_loop_t, Deleter> ptr) noexcept UVW_INLINE loop::loop(std::unique_ptr<uv_loop_t, deleter> ptr) noexcept
: loop{std::move(ptr)} {} : uv_loop{std::move(ptr)} {}
UVW_INLINE std::shared_ptr<Loop> Loop::create() { UVW_INLINE std::shared_ptr<loop> loop::create() {
auto ptr = std::unique_ptr<uv_loop_t, Deleter>{new uv_loop_t, [](uv_loop_t *l) { auto ptr = std::unique_ptr<uv_loop_t, deleter>{new uv_loop_t, [](uv_loop_t *l) { delete l; }};
delete l; auto curr = std::shared_ptr<loop>{new loop{std::move(ptr)}};
}};
auto loop = std::shared_ptr<Loop>{new Loop{std::move(ptr)}}; if(uv_loop_init(curr->uv_loop.get())) {
curr = nullptr;
if(uv_loop_init(loop->loop.get())) {
loop = nullptr;
} }
return loop; return curr;
} }
UVW_INLINE std::shared_ptr<Loop> Loop::create(uv_loop_t *loop) { UVW_INLINE std::shared_ptr<loop> loop::create(uv_loop_t *res) {
auto ptr = std::unique_ptr<uv_loop_t, Deleter>{loop, [](uv_loop_t *) {}}; auto ptr = std::unique_ptr<uv_loop_t, deleter>{res, [](uv_loop_t *) {}};
return std::shared_ptr<Loop>{new Loop{std::move(ptr)}}; return std::shared_ptr<loop>{new loop{std::move(ptr)}};
} }
UVW_INLINE std::shared_ptr<Loop> Loop::getDefault() { UVW_INLINE std::shared_ptr<loop> loop::get_default() {
static std::weak_ptr<Loop> ref; static std::weak_ptr<loop> ref;
std::shared_ptr<Loop> loop; std::shared_ptr<loop> curr;
if(ref.expired()) { if(ref.expired()) {
auto def = uv_default_loop(); auto def = uv_default_loop();
if(def) { if(def) {
auto ptr = std::unique_ptr<uv_loop_t, Deleter>(def, [](uv_loop_t *) {}); auto ptr = std::unique_ptr<uv_loop_t, deleter>(def, [](uv_loop_t *) {});
loop = std::shared_ptr<Loop>{new Loop{std::move(ptr)}}; curr = std::shared_ptr<loop>{new loop{std::move(ptr)}};
} }
ref = loop; ref = curr;
} else { } else {
loop = ref.lock(); curr = ref.lock();
} }
return loop; return curr;
} }
UVW_INLINE Loop::~Loop() noexcept { UVW_INLINE loop::~loop() noexcept {
if(loop) { if(uv_loop) {
close(); close();
} }
} }
UVW_INLINE void Loop::close() { UVW_INLINE int loop::close() {
auto err = uv_loop_close(loop.get()); int ret = 0;
return err ? publish(ErrorEvent{err}) : loop.reset();
}
template<Loop::Mode mode> if(uv_loop) {
bool Loop::run() noexcept { ret = uv_loop_close(uv_loop.get());
auto utm = static_cast<std::underlying_type_t<Mode>>(mode); uv_loop.reset();
auto uvrm = static_cast<uv_run_mode>(utm);
return (uv_run(loop.get(), uvrm) == 0);
}
UVW_INLINE bool Loop::alive() const noexcept {
return !(uv_loop_alive(loop.get()) == 0);
}
UVW_INLINE void Loop::stop() noexcept {
uv_stop(loop.get());
}
UVW_INLINE int Loop::descriptor() const noexcept {
return uv_backend_fd(loop.get());
}
UVW_INLINE std::pair<bool, Loop::Time> Loop::timeout() const noexcept {
auto to = uv_backend_timeout(loop.get());
return std::make_pair(to == -1, Time{to});
}
UVW_INLINE Loop::Time Loop::idleTime() const noexcept {
return Time{uv_metrics_idle_time(loop.get())};
}
UVW_INLINE Loop::Time Loop::now() const noexcept {
return Time{uv_now(loop.get())};
}
UVW_INLINE void Loop::update() const noexcept {
return uv_update_time(loop.get());
}
UVW_INLINE void Loop::fork() noexcept {
auto err = uv_loop_fork(loop.get());
if(err) {
publish(ErrorEvent{err});
} }
return ret;
} }
UVW_INLINE void Loop::data(std::shared_ptr<void> uData) { int loop::run(run_mode mode) noexcept {
userData = std::move(uData); return uv_run(uv_loop.get(), static_cast<uv_run_mode>(mode));
} }
UVW_INLINE const uv_loop_t *Loop::raw() const noexcept { UVW_INLINE bool loop::alive() const noexcept {
return loop.get(); return !!uv_loop_alive(uv_loop.get());
} }
UVW_INLINE uv_loop_t *Loop::raw() noexcept { UVW_INLINE void loop::stop() noexcept {
return const_cast<uv_loop_t *>(const_cast<const Loop *>(this)->raw()); uv_stop(uv_loop.get());
} }
// explicit instantiations UVW_INLINE int loop::descriptor() const noexcept {
#ifdef UVW_AS_LIB return uv_backend_fd(uv_loop.get());
template bool Loop::run<Loop::Mode::DEFAULT>() noexcept; }
template bool Loop::run<Loop::Mode::ONCE>() noexcept;
template bool Loop::run<Loop::Mode::NOWAIT>() noexcept; UVW_INLINE std::pair<bool, loop::time> loop::timeout() const noexcept {
#endif // UVW_AS_LIB auto to = uv_backend_timeout(uv_loop.get());
return std::make_pair(to == -1, time{to});
}
UVW_INLINE loop::time loop::idle_time() const noexcept {
return time{uv_metrics_idle_time(uv_loop.get())};
}
UVW_INLINE loop::time loop::now() const noexcept {
return time{uv_now(uv_loop.get())};
}
UVW_INLINE void loop::update() const noexcept {
return uv_update_time(uv_loop.get());
}
UVW_INLINE int loop::fork() noexcept {
return uv_loop_fork(uv_loop.get());
}
UVW_INLINE void loop::data(std::shared_ptr<void> ud) {
user_data = std::move(ud);
}
UVW_INLINE const uv_loop_t *loop::raw() const noexcept {
return uv_loop.get();
}
UVW_INLINE uv_loop_t *loop::raw() noexcept {
return const_cast<uv_loop_t *>(const_cast<const loop *>(this)->raw());
}
} // namespace uvw } // namespace uvw

View File

@ -11,34 +11,35 @@
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include <uv.h> #include <uv.h>
#include "config.h"
#include "emitter.h" #include "emitter.h"
#include "util.h" #include "util.h"
namespace uvw { namespace uvw {
class AsyncHandle; class async_handle;
class CheckHandle; class check_handle;
class FsEventHandle; class fs_event_handle;
class FsPollHandle; class fs_poll_handle;
class IdleHandle; class idle_handle;
class PipeHandle; class pipe_handle;
class PollHandle; class poll_handle;
class PrepareHandle; class prepare_handle;
class ProcessHandle; class process_handle;
class SignalHandle; class signal_handle;
class TCPHandle; class tcp_handle;
class TimerHandle; class timer_handle;
class TTYHandle; class tty_handle;
class UDPHandle; class udp_handle;
namespace details { namespace details {
enum class UVLoopOption : std::underlying_type_t<uv_loop_option> { enum class uvw_loop_option : std::underlying_type_t<uv_loop_option> {
BLOCK_SIGNAL = UV_LOOP_BLOCK_SIGNAL, BLOCK_SIGNAL = UV_LOOP_BLOCK_SIGNAL,
IDLE_TIME = UV_METRICS_IDLE_TIME IDLE_TIME = UV_METRICS_IDLE_TIME
}; };
enum class UVRunMode : std::underlying_type_t<uv_run_mode> { enum class uvw_run_mode : std::underlying_type_t<uv_run_mode> {
DEFAULT = UV_RUN_DEFAULT, DEFAULT = UV_RUN_DEFAULT,
ONCE = UV_RUN_ONCE, ONCE = UV_RUN_ONCE,
NOWAIT = UV_RUN_NOWAIT NOWAIT = UV_RUN_NOWAIT
@ -47,55 +48,49 @@ enum class UVRunMode : std::underlying_type_t<uv_run_mode> {
} // namespace details } // namespace details
/** /**
* @brief The Loop class. * @brief The loop class.
* *
* The event loop is the central part of `uvw`'s functionalities, as well as * The event loop is the central part of `uvw`'s functionalities, as well as
* `libuv`'s ones.<br/> * `libuv`'s ones.<br/>
* It takes care of polling for I/O and scheduling callbacks to be run based on * It takes care of polling for I/O and scheduling callbacks to be run based on
* different sources of events. * different sources of events.
*/ */
class Loop final: public Emitter<Loop>, public std::enable_shared_from_this<Loop> { class loop final: public emitter<loop>, public std::enable_shared_from_this<loop> {
using Deleter = void (*)(uv_loop_t *); using deleter = void (*)(uv_loop_t *);
template<typename, typename> template<typename, typename, typename...>
friend class Resource; friend class resource;
template<typename R, typename... Args> class uv_token {
auto create_resource(int, Args &&...args) -> decltype(std::declval<R>().init(), std::shared_ptr<R>{}) { friend class loop;
auto ptr = R::create(shared_from_this(), std::forward<Args>(args)...); explicit uv_token(int) {}
ptr = ptr->init() ? ptr : nullptr; };
return ptr;
}
template<typename R, typename... Args> loop(std::unique_ptr<uv_loop_t, deleter> ptr) noexcept;
std::shared_ptr<R> create_resource(char, Args &&...args) {
return R::create(shared_from_this(), std::forward<Args>(args)...);
}
Loop(std::unique_ptr<uv_loop_t, Deleter> ptr) noexcept;
public: public:
using Time = std::chrono::duration<uint64_t, std::milli>; using token = uv_token;
using Configure = details::UVLoopOption; using time = std::chrono::duration<uint64_t, std::milli>;
using Mode = details::UVRunMode; using option = details::uvw_loop_option;
using run_mode = details::uvw_run_mode;
/** /**
* @brief Initializes a new Loop instance. * @brief Initializes a new loop instance.
* @return A pointer to the newly created loop. * @return A pointer to the newly created loop.
*/ */
static std::shared_ptr<Loop> create(); static std::shared_ptr<loop> create();
/** /**
* @brief Initializes a new Loop instance from an existing resource. * @brief Initializes a new loop instance from an existing resource.
* *
* The lifetime of the resource must exceed that of the instance to which * The lifetime of the resource must exceed that of the instance to which
* it's associated. Management of the memory associated with the resource is * it's associated. Management of the memory associated with the resource is
* in charge of the user. * in charge of the user.
* *
* @param loop A valid pointer to a correctly initialized resource. * @param res A valid pointer to a correctly initialized resource.
* @return A pointer to the newly created loop. * @return A pointer to the newly created loop.
*/ */
static std::shared_ptr<Loop> create(uv_loop_t *loop); static std::shared_ptr<loop> create(uv_loop_t *res);
/** /**
* @brief Gets the initialized default loop. * @brief Gets the initialized default loop.
@ -109,15 +104,15 @@ public:
* *
* @return The initialized default loop. * @return The initialized default loop.
*/ */
static std::shared_ptr<Loop> getDefault(); static std::shared_ptr<loop> get_default();
Loop(const Loop &) = delete; loop(const loop &) = delete;
Loop(Loop &&other) = delete; loop(loop &&other) = delete;
Loop &operator=(const Loop &) = delete; loop &operator=(const loop &) = delete;
Loop &operator=(Loop &&other) = delete; loop &operator=(loop &&other) = delete;
~Loop() noexcept; ~loop() noexcept;
/** /**
* @brief Sets additional loop options. * @brief Sets additional loop options.
@ -126,23 +121,21 @@ public:
* mentioned otherwise.<br/> * mentioned otherwise.<br/>
* Supported options: * Supported options:
* *
* * `Loop::Configure::BLOCK_SIGNAL`: Block a signal when polling for new * * `loop::option::BLOCK_SIGNAL`: Block a signal when polling for new
* events. A second argument is required and it is the signal number. * events. A second argument is required and it is the signal number.
* * `Loop::Configure::IDLE_TIME`: Accumulate the amount of idle time the * * `loop::option::IDLE_TIME`: Accumulate the amount of idle time the event
* event loop spends in the event provider. This option is necessary to use * loop spends in the event provider. This option is necessary to use
* `idleTime()`. * `idle_time()`.
*
* An ErrorEvent will be emitted in case of errors.
* *
* See the official * See the official
* [documentation](http://docs.libuv.org/en/v1.x/loop.html#c.uv_loop_configure) * [documentation](http://docs.libuv.org/en/v1.x/loop.html#c.uv_loop_configure)
* for further details. * for further details.
*
* @return Underlying return value.
*/ */
template<typename... Args> template<typename... Args>
void configure(Configure flag, Args &&...args) { int configure(option flag, Args &&...args) {
auto option = static_cast<std::underlying_type_t<Configure>>(flag); return uv_loop_configure(uv_loop.get(), static_cast<uv_loop_option>(flag), std::forward<Args>(args)...);
auto err = uv_loop_configure(loop.get(), static_cast<uv_loop_option>(option), std::forward<Args>(args)...);
if(err) { publish(ErrorEvent{err}); }
} }
/** /**
@ -151,45 +144,55 @@ public:
* This should be used as a default method to create resources.<br/> * This should be used as a default method to create resources.<br/>
* The arguments are the ones required for the specific resource. * The arguments are the ones required for the specific resource.
* *
* Use it as `loop->resource<uvw::TimerHandle>()`. * Use it as `loop->resource<uvw::timer_handle>()`.
* *
* @return A pointer to the newly created resource. * @return A pointer to the newly created resource.
*/ */
template<typename R, typename... Args> template<typename R, typename... Args>
std::shared_ptr<R> resource(Args &&...args) { std::shared_ptr<R> resource(Args &&...args) {
return create_resource<R>(0, std::forward<Args>(args)...); auto ptr = uninitialized_resource<R>(std::forward<Args>(args)...);
ptr = (ptr->init() == 0) ? ptr : nullptr;
return ptr;
}
/**
* @brief Creates uninitialized resources of any type.
* @return A pointer to the newly created resource.
*/
template<typename R, typename... Args>
std::shared_ptr<R> uninitialized_resource(Args &&...args) {
return std::make_shared<R>(token{0}, shared_from_this(), std::forward<Args>(args)...);
} }
/** /**
* @brief Releases all internal loop resources. * @brief Releases all internal loop resources.
* *
* Call this function only when the loop has finished executing and all open * Call this function only when the loop has finished executing and all open
* handles and requests have been closed, or the loop will emit an error. * handles and requests have been closed, or the loop will error.
* *
* An ErrorEvent will be emitted in case of errors. * @return Underlying return value.
*/ */
void close(); int close();
/** /**
* @brief Runs the event loop. * @brief Runs the event loop.
* *
* Available modes are: * Available modes are:
* *
* * `Loop::Mode::DEFAULT`: Runs the event loop until there are no more * * `loop::run_mode::DEFAULT`: Runs the event loop until there are no more
* active and referenced handles or requests. * active and referenced handles or requests.
* * `Loop::Mode::ONCE`: Poll for i/o once. Note that this function blocks * * `loop::run_mode::ONCE`: Poll for i/o once. Note that this function
* if there are no pending callbacks. * blocks if there are no pending callbacks.
* * `Loop::Mode::NOWAIT`: Poll for i/o once but dont block if there are no * * `loop::run_mode::NOWAIT`: Poll for i/o once but dont block if there
* pending callbacks. * are no pending callbacks.
* *
* See the official * See the official
* [documentation](http://docs.libuv.org/en/v1.x/loop.html#c.uv_run) * [documentation](http://docs.libuv.org/en/v1.x/loop.html#c.uv_run)
* for further details. * for further details.
* *
* @return True when done, false in all other cases. * @return Underlying return value.
*/ */
template<Mode mode = Mode::DEFAULT> int run(run_mode mode = run_mode::DEFAULT) noexcept;
bool run() noexcept;
/** /**
* @brief Checks if there are active resources. * @brief Checks if there are active resources.
@ -211,8 +214,8 @@ public:
* @brief Get backend file descriptor. * @brief Get backend file descriptor.
* *
* Only kqueue, epoll and event ports are supported.<br/> * Only kqueue, epoll and event ports are supported.<br/>
* This can be used in conjunction with `run<Loop::Mode::NOWAIT>()` to poll * This can be used in conjunction with `run(loop::run_mode::NOWAIT)` to
* in one thread and run the event loops callbacks in another. * poll in one thread and run the event loops callbacks in another.
* *
* @return The backend file descriptor. * @return The backend file descriptor.
*/ */
@ -224,14 +227,14 @@ public:
* * A boolean value that is true in case of valid timeout, false otherwise. * * A boolean value that is true in case of valid timeout, false otherwise.
* * Milliseconds (`std::chrono::duration<uint64_t, std::milli>`). * * Milliseconds (`std::chrono::duration<uint64_t, std::milli>`).
*/ */
std::pair<bool, Time> timeout() const noexcept; std::pair<bool, time> timeout() const noexcept;
/** /**
* @brief Returns the amount of time the event loop has been idle. The call * @brief Returns the amount of time the event loop has been idle. The call
* is thread safe. * is thread safe.
* @return The accumulated time spent idle. * @return The accumulated time spent idle.
*/ */
Time idleTime() const noexcept; time idle_time() const noexcept;
/** /**
* @brief Returns the current timestamp in milliseconds. * @brief Returns the current timestamp in milliseconds.
@ -245,7 +248,7 @@ public:
* @return The current timestamp in milliseconds (actual type is * @return The current timestamp in milliseconds (actual type is
* `std::chrono::duration<uint64_t, std::milli>`). * `std::chrono::duration<uint64_t, std::milli>`).
*/ */
Time now() const noexcept; time now() const noexcept;
/** /**
* @brief Updates the event loops concept of _now_. * @brief Updates the event loops concept of _now_.
@ -261,58 +264,58 @@ public:
/** /**
* @brief Walks the list of handles. * @brief Walks the list of handles.
* *
* The callback will be executed once for each handle that is still active. * The callback is invoked once for each handle that is still active.
* *
* @param callback A function to be invoked once for each active handle. * @param callback A function to invoke once for each active handle.
*/ */
template<typename Func> template<typename Func>
void walk(Func callback) { void walk(Func callback) {
auto func = [](uv_handle_t *handle, void *func) { auto func = [](uv_handle_t *hndl, void *func) {
if(handle->data) { if(hndl->data) {
auto &cb = *static_cast<Func *>(func); auto &cb = *static_cast<Func *>(func);
switch(Utilities::guessHandle(HandleCategory{handle->type})) { switch(utilities::guess_handle(handle_category{hndl->type})) {
case HandleType::ASYNC: case handle_type::ASYNC:
cb(*static_cast<AsyncHandle *>(handle->data)); cb(*static_cast<async_handle *>(hndl->data));
break; break;
case HandleType::CHECK: case handle_type::CHECK:
cb(*static_cast<CheckHandle *>(handle->data)); cb(*static_cast<check_handle *>(hndl->data));
break; break;
case HandleType::FS_EVENT: case handle_type::FS_EVENT:
cb(*static_cast<FsEventHandle *>(handle->data)); cb(*static_cast<fs_event_handle *>(hndl->data));
break; break;
case HandleType::FS_POLL: case handle_type::FS_POLL:
cb(*static_cast<FsPollHandle *>(handle->data)); cb(*static_cast<fs_poll_handle *>(hndl->data));
break; break;
case HandleType::IDLE: case handle_type::IDLE:
cb(*static_cast<IdleHandle *>(handle->data)); cb(*static_cast<idle_handle *>(hndl->data));
break; break;
case HandleType::PIPE: case handle_type::PIPE:
cb(*static_cast<PipeHandle *>(handle->data)); cb(*static_cast<pipe_handle *>(hndl->data));
break; break;
case HandleType::POLL: case handle_type::POLL:
cb(*static_cast<PollHandle *>(handle->data)); cb(*static_cast<poll_handle *>(hndl->data));
break; break;
case HandleType::PREPARE: case handle_type::PREPARE:
cb(*static_cast<PrepareHandle *>(handle->data)); cb(*static_cast<prepare_handle *>(hndl->data));
break; break;
case HandleType::PROCESS: case handle_type::PROCESS:
cb(*static_cast<ProcessHandle *>(handle->data)); cb(*static_cast<process_handle *>(hndl->data));
break; break;
case HandleType::SIGNAL: case handle_type::SIGNAL:
cb(*static_cast<SignalHandle *>(handle->data)); cb(*static_cast<signal_handle *>(hndl->data));
break; break;
case HandleType::TCP: case handle_type::TCP:
cb(*static_cast<TCPHandle *>(handle->data)); cb(*static_cast<tcp_handle *>(hndl->data));
break; break;
case HandleType::TIMER: case handle_type::TIMER:
cb(*static_cast<TimerHandle *>(handle->data)); cb(*static_cast<timer_handle *>(hndl->data));
break; break;
case HandleType::TTY: case handle_type::TTY:
cb(*static_cast<TTYHandle *>(handle->data)); cb(*static_cast<tty_handle *>(hndl->data));
break; break;
case HandleType::UDP: case handle_type::UDP:
cb(*static_cast<UDPHandle *>(handle->data)); cb(*static_cast<udp_handle *>(hndl->data));
break; break;
default: default:
// this handle isn't managed by uvw, let it be... // this handle isn't managed by uvw, let it be...
@ -321,7 +324,7 @@ public:
} }
}; };
uv_walk(loop.get(), func, &callback); uv_walk(uv_loop.get(), func, &callback);
} }
/** /**
@ -348,13 +351,13 @@ public:
* bugs, and is subject to change or removal. API and ABI stability is not * bugs, and is subject to change or removal. API and ABI stability is not
* guaranteed. * guaranteed.
* *
* An ErrorEvent will be emitted in case of errors.
*
* See the official * See the official
* [documentation](http://docs.libuv.org/en/v1.x/loop.html#c.uv_loop_fork) * [documentation](http://docs.libuv.org/en/v1.x/loop.html#c.uv_loop_fork)
* for further details. * for further details.
*
* @return Underlying return value.
*/ */
void fork() noexcept; int fork() noexcept;
/** /**
* @brief Gets user-defined data. `uvw` won't use this field in any case. * @brief Gets user-defined data. `uvw` won't use this field in any case.
@ -362,14 +365,14 @@ public:
*/ */
template<typename R = void> template<typename R = void>
std::shared_ptr<R> data() const { std::shared_ptr<R> data() const {
return std::static_pointer_cast<R>(userData); return std::static_pointer_cast<R>(user_data);
} }
/** /**
* @brief Sets arbitrary data. `uvw` won't use this field in any case. * @brief Sets arbitrary data. `uvw` won't use this field in any case.
* @param uData User-defined arbitrary data. * @param ud User-defined arbitrary data.
*/ */
void data(std::shared_ptr<void> uData); void data(std::shared_ptr<void> ud);
/** /**
* @brief Gets the underlying raw data structure. * @brief Gets the underlying raw data structure.
@ -406,17 +409,10 @@ public:
uv_loop_t *raw() noexcept; uv_loop_t *raw() noexcept;
private: private:
std::unique_ptr<uv_loop_t, Deleter> loop; std::unique_ptr<uv_loop_t, deleter> uv_loop;
std::shared_ptr<void> userData{nullptr}; std::shared_ptr<void> user_data{nullptr};
}; };
// (extern) explicit instantiations
#ifdef UVW_AS_LIB
extern template bool Loop::run<Loop::Mode::DEFAULT>() noexcept;
extern template bool Loop::run<Loop::Mode::ONCE>() noexcept;
extern template bool Loop::run<Loop::Mode::NOWAIT>() noexcept;
#endif // UVW_AS_LIB
} // namespace uvw } // namespace uvw
#ifndef UVW_AS_LIB #ifndef UVW_AS_LIB

View File

@ -7,55 +7,56 @@
namespace uvw { namespace uvw {
UVW_INLINE PipeHandle::PipeHandle(ConstructorAccess ca, std::shared_ptr<Loop> ref, bool pass) UVW_INLINE pipe_handle::pipe_handle(loop::token token, std::shared_ptr<loop> ref, bool pass)
: StreamHandle{ca, std::move(ref)}, ipc{pass} {} : stream_handle{token, std::move(ref)}, ipc{pass} {}
UVW_INLINE bool PipeHandle::init() { UVW_INLINE int pipe_handle::init() {
return initialize(&uv_pipe_init, ipc); return leak_if(uv_pipe_init(parent().raw(), raw(), ipc));
} }
UVW_INLINE void PipeHandle::open(FileHandle file) { UVW_INLINE int pipe_handle::open(file_handle file) {
invoke(&uv_pipe_open, get(), file); return uv_pipe_open(raw(), file);
} }
UVW_INLINE void PipeHandle::bind(const std::string &name) { UVW_INLINE int pipe_handle::bind(const std::string &name) {
invoke(&uv_pipe_bind, get(), name.data()); return uv_pipe_bind(raw(), name.data());
} }
UVW_INLINE void PipeHandle::connect(const std::string &name) { UVW_INLINE int pipe_handle::connect(const std::string &name) {
auto listener = [ptr = shared_from_this()](const auto &event, const auto &) { auto listener = [ptr = shared_from_this()](const auto &event, const auto &) {
ptr->publish(event); ptr->publish(event);
}; };
auto connect = loop().resource<details::ConnectReq>(); auto connect = parent().resource<details::connect_req>();
connect->once<ErrorEvent>(listener); connect->on<error_event>(listener);
connect->once<ConnectEvent>(listener); connect->on<connect_event>(listener);
connect->connect(&uv_pipe_connect, get(), name.data());
return connect->connect(&uv_pipe_connect, raw(), name.data());
} }
UVW_INLINE std::string PipeHandle::sock() const noexcept { UVW_INLINE std::string pipe_handle::sock() const noexcept {
return details::tryRead(&uv_pipe_getsockname, get()); return details::try_read(&uv_pipe_getsockname, raw());
} }
UVW_INLINE std::string PipeHandle::peer() const noexcept { UVW_INLINE std::string pipe_handle::peer() const noexcept {
return details::tryRead(&uv_pipe_getpeername, get()); return details::try_read(&uv_pipe_getpeername, raw());
} }
UVW_INLINE void PipeHandle::pending(int count) noexcept { UVW_INLINE void pipe_handle::pending(int count) noexcept {
uv_pipe_pending_instances(get(), count); uv_pipe_pending_instances(raw(), count);
} }
UVW_INLINE int PipeHandle::pending() noexcept { UVW_INLINE int pipe_handle::pending() noexcept {
return uv_pipe_pending_count(get()); return uv_pipe_pending_count(raw());
} }
UVW_INLINE HandleType PipeHandle::receive() noexcept { UVW_INLINE handle_type pipe_handle::receive() noexcept {
HandleCategory category = uv_pipe_pending_type(get()); handle_category category = uv_pipe_pending_type(raw());
return Utilities::guessHandle(category); return utilities::guess_handle(category);
} }
UVW_INLINE bool PipeHandle::chmod(Flags<Chmod> flags) noexcept { UVW_INLINE int pipe_handle::chmod(chmod_flags flags) noexcept {
return (0 == uv_pipe_chmod(get(), flags)); return uv_pipe_chmod(raw(), static_cast<uv_poll_event>(flags));
} }
} // namespace uvw } // namespace uvw

View File

@ -5,6 +5,8 @@
#include <string> #include <string>
#include <type_traits> #include <type_traits>
#include <uv.h> #include <uv.h>
#include "config.h"
#include "enum.hpp"
#include "loop.h" #include "loop.h"
#include "request.hpp" #include "request.hpp"
#include "stream.h" #include "stream.h"
@ -14,68 +16,69 @@ namespace uvw {
namespace details { namespace details {
enum class UVChmodFlags : std::underlying_type_t<uv_poll_event> { enum class uvw_chmod_flags : std::underlying_type_t<uv_poll_event> {
READABLE = UV_READABLE, READABLE = UV_READABLE,
WRITABLE = UV_WRITABLE WRITABLE = UV_WRITABLE,
_UVW_ENUM = 0
}; };
} }
/** /**
* @brief The PipeHandle handle. * @brief The pipe handle.
* *
* Pipe handles provide an abstraction over local domain sockets on Unix and * Pipe handles provide an abstraction over local domain sockets on Unix and
* named pipes on Windows. * named pipes on Windows.
* *
* To create a `PipeHandle` through a `Loop`, arguments follow: * To create a `pipe_handle` through a `loop`, arguments follow:
* *
* * An optional boolean value that indicates if this pipe will be used for * * An optional boolean value that indicates if this pipe will be used for
* handle passing between processes. * handle passing between processes.
*/ */
class PipeHandle final: public StreamHandle<PipeHandle, uv_pipe_t> { class pipe_handle final: public stream_handle<pipe_handle, uv_pipe_t> {
public: public:
using Chmod = details::UVChmodFlags; using chmod_flags = details::uvw_chmod_flags;
explicit PipeHandle(ConstructorAccess ca, std::shared_ptr<Loop> ref, bool pass = false); explicit pipe_handle(loop::token token, std::shared_ptr<loop> ref, bool pass = false);
/** /**
* @brief Initializes the handle. * @brief Initializes the handle.
* @return True in case of success, false otherwise. * @return Underlying return value.
*/ */
bool init(); int init() final;
/** /**
* @brief Opens an existing file descriptor or HANDLE as a pipe. * @brief Opens an existing file descriptor or HANDLE as a pipe.
* *
* The passed file descriptor or HANDLE is not checked for its type, but * The passed file descriptor or HANDLE is not checked for its type, but
* its required that it represents a valid pipe.<br/> * its required that it represents a valid pipe.
* An ErrorEvent event is emitted in case of errors.
* *
* @param file A valid file handle (either a file descriptor or a HANDLE). * @param file A valid file handle (either a file descriptor or a HANDLE).
* @return Underlying return value.
*/ */
void open(FileHandle file); int open(file_handle file);
/** /**
* @brief bind Binds the pipe to a file path (Unix) or a name (Windows). * @brief bind Binds the pipe to a file path (Unix) or a name (Windows).
* *
* Paths on Unix get truncated typically between 92 and 108 bytes.<br/> * Paths on Unix get truncated typically between 92 and 108 bytes.
* An ErrorEvent event is emitted in case of errors.
* *
* @param name A valid file path. * @param name A valid file path.
* @return Underlying return value.
*/ */
void bind(const std::string &name); int bind(const std::string &name);
/** /**
* @brief Connects to the Unix domain socket or the named pipe. * @brief Connects to the Unix domain socket or the named pipe.
* *
* Paths on Unix get truncated typically between 92 and 108 bytes.<br/> * Paths on Unix get truncated typically between 92 and 108 bytes.<br/>
* A ConnectEvent event is emitted when the connection has been * A connect event is emitted when the connection has been
* established.<br/> * established.
* An ErrorEvent event is emitted in case of errors during the connection.
* *
* @param name A valid domain socket or named pipe. * @param name A valid domain socket or named pipe.
* @return Underlying return value.
*/ */
void connect(const std::string &name); int connect(const std::string &name);
/** /**
* @brief Gets the name of the Unix domain socket or the named pipe. * @brief Gets the name of the Unix domain socket or the named pipe.
@ -120,12 +123,12 @@ public:
* *
* @return The type of the pending handle. Possible values are: * @return The type of the pending handle. Possible values are:
* *
* * `HandleType::PIPE` * * `handle_type::PIPE`
* * `HandleType::TCP` * * `handle_type::TCP`
* * `HandleType::UDP` * * `handle_type::UDP`
* * `HandleType::UNKNOWN` * * `handle_type::UNKNOWN`
*/ */
HandleType receive() noexcept; handle_type receive() noexcept;
/** /**
* @brief Alters pipe permissions. * @brief Alters pipe permissions.
@ -134,17 +137,17 @@ public:
* *
* Available flags are: * Available flags are:
* *
* * `PipeHandle::Chmod::READABLE` * * `pipe_handle::chmod_flags::READABLE`
* * `PipeHandle::Chmod::WRITABLE` * * `pipe_handle::chmod_flags::WRITABLE`
* *
* See the official * See the official
* [documentation](http://docs.libuv.org/en/v1.x/pipe.html#c.uv_pipe_chmod) * [documentation](http://docs.libuv.org/en/v1.x/pipe.html#c.uv_pipe_chmod)
* for further details. * for further details.
* *
* @param flags A valid set of flags. * @param flags A valid set of flags.
* @return True in case of success, false otherwise. * @return Underlying return value.
*/ */
bool chmod(Flags<Chmod> flags) noexcept; int chmod(chmod_flags flags) noexcept;
private: private:
bool ipc; bool ipc;

View File

@ -3,44 +3,41 @@
#endif #endif
#include <utility> #include <utility>
#include "config.h" #include "config.h"
namespace uvw { namespace uvw {
UVW_INLINE PollEvent::PollEvent(Flags<details::UVPollEvent> events) noexcept UVW_INLINE poll_event::poll_event(details::uvw_poll_event events) noexcept
: flags{std::move(events)} {} : flags{std::move(events)} {}
UVW_INLINE PollHandle::PollHandle(ConstructorAccess ca, std::shared_ptr<Loop> ref, int desc) UVW_INLINE poll_handle::poll_handle(loop::token token, std::shared_ptr<loop> ref, int desc)
: Handle{ca, std::move(ref)}, tag{FD}, file_desc{desc} {} : handle{token, std::move(ref)}, tag{FD}, file_desc{desc} {}
UVW_INLINE PollHandle::PollHandle(ConstructorAccess ca, std::shared_ptr<Loop> ref, OSSocketHandle sock) UVW_INLINE poll_handle::poll_handle(loop::token token, std::shared_ptr<loop> ref, os_socket_handle sock)
: Handle{ca, std::move(ref)}, tag{SOCKET}, socket{sock} {} : handle{token, std::move(ref)}, tag{SOCKET}, socket{sock} {}
UVW_INLINE void PollHandle::startCallback(uv_poll_t *handle, int status, int events) { UVW_INLINE void poll_handle::start_callback(uv_poll_t *hndl, int status, int events) {
PollHandle &poll = *(static_cast<PollHandle *>(handle->data)); if(poll_handle &poll = *(static_cast<poll_handle *>(hndl->data)); status) {
poll.publish(error_event{status});
if(status) {
poll.publish(ErrorEvent{status});
} else { } else {
poll.publish(PollEvent{static_cast<std::underlying_type_t<Event>>(events)}); poll.publish(poll_event{poll_event(events)});
} }
} }
UVW_INLINE bool PollHandle::init() { UVW_INLINE int poll_handle::init() {
return (tag == SOCKET) ? initialize(&uv_poll_init_socket, socket) : initialize(&uv_poll_init, file_desc); if(tag == SOCKET) {
return leak_if(uv_poll_init_socket(parent().raw(), raw(), socket));
} else {
return leak_if(uv_poll_init(parent().raw(), raw(), file_desc));
}
} }
UVW_INLINE void PollHandle::start(Flags<PollHandle::Event> flags) { UVW_INLINE int poll_handle::start(poll_handle::poll_event flags) {
invoke(&uv_poll_start, get(), flags, &startCallback); return uv_poll_start(raw(), static_cast<uv_poll_event>(flags), &start_callback);
} }
UVW_INLINE void PollHandle::start(PollHandle::Event event) { UVW_INLINE int poll_handle::stop() {
start(Flags<Event>{event}); return uv_poll_stop(raw());
}
UVW_INLINE void PollHandle::stop() {
invoke(&uv_poll_stop, get());
} }
} // namespace uvw } // namespace uvw

View File

@ -4,6 +4,8 @@
#include <memory> #include <memory>
#include <type_traits> #include <type_traits>
#include <uv.h> #include <uv.h>
#include "config.h"
#include "enum.hpp"
#include "handle.hpp" #include "handle.hpp"
#include "util.h" #include "util.h"
@ -11,113 +13,90 @@ namespace uvw {
namespace details { namespace details {
enum class UVPollEvent : std::underlying_type_t<uv_poll_event> { enum class uvw_poll_event : std::underlying_type_t<uv_poll_event> {
READABLE = UV_READABLE, READABLE = UV_READABLE,
WRITABLE = UV_WRITABLE, WRITABLE = UV_WRITABLE,
DISCONNECT = UV_DISCONNECT, DISCONNECT = UV_DISCONNECT,
PRIORITIZED = UV_PRIORITIZED PRIORITIZED = UV_PRIORITIZED,
_UVW_ENUM = 0
}; };
} }
/** /*! @brief Poll event. */
* @brief PollEvent event. struct poll_event {
* explicit poll_event(details::uvw_poll_event events) noexcept;
* It will be emitted by PollHandle according with its functionalities.
*/
struct PollEvent {
explicit PollEvent(Flags<details::UVPollEvent> events) noexcept;
/** /**
* @brief Detected events all in one. * @brief Detected events all in one.
* *
* Available flags are: * Available flags are:
* *
* * `PollHandle::Event::READABLE` * * `poll_handle::event::READABLE`
* * `PollHandle::Event::WRITABLE` * * `poll_handle::event::WRITABLE`
* * `PollHandle::Event::DISCONNECT` * * `poll_handle::event::DISCONNECT`
* * `PollHandle::Event::PRIORITIZED` * * `poll_handle::event::PRIORITIZED`
*/ */
Flags<details::UVPollEvent> flags; details::uvw_poll_event flags;
}; };
/** /**
* @brief The PollHandle handle. * @brief The poll handle.
* *
* Poll handles are used to watch file descriptors for readability, writability * Poll handles are used to watch file descriptors for readability, writability
* and disconnection. * and disconnection.
* *
* To create a `PollHandle` through a `Loop`, arguments follow: * To create a `poll_handle` through a `loop`, arguments follow:
* *
* * A descriptor that can be: * * A descriptor that can be:
* * either an `int` file descriptor * * either an `int` file descriptor
* * or a `OSSocketHandle` socket descriptor * * or a `os_socket_handle` socket descriptor
* *
* See the official * See the official
* [documentation](http://docs.libuv.org/en/v1.x/poll.html) * [documentation](http://docs.libuv.org/en/v1.x/poll.html)
* for further details. * for further details.
*/ */
class PollHandle final: public Handle<PollHandle, uv_poll_t> { class poll_handle final: public handle<poll_handle, uv_poll_t, details::uvw_poll_event> {
static void startCallback(uv_poll_t *handle, int status, int events); static void start_callback(uv_poll_t *hndl, int status, int events);
public: public:
using Event = details::UVPollEvent; using poll_event = details::uvw_poll_event;
explicit PollHandle(ConstructorAccess ca, std::shared_ptr<Loop> ref, int desc); explicit poll_handle(loop::token token, std::shared_ptr<loop> ref, int desc);
explicit PollHandle(ConstructorAccess ca, std::shared_ptr<Loop> ref, OSSocketHandle sock); explicit poll_handle(loop::token token, std::shared_ptr<loop> ref, os_socket_handle sock);
/** /**
* @brief Initializes the handle. * @brief Initializes the handle.
* @return True in case of success, false otherwise. * @return Underlying return value.
*/ */
bool init(); int init() final;
/** /**
* @brief Starts polling the file descriptor. * @brief Starts polling the file descriptor.
* *
* Available flags are: * Available flags are:
* *
* * `PollHandle::Event::READABLE` * * `poll_handle::event::READABLE`
* * `PollHandle::Event::WRITABLE` * * `poll_handle::event::WRITABLE`
* * `PollHandle::Event::DISCONNECT` * * `poll_handle::event::DISCONNECT`
* * `PollHandle::Event::PRIORITIZED` * * `poll_handle::event::PRIORITIZED`
* *
* As soon as an event is detected, a PollEvent is emitted by the * As soon as an event is detected, a poll event is emitted by the
* handle.<br> * handle.
* It could happen that ErrorEvent events are emitted while running.
* *
* Calling more than once this method will update the flags to which the * Calling more than once this method will update the flags to which the
* caller is interested. * caller is interested.
* *
* @param flags The events to which the caller is interested. * @param flags The events to which the caller is interested.
* @return Underlying return value.
*/ */
void start(Flags<Event> flags); int start(poll_event flags);
/**
* @brief Starts polling the file descriptor.
*
* Available flags are:
*
* * `PollHandle::Event::READABLE`
* * `PollHandle::Event::WRITABLE`
* * `PollHandle::Event::DISCONNECT`
* * `PollHandle::Event::PRIORITIZED`
*
* As soon as an event is detected, a PollEvent is emitted by the
* handle.<br>
* It could happen that ErrorEvent events are emitted while running.
*
* Calling more than once this method will update the flags to which the
* caller is interested.
*
* @param event The event to which the caller is interested.
*/
void start(Event event);
/** /**
* @brief Stops polling the file descriptor. * @brief Stops polling the file descriptor.
* @return Underlying return value.
*/ */
void stop(); int stop();
private: private:
enum { enum {
@ -127,7 +106,7 @@ private:
union { union {
int file_desc; int file_desc;
OSSocketHandle::Type socket; os_socket_handle socket;
}; };
}; };

View File

@ -6,21 +6,21 @@
namespace uvw { namespace uvw {
UVW_INLINE void PrepareHandle::startCallback(uv_prepare_t *handle) { UVW_INLINE void prepare_handle::start_callback(uv_prepare_t *hndl) {
PrepareHandle &prepare = *(static_cast<PrepareHandle *>(handle->data)); prepare_handle &prepare = *(static_cast<prepare_handle *>(hndl->data));
prepare.publish(PrepareEvent{}); prepare.publish(prepare_event{});
} }
UVW_INLINE bool PrepareHandle::init() { UVW_INLINE int prepare_handle::init() {
return initialize(&uv_prepare_init); return leak_if(uv_prepare_init(parent().raw(), raw()));
} }
UVW_INLINE void PrepareHandle::start() { UVW_INLINE int prepare_handle::start() {
invoke(&uv_prepare_start, get(), &startCallback); return uv_prepare_start(raw(), &start_callback);
} }
UVW_INLINE void PrepareHandle::stop() { UVW_INLINE int prepare_handle::stop() {
invoke(&uv_prepare_stop, get()); return uv_prepare_stop(raw());
} }
} // namespace uvw } // namespace uvw

View File

@ -7,47 +7,46 @@
namespace uvw { namespace uvw {
/** /*! @brief Prepare event. */
* @brief PrepareEvent event. struct prepare_event {};
*
* It will be emitted by PrepareHandle according with its functionalities.
*/
struct PrepareEvent {};
/** /**
* @brief The PrepareHandle handle. * @brief The prepare handle.
* *
* Prepare handles will emit a PrepareEvent event once per loop iteration, right * Prepare handles will emit a prepare event once per loop iteration, right
* before polling for I/O. * before polling for I/O.
* *
* To create a `PrepareHandle` through a `Loop`, no arguments are required. * To create a `prepare_handle` through a `loop`, no arguments are required.
*/ */
class PrepareHandle final: public Handle<PrepareHandle, uv_prepare_t> { class prepare_handle final: public handle<prepare_handle, uv_prepare_t, prepare_event> {
static void startCallback(uv_prepare_t *handle); static void start_callback(uv_prepare_t *hndl);
public: public:
using Handle::Handle; using handle::handle;
/** /**
* @brief Initializes the handle. * @brief Initializes the handle.
* @return True in case of success, false otherwise. * @return Underlying return value.
*/ */
bool init(); int init() final;
/** /**
* @brief Starts the handle. * @brief Starts the handle.
* *
* A PrepareEvent event will be emitted once per loop iteration, right * A prepare event will be emitted once per loop iteration, right before
* before polling for I/O. * polling for I/O.
* *
* The handle will start emitting PrepareEvent when needed. * The handle will start emitting prepare events when needed.
*
* @return Underlying return value.
*/ */
void start(); int start();
/** /**
* @brief Stops the handle. * @brief Stops the handle.
* @return Underlying return value.
*/ */
void stop(); int stop();
}; };
} // namespace uvw } // namespace uvw

View File

@ -1,98 +1,95 @@
#ifdef UVW_AS_LIB #ifdef UVW_AS_LIB
# include "process.h" # include "process.h"
#endif #endif
#include <algorithm>
#include <algorithm>
#include "config.h" #include "config.h"
namespace uvw { namespace uvw {
UVW_INLINE ExitEvent::ExitEvent(int64_t code, int sig) noexcept UVW_INLINE exit_event::exit_event(int64_t code, int sig) noexcept
: status{code}, signal{sig} {} : status{code}, signal{sig} {}
UVW_INLINE void ProcessHandle::exitCallback(uv_process_t *handle, int64_t exitStatus, int termSignal) { UVW_INLINE void process_handle::exit_callback(uv_process_t *hndl, int64_t exit_status, int term_signal) {
ProcessHandle &process = *(static_cast<ProcessHandle *>(handle->data)); process_handle &process = *(static_cast<process_handle *>(hndl->data));
process.publish(ExitEvent{exitStatus, termSignal}); process.publish(exit_event{exit_status, term_signal});
} }
UVW_INLINE ProcessHandle::ProcessHandle(ConstructorAccess ca, std::shared_ptr<Loop> ref) UVW_INLINE process_handle::process_handle(loop::token token, std::shared_ptr<loop> ref)
: Handle{ca, std::move(ref)} {} : handle{token, std::move(ref)} {}
UVW_INLINE void ProcessHandle::disableStdIOInheritance() noexcept { UVW_INLINE void process_handle::disable_stdio_inheritance() noexcept {
uv_disable_stdio_inheritance(); uv_disable_stdio_inheritance();
} }
UVW_INLINE bool ProcessHandle::kill(int pid, int signum) noexcept { UVW_INLINE bool process_handle::kill(int pid, int signum) noexcept {
return (0 == uv_kill(pid, signum)); return (0 == uv_kill(pid, signum));
} }
UVW_INLINE bool ProcessHandle::init() { UVW_INLINE int process_handle::init() {
// deferred initialization: libuv initializes process handles only when // deferred initialization: libuv initializes process handles only when
// uv_spawn is invoked and uvw stays true to the underlying library // uv_spawn is invoked and uvw stays true to the underlying library
return true; return 0;
} }
UVW_INLINE void ProcessHandle::spawn(const char *file, char **args, char **env) { UVW_INLINE int process_handle::spawn(const char *file, char **args, char **env) {
uv_process_options_t po; uv_process_options_t po;
po.exit_cb = &exitCallback; po.exit_cb = &exit_callback;
po.file = file; po.file = file;
po.args = args; po.args = args;
po.env = env; po.env = env;
po.cwd = poCwd.empty() ? nullptr : poCwd.data(); po.cwd = po_cwd.empty() ? nullptr : po_cwd.data();
po.flags = poFlags; po.flags = static_cast<uv_process_flags>(po_flags);
po.uid = poUid; po.uid = po_uid;
po.gid = poGid; po.gid = po_gid;
std::vector<uv_stdio_container_t> poStdio; std::vector<uv_stdio_container_t> poStdio;
poStdio.reserve(poFdStdio.size() + poStreamStdio.size()); poStdio.reserve(po_fd_stdio.size() + po_stream_stdio.size());
poStdio.insert(poStdio.begin(), poFdStdio.cbegin(), poFdStdio.cend()); poStdio.insert(poStdio.begin(), po_fd_stdio.cbegin(), po_fd_stdio.cend());
poStdio.insert(poStdio.end(), poStreamStdio.cbegin(), poStreamStdio.cend()); poStdio.insert(poStdio.end(), po_stream_stdio.cbegin(), po_stream_stdio.cend());
po.stdio_count = static_cast<decltype(po.stdio_count)>(poStdio.size()); po.stdio_count = static_cast<decltype(po.stdio_count)>(poStdio.size());
po.stdio = poStdio.data(); po.stdio = poStdio.data();
// fake initialization so as to have leak invoked
// see init member function for more details // see init member function for more details
initialize([](auto...) { leak_if(0);
return 0;
});
invoke(&uv_spawn, parent(), get(), &po); return uv_spawn(parent().raw(), raw(), &po);
} }
UVW_INLINE void ProcessHandle::kill(int signum) { UVW_INLINE int process_handle::kill(int signum) {
invoke(&uv_process_kill, get(), signum); return uv_process_kill(raw(), signum);
} }
UVW_INLINE int ProcessHandle::pid() noexcept { UVW_INLINE int process_handle::pid() noexcept {
return get()->pid; return raw()->pid;
} }
UVW_INLINE ProcessHandle &ProcessHandle::cwd(const std::string &path) noexcept { UVW_INLINE process_handle &process_handle::cwd(const std::string &path) noexcept {
poCwd = path; po_cwd = path;
return *this; return *this;
} }
UVW_INLINE ProcessHandle &ProcessHandle::flags(Flags<Process> flags) noexcept { UVW_INLINE process_handle &process_handle::flags(process_flags flags) noexcept {
poFlags = flags; po_flags = flags;
return *this; return *this;
} }
UVW_INLINE ProcessHandle &ProcessHandle::stdio(FileHandle fd, Flags<StdIO> flags) { UVW_INLINE process_handle &process_handle::stdio(file_handle fd, stdio_flags flags) {
auto fgs = static_cast<uv_stdio_flags>(Flags<StdIO>::Type{flags}); auto fgs = static_cast<uv_stdio_flags>(flags);
auto actual = FileHandle::Type{fd}; auto actual = uvw::file_handle{fd};
auto it = std::find_if(poFdStdio.begin(), poFdStdio.end(), [actual](auto &&container) { auto it = std::find_if(po_fd_stdio.begin(), po_fd_stdio.end(), [actual](auto &&container) {
return container.data.fd == actual; return container.data.fd == actual;
}); });
if(it == poFdStdio.cend()) { if(it == po_fd_stdio.cend()) {
uv_stdio_container_t container; uv_stdio_container_t container;
container.flags = fgs; container.flags = fgs;
container.data.fd = actual; container.data.fd = actual;
poFdStdio.push_back(std::move(container)); po_fd_stdio.push_back(std::move(container));
} else { } else {
it->flags = fgs; it->flags = fgs;
it->data.fd = actual; it->data.fd = actual;
@ -101,13 +98,13 @@ UVW_INLINE ProcessHandle &ProcessHandle::stdio(FileHandle fd, Flags<StdIO> flags
return *this; return *this;
} }
UVW_INLINE ProcessHandle &ProcessHandle::uid(Uid id) { UVW_INLINE process_handle &process_handle::uid(uid_type id) {
poUid = id; po_uid = id;
return *this; return *this;
} }
UVW_INLINE ProcessHandle &ProcessHandle::gid(Gid id) { UVW_INLINE process_handle &process_handle::gid(gid_type id) {
poGid = id; po_gid = id;
return *this; return *this;
} }

View File

@ -6,6 +6,8 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <uv.h> #include <uv.h>
#include "config.h"
#include "enum.hpp"
#include "handle.hpp" #include "handle.hpp"
#include "loop.h" #include "loop.h"
#include "stream.h" #include "stream.h"
@ -15,54 +17,52 @@ namespace uvw {
namespace details { namespace details {
enum class UVProcessFlags : std::underlying_type_t<uv_process_flags> { enum class uvw_process_flags : std::underlying_type_t<uv_process_flags> {
SETUID = UV_PROCESS_SETUID, SETUID = UV_PROCESS_SETUID,
SETGID = UV_PROCESS_SETGID, SETGID = UV_PROCESS_SETGID,
WINDOWS_VERBATIM_ARGUMENTS = UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS, WINDOWS_VERBATIM_ARGUMENTS = UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS,
DETACHED = UV_PROCESS_DETACHED, DETACHED = UV_PROCESS_DETACHED,
WINDOWS_HIDE = UV_PROCESS_WINDOWS_HIDE, WINDOWS_HIDE = UV_PROCESS_WINDOWS_HIDE,
WINDOWS_HIDE_CONSOLE = UV_PROCESS_WINDOWS_HIDE_CONSOLE, WINDOWS_HIDE_CONSOLE = UV_PROCESS_WINDOWS_HIDE_CONSOLE,
WINDOWS_HIDE_GUI = UV_PROCESS_WINDOWS_HIDE_GUI WINDOWS_HIDE_GUI = UV_PROCESS_WINDOWS_HIDE_GUI,
_UVW_ENUM = 0
}; };
enum class UVStdIOFlags : std::underlying_type_t<uv_stdio_flags> { enum class uvw_stdio_flags : std::underlying_type_t<uv_stdio_flags> {
IGNORE_STREAM = UV_IGNORE, IGNORE_STREAM = UV_IGNORE,
CREATE_PIPE = UV_CREATE_PIPE, CREATE_PIPE = UV_CREATE_PIPE,
INHERIT_FD = UV_INHERIT_FD, INHERIT_FD = UV_INHERIT_FD,
INHERIT_STREAM = UV_INHERIT_STREAM, INHERIT_STREAM = UV_INHERIT_STREAM,
READABLE_PIPE = UV_READABLE_PIPE, READABLE_PIPE = UV_READABLE_PIPE,
WRITABLE_PIPE = UV_WRITABLE_PIPE, WRITABLE_PIPE = UV_WRITABLE_PIPE,
OVERLAPPED_PIPE = UV_OVERLAPPED_PIPE OVERLAPPED_PIPE = UV_OVERLAPPED_PIPE,
_UVW_ENUM = 0
}; };
} // namespace details } // namespace details
/** /*! @brief Exit event. */
* @brief ExitEvent event. struct exit_event {
* explicit exit_event(int64_t code, int sig) noexcept;
* It will be emitted by ProcessHandle according with its functionalities.
*/
struct ExitEvent {
explicit ExitEvent(int64_t code, int sig) noexcept;
int64_t status; /*!< The exit status. */ int64_t status; /*!< The exit status. */
int signal; /*!< The signal that caused the process to terminate, if any. */ int signal; /*!< The signal that caused the process to terminate, if any. */
}; };
/** /**
* @brief The ProcessHandle handle. * @brief The process handle.
* *
* Process handles will spawn a new process and allow the user to control it and * Process handles will spawn a new process and allow the user to control it and
* establish communication channels with it using streams. * establish communication channels with it using streams.
*/ */
class ProcessHandle final: public Handle<ProcessHandle, uv_process_t> { class process_handle final: public handle<process_handle, uv_process_t, exit_event> {
static void exitCallback(uv_process_t *handle, int64_t exitStatus, int termSignal); static void exit_callback(uv_process_t *hndl, int64_t exit_status, int term_signal);
public: public:
using Process = details::UVProcessFlags; using process_flags = details::uvw_process_flags;
using StdIO = details::UVStdIOFlags; using stdio_flags = details::uvw_stdio_flags;
ProcessHandle(ConstructorAccess ca, std::shared_ptr<Loop> ref); process_handle(loop::token token, std::shared_ptr<loop> ref);
/** /**
* @brief Disables inheritance for file descriptors/handles. * @brief Disables inheritance for file descriptors/handles.
@ -78,7 +78,7 @@ public:
* [documentation](http://docs.libuv.org/en/v1.x/process.html#c.uv_disable_stdio_inheritance) * [documentation](http://docs.libuv.org/en/v1.x/process.html#c.uv_disable_stdio_inheritance)
* for further details. * for further details.
*/ */
static void disableStdIOInheritance() noexcept; static void disable_stdio_inheritance() noexcept;
/** /**
* @brief kill Sends the specified signal to the given PID. * @brief kill Sends the specified signal to the given PID.
@ -90,16 +90,13 @@ public:
/** /**
* @brief Initializes the handle. * @brief Initializes the handle.
* @return True in case of success, false otherwise. * @return Underlying return value.
*/ */
bool init(); int init() final;
/** /**
* @brief spawn Starts the process. * @brief spawn Starts the process.
* *
* If the process isn't successfully spawned, an ErrorEvent event will be
* emitted by the handle.
*
* See the official * See the official
* [documentation](http://docs.libuv.org/en/v1.x/process.html) * [documentation](http://docs.libuv.org/en/v1.x/process.html)
* for further details. * for further details.
@ -107,14 +104,16 @@ public:
* @param file Path pointing to the program to be executed. * @param file Path pointing to the program to be executed.
* @param args Command line arguments. * @param args Command line arguments.
* @param env Optional environment for the new process. * @param env Optional environment for the new process.
* @return Underlying return value.
*/ */
void spawn(const char *file, char **args, char **env = nullptr); int spawn(const char *file, char **args, char **env = nullptr);
/** /**
* @brief Sends the specified signal to the internal process handle. * @brief Sends the specified signal to the internal process handle.
* @param signum A valid signal identifier. * @param signum A valid signal identifier.
* @return Underlying return value.
*/ */
void kill(int signum); int kill(int signum);
/** /**
* @brief Gets the PID of the spawned process. * @brief Gets the PID of the spawned process.
@ -130,20 +129,20 @@ public:
* @param path The working directory to be used when `spawn()` is invoked. * @param path The working directory to be used when `spawn()` is invoked.
* @return A reference to this process handle. * @return A reference to this process handle.
*/ */
ProcessHandle &cwd(const std::string &path) noexcept; process_handle &cwd(const std::string &path) noexcept;
/** /**
* @brief Sets flags that control how `spawn()` behaves. * @brief Sets flags that control how `spawn()` behaves.
* *
* Available flags are: * Available flags are:
* *
* * `ProcessHandle::Process::SETUID` * * `process_handle::process_flags::SETUID`
* * `ProcessHandle::Process::SETGID` * * `process_handle::process_flags::SETGID`
* * `ProcessHandle::Process::WINDOWS_VERBATIM_ARGUMENTS` * * `process_handle::process_flags::WINDOWS_VERBATIM_ARGUMENTS`
* * `ProcessHandle::Process::DETACHED` * * `process_handle::process_flags::DETACHED`
* * `ProcessHandle::Process::WINDOWS_HIDE` * * `process_handle::process_flags::WINDOWS_HIDE`
* * `ProcessHandle::Process::WINDOWS_HIDE_CONSOLE` * * `process_handle::process_flags::WINDOWS_HIDE_CONSOLE`
* * `ProcessHandle::Process::WINDOWS_HIDE_GUI` * * `process_handle::process_flags::WINDOWS_HIDE_GUI`
* *
* See the official * See the official
* [documentation](http://docs.libuv.org/en/v1.x/process.html#c.uv_process_flags) * [documentation](http://docs.libuv.org/en/v1.x/process.html#c.uv_process_flags)
@ -152,20 +151,20 @@ public:
* @param flags A valid set of flags. * @param flags A valid set of flags.
* @return A reference to this process handle. * @return A reference to this process handle.
*/ */
ProcessHandle &flags(Flags<Process> flags) noexcept; process_handle &flags(process_flags flags) noexcept;
/** /**
* @brief Makes a `stdio` handle available to the child process. * @brief Makes a `stdio` handle available to the child process.
* *
* Available flags are: * Available flags are:
* *
* * `ProcessHandle::StdIO::IGNORE_STREAM` * * `process_handle::stdio_flags::IGNORE_STREAM`
* * `ProcessHandle::StdIO::CREATE_PIPE` * * `process_handle::stdio_flags::CREATE_PIPE`
* * `ProcessHandle::StdIO::INHERIT_FD` * * `process_handle::stdio_flags::INHERIT_FD`
* * `ProcessHandle::StdIO::INHERIT_STREAM` * * `process_handle::stdio_flags::INHERIT_STREAM`
* * `ProcessHandle::StdIO::READABLE_PIPE` * * `process_handle::stdio_flags::READABLE_PIPE`
* * `ProcessHandle::StdIO::WRITABLE_PIPE` * * `process_handle::stdio_flags::WRITABLE_PIPE`
* * `ProcessHandle::StdIO::OVERLAPPED_PIPE` * * `process_handle::stdio_flags::OVERLAPPED_PIPE`
* *
* See the official * See the official
* [documentation](http://docs.libuv.org/en/v1.x/process.html#c.uv_stdio_flags) * [documentation](http://docs.libuv.org/en/v1.x/process.html#c.uv_stdio_flags)
@ -175,13 +174,12 @@ public:
* @param flags A valid set of flags. * @param flags A valid set of flags.
* @return A reference to this process handle. * @return A reference to this process handle.
*/ */
template<typename T, typename U> template<typename T, typename U, typename... E>
ProcessHandle &stdio(StreamHandle<T, U> &stream, Flags<StdIO> flags) { process_handle &stdio(stream_handle<T, U, E...> &stream, stdio_flags flags) {
uv_stdio_container_t container; uv_stdio_container_t container;
Flags<StdIO>::Type fgs = flags; container.flags = static_cast<uv_stdio_flags>(flags);
container.flags = static_cast<uv_stdio_flags>(fgs); container.data.stream = reinterpret_cast<uv_stream_t *>(stream.raw());
container.data.stream = get<uv_stream_t>(stream); po_stream_stdio.push_back(std::move(container));
poStreamStdio.push_back(std::move(container));
return *this; return *this;
} }
@ -190,18 +188,18 @@ public:
* *
* Available flags are: * Available flags are:
* *
* * `ProcessHandle::StdIO::IGNORE_STREAM` * * `process_handle::stdio_flags::IGNORE_STREAM`
* * `ProcessHandle::StdIO::CREATE_PIPE` * * `process_handle::stdio_flags::CREATE_PIPE`
* * `ProcessHandle::StdIO::INHERIT_FD` * * `process_handle::stdio_flags::INHERIT_FD`
* * `ProcessHandle::StdIO::INHERIT_STREAM` * * `process_handle::stdio_flags::INHERIT_STREAM`
* * `ProcessHandle::StdIO::READABLE_PIPE` * * `process_handle::stdio_flags::READABLE_PIPE`
* * `ProcessHandle::StdIO::WRITABLE_PIPE` * * `process_handle::stdio_flags::WRITABLE_PIPE`
* * `ProcessHandle::StdIO::OVERLAPPED_PIPE` * * `process_handle::stdio_flags::OVERLAPPED_PIPE`
* *
* Default file descriptors are: * Default file descriptors are:
* * `uvw::StdIN` for `stdin` * * `uvw::std_in` for `stdin`
* * `uvw::StdOUT` for `stdout` * * `uvw::std_out` for `stdout`
* * `uvw::StdERR` for `stderr` * * `uvw::std_err` for `stderr`
* *
* See the official * See the official
* [documentation](http://docs.libuv.org/en/v1.x/process.html#c.uv_stdio_flags) * [documentation](http://docs.libuv.org/en/v1.x/process.html#c.uv_stdio_flags)
@ -211,29 +209,29 @@ public:
* @param flags A valid set of flags. * @param flags A valid set of flags.
* @return A reference to this process handle. * @return A reference to this process handle.
*/ */
ProcessHandle &stdio(FileHandle fd, Flags<StdIO> flags); process_handle &stdio(file_handle fd, stdio_flags flags);
/** /**
* @brief Sets the child process' user id. * @brief Sets the child process' user id.
* @param id A valid user id to be used. * @param id A valid user id to be used.
* @return A reference to this process handle. * @return A reference to this process handle.
*/ */
ProcessHandle &uid(Uid id); process_handle &uid(uid_type id);
/** /**
* @brief Sets the child process' group id. * @brief Sets the child process' group id.
* @param id A valid group id to be used. * @param id A valid group id to be used.
* @return A reference to this process handle. * @return A reference to this process handle.
*/ */
ProcessHandle &gid(Gid id); process_handle &gid(gid_type id);
private: private:
std::string poCwd; std::string po_cwd;
Flags<Process> poFlags; process_flags po_flags;
std::vector<uv_stdio_container_t> poFdStdio; std::vector<uv_stdio_container_t> po_fd_stdio;
std::vector<uv_stdio_container_t> poStreamStdio; std::vector<uv_stdio_container_t> po_stream_stdio;
Uid poUid; uid_type po_uid;
Gid poGid; gid_type po_gid;
}; };
} // namespace uvw } // namespace uvw

View File

@ -5,6 +5,7 @@
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include <uv.h> #include <uv.h>
#include "config.h"
#include "resource.hpp" #include "resource.hpp"
namespace uvw { namespace uvw {
@ -14,56 +15,32 @@ namespace uvw {
* *
* Base type for all `uvw` request types. * Base type for all `uvw` request types.
*/ */
template<typename T, typename U> template<typename T, typename U, typename... E>
class Request: public Resource<T, U> { class request: public resource<T, U, E...> {
protected: protected:
static auto reserve(U *req) { static auto reserve(U *req) {
auto ptr = static_cast<T *>(req->data)->shared_from_this(); auto ptr = static_cast<T *>(req->data)->shared_from_this();
ptr->reset(); ptr->self_reset();
return ptr; return ptr;
} }
template<typename E>
static void defaultCallback(U *req, int status) {
if(auto ptr = reserve(req); status) {
ptr->publish(ErrorEvent{status});
} else {
ptr->publish(E{});
}
}
template<typename F, typename... Args>
auto invoke(F &&f, Args &&...args) {
if constexpr(std::is_void_v<std::invoke_result_t<F, Args...>>) {
std::forward<F>(f)(std::forward<Args>(args)...);
this->leak();
} else {
if(auto err = std::forward<F>(f)(std::forward<Args>(args)...); err) {
Emitter<T>::publish(ErrorEvent{err});
} else {
this->leak();
}
}
}
public: public:
using Resource<T, U>::Resource; using resource<T, U, E...>::resource;
/** /**
* @brief Cancels a pending request. * @brief Cancels a pending request.
* *
* This method fails if the request is executing or has finished * This method fails if the request is executing or has finished
* executing.<br/> * executing.
* It can emit an ErrorEvent event in case of errors.
* *
* See the official * See the official
* [documentation](http://docs.libuv.org/en/v1.x/request.html#c.uv_cancel) * [documentation](http://docs.libuv.org/en/v1.x/request.html#c.uv_cancel)
* for further details. * for further details.
* *
* @return True in case of success, false otherwise. * @return Underlying return value.
*/ */
bool cancel() { int cancel() {
return (0 == uv_cancel(this->template get<uv_req_t>())); return uv_cancel(reinterpret_cast<uv_req_t *>(this->raw()));
} }
/** /**
@ -71,7 +48,7 @@ public:
* @return The size of the underlying request type. * @return The size of the underlying request type.
*/ */
std::size_t size() const noexcept { std::size_t size() const noexcept {
return uv_req_size(this->template get<uv_req_t>()->type); return uv_req_size(reinterpret_cast<const uv_req_t *>(this->raw())->type);
} }
}; };

View File

@ -3,8 +3,9 @@
#include <memory> #include <memory>
#include <utility> #include <utility>
#include "config.h"
#include "emitter.h" #include "emitter.h"
#include "underlying_type.hpp" #include "uv_type.hpp"
namespace uvw { namespace uvw {
@ -13,31 +14,29 @@ namespace uvw {
* *
* This is the base class for handles and requests. * This is the base class for handles and requests.
*/ */
template<typename T, typename U> template<typename T, typename U, typename... E>
class Resource: public UnderlyingType<T, U>, public Emitter<T>, public std::enable_shared_from_this<T> { class resource: public uv_type<U>, public emitter<T, E...>, public std::enable_shared_from_this<T> {
protected: protected:
using ConstructorAccess = typename UnderlyingType<T, U>::ConstructorAccess; int leak_if(int err) noexcept {
if(err == 0) {
self_ptr = this->shared_from_this();
}
auto parent() const noexcept { return err;
return this->loop().loop.get();
} }
void leak() noexcept { void self_reset() noexcept {
sPtr = this->shared_from_this(); self_ptr.reset();
} }
void reset() noexcept { bool has_self() const noexcept {
sPtr.reset(); return static_cast<bool>(self_ptr);
}
bool self() const noexcept {
return static_cast<bool>(sPtr);
} }
public: public:
explicit Resource(ConstructorAccess ca, std::shared_ptr<Loop> ref) explicit resource(loop::token token, std::shared_ptr<loop> ref)
: UnderlyingType<T, U>{ca, std::move(ref)} { : uv_type<U>{token, std::move(ref)} {
this->get()->data = this; this->raw()->data = this;
} }
/** /**
@ -46,20 +45,20 @@ public:
*/ */
template<typename R = void> template<typename R = void>
std::shared_ptr<R> data() const { std::shared_ptr<R> data() const {
return std::static_pointer_cast<R>(userData); return std::static_pointer_cast<R>(user_data);
} }
/** /**
* @brief Sets arbitrary data. `uvw` won't use this field in any case. * @brief Sets arbitrary data. `uvw` won't use this field in any case.
* @param uData User-defined arbitrary data. * @param udata User-defined arbitrary data.
*/ */
void data(std::shared_ptr<void> uData) { void data(std::shared_ptr<void> udata) {
userData = std::move(uData); user_data = std::move(udata);
} }
private: private:
std::shared_ptr<void> userData{nullptr}; std::shared_ptr<void> user_data{nullptr};
std::shared_ptr<void> sPtr{nullptr}; std::shared_ptr<void> self_ptr{nullptr};
}; };
} // namespace uvw } // namespace uvw

View File

@ -6,32 +6,32 @@
namespace uvw { namespace uvw {
UVW_INLINE SignalEvent::SignalEvent(int sig) noexcept UVW_INLINE signal_event::signal_event(int sig) noexcept
: signum{sig} {} : signum{sig} {}
UVW_INLINE void SignalHandle::startCallback(uv_signal_t *handle, int signum) { UVW_INLINE void signal_handle::start_callback(uv_signal_t *hndl, int signum) {
SignalHandle &signal = *(static_cast<SignalHandle *>(handle->data)); signal_handle &signal = *(static_cast<signal_handle *>(hndl->data));
signal.publish(SignalEvent{signum}); signal.publish(signal_event{signum});
} }
UVW_INLINE bool SignalHandle::init() { UVW_INLINE int signal_handle::init() {
return initialize(&uv_signal_init); return leak_if(uv_signal_init(parent().raw(), raw()));
} }
UVW_INLINE void SignalHandle::start(int signum) { UVW_INLINE int signal_handle::start(int signum) {
invoke(&uv_signal_start, get(), &startCallback, signum); return uv_signal_start(raw(), &start_callback, signum);
} }
UVW_INLINE void SignalHandle::oneShot(int signum) { UVW_INLINE int signal_handle::one_shot(int signum) {
invoke(&uv_signal_start_oneshot, get(), &startCallback, signum); return uv_signal_start_oneshot(raw(), &start_callback, signum);
} }
UVW_INLINE void SignalHandle::stop() { UVW_INLINE int signal_handle::stop() {
invoke(&uv_signal_stop, get()); return uv_signal_stop(raw());
} }
UVW_INLINE int SignalHandle::signal() const noexcept { UVW_INLINE int signal_handle::signal() const noexcept {
return get()->signum; return raw()->signum;
} }
} // namespace uvw } // namespace uvw

View File

@ -2,70 +2,70 @@
#define UVW_SIGNAL_INCLUDE_H #define UVW_SIGNAL_INCLUDE_H
#include <uv.h> #include <uv.h>
#include "config.h"
#include "handle.hpp" #include "handle.hpp"
#include "loop.h" #include "loop.h"
namespace uvw { namespace uvw {
/** /*! @brief Signal event. */
* @brief SignalEvent event. struct signal_event {
* explicit signal_event(int sig) noexcept;
* It will be emitted by SignalHandle according with its functionalities.
*/
struct SignalEvent {
explicit SignalEvent(int sig) noexcept;
int signum; /*!< The signal being monitored by this handle. */ int signum; /*!< The signal being monitored by this handle. */
}; };
/** /**
* @brief The SignalHandle handle. * @brief The signal handle.
* *
* Signal handles implement Unix style signal handling on a per-event loop * Signal handles implement Unix style signal handling on a per-event loop
* bases.<br/> * bases.<br/>
* Reception of some signals is emulated on Windows. * Reception of some signals is emulated on Windows.
* *
* To create a `SignalHandle` through a `Loop`, no arguments are required. * To create a `signal_handle` through a `loop`, no arguments are required.
* *
* See the official * See the official
* [documentation](http://docs.libuv.org/en/v1.x/signal.html) * [documentation](http://docs.libuv.org/en/v1.x/signal.html)
* for further details. * for further details.
*/ */
class SignalHandle final: public Handle<SignalHandle, uv_signal_t> { class signal_handle final: public handle<signal_handle, uv_signal_t, signal_event> {
static void startCallback(uv_signal_t *handle, int signum); static void start_callback(uv_signal_t *hndl, int signum);
public: public:
using Handle::Handle; using handle::handle;
/** /**
* @brief Initializes the handle. * @brief Initializes the handle.
* @return True in case of success, false otherwise. * @return Underlying return value.
*/ */
bool init(); int init() final;
/** /**
* @brief Starts the handle. * @brief Starts the handle.
* *
* The handle will start emitting SignalEvent when needed. * The handle will start emitting signal events when needed.
* *
* @param signum The signal to be monitored. * @param signum The signal to be monitored.
* @return Underlying return value.
*/ */
void start(int signum); int start(int signum);
/** /**
* @brief Starts the handle. * @brief Starts the handle.
* *
* Same functionality as SignalHandle::start but the signal handler is reset * Same functionality as signal_handle::start but the signal handler is
* the moment the signal is received. * reset the moment the signal is received.
* *
* @param signum * @param signum The signal to be monitored.
* @return Underlying return value.
*/ */
void oneShot(int signum); int one_shot(int signum);
/** /**
* @brief Stops the handle. * @brief Stops the handle.
* @return Underlying return value.
*/ */
void stop(); int stop();
/** /**
* @brief Gets the signal being monitored. * @brief Gets the signal being monitored.

View File

@ -6,11 +6,28 @@
namespace uvw { namespace uvw {
UVW_INLINE DataEvent::DataEvent(std::unique_ptr<char[]> buf, std::size_t len) noexcept UVW_INLINE data_event::data_event(std::unique_ptr<char[]> buf, std::size_t len) noexcept
: data{std::move(buf)}, length{len} {} : data{std::move(buf)},
length{len} {}
UVW_INLINE void details::ShutdownReq::shutdown(uv_stream_t *handle) { UVW_INLINE void details::connect_req::connect_callback(uv_connect_t *req, int status) {
invoke(&uv_shutdown, get(), handle, &defaultCallback<ShutdownEvent>); if(auto ptr = reserve(req); status) {
ptr->publish(error_event{status});
} else {
ptr->publish(connect_event{});
}
}
UVW_INLINE void details::shutdown_req::shoutdown_callback(uv_shutdown_t *req, int status) {
if(auto ptr = reserve(req); status) {
ptr->publish(error_event{status});
} else {
ptr->publish(shutdown_event{});
}
}
UVW_INLINE int details::shutdown_req::shutdown(uv_stream_t *hndl) {
return this->leak_if(uv_shutdown(raw(), hndl, &shoutdown_callback));
} }
} // namespace uvw } // namespace uvw

View File

@ -7,54 +7,31 @@
#include <memory> #include <memory>
#include <utility> #include <utility>
#include <uv.h> #include <uv.h>
#include "config.h"
#include "handle.hpp" #include "handle.hpp"
#include "loop.h" #include "loop.h"
#include "request.hpp" #include "request.hpp"
namespace uvw { namespace uvw {
/** /*! @brief Connect event. */
* @brief ConnectEvent event. struct connect_event {};
*
* It will be emitted by StreamHandle according with its functionalities.
*/
struct ConnectEvent {};
/** /*! @brief End event. */
* @brief EndEvent event. struct end_event {};
*
* It will be emitted by StreamHandle according with its functionalities.
*/
struct EndEvent {};
/** /*! @brief Listen event. */
* @brief ListenEvent event. struct listen_event {};
*
* It will be emitted by StreamHandle according with its functionalities.
*/
struct ListenEvent {};
/** /*! @brief Shutdown event. */
* @brief ShutdownEvent event. struct shutdown_event {};
*
* It will be emitted by StreamHandle according with its functionalities.
*/
struct ShutdownEvent {};
/** /*! @brief Write event. */
* @brief WriteEvent event. struct write_event {};
*
* It will be emitted by StreamHandle according with its functionalities.
*/
struct WriteEvent {};
/** /*! @brief Data event. */
* @brief DataEvent event. struct data_event {
* explicit data_event(std::unique_ptr<char[]> buf, std::size_t len) noexcept;
* It will be emitted by StreamHandle according with its functionalities.
*/
struct DataEvent {
explicit DataEvent(std::unique_ptr<char[]> buf, std::size_t len) noexcept;
std::unique_ptr<char[]> data; /*!< A bunch of data read on the stream. */ std::unique_ptr<char[]> data; /*!< A bunch of data read on the stream. */
std::size_t length; /*!< The amount of data read on the stream. */ std::size_t length; /*!< The amount of data read on the stream. */
@ -62,37 +39,55 @@ struct DataEvent {
namespace details { namespace details {
struct ConnectReq final: public Request<ConnectReq, uv_connect_t> { class connect_req final: public request<connect_req, uv_connect_t, connect_event> {
using Request::Request; static void connect_callback(uv_connect_t *req, int status);
public:
using request::request;
template<typename F, typename... Args> template<typename F, typename... Args>
void connect(F &&f, Args &&...args) { auto connect(F &&f, Args &&...args) -> std::enable_if_t<std::is_same_v<decltype(std::forward<F>(f)(raw(), std::forward<Args>(args)..., &connect_callback)), void>, int> {
invoke(std::forward<F>(f), get(), std::forward<Args>(args)..., &defaultCallback<ConnectEvent>); std::forward<F>(f)(raw(), std::forward<Args>(args)..., &connect_callback);
return this->leak_if(0);
}
template<typename F, typename... Args>
auto connect(F &&f, Args &&...args) -> std::enable_if_t<!std::is_same_v<decltype(std::forward<F>(f)(raw(), std::forward<Args>(args)..., &connect_callback)), void>, int> {
return this->leak_if(std::forward<F>(f)(raw(), std::forward<Args>(args)..., &connect_callback));
} }
}; };
struct ShutdownReq final: public Request<ShutdownReq, uv_shutdown_t> { class shutdown_req final: public request<shutdown_req, uv_shutdown_t, shutdown_event> {
using Request::Request; static void shoutdown_callback(uv_shutdown_t *req, int status);
void shutdown(uv_stream_t *handle); public:
using request::request;
int shutdown(uv_stream_t *hndl);
}; };
template<typename Deleter> template<typename Deleter>
class WriteReq final: public Request<WriteReq<Deleter>, uv_write_t> { class write_req final: public request<write_req<Deleter>, uv_write_t, write_event> {
using ConstructorAccess = typename Request<WriteReq<Deleter>, uv_write_t>::ConstructorAccess; static void write_callback(uv_write_t *req, int status) {
if(auto ptr = request<write_req<Deleter>, uv_write_t, write_event>::reserve(req); status) {
ptr->publish(error_event{status});
} else {
ptr->publish(write_event{});
}
}
public: public:
WriteReq(ConstructorAccess ca, std::shared_ptr<Loop> loop, std::unique_ptr<char[], Deleter> dt, unsigned int len) write_req(loop::token token, std::shared_ptr<loop> parent, std::unique_ptr<char[], Deleter> dt, unsigned int len)
: Request<WriteReq<Deleter>, uv_write_t>{ca, std::move(loop)}, : request<write_req<Deleter>, uv_write_t, write_event>{token, std::move(parent)},
data{std::move(dt)}, data{std::move(dt)},
buf{uv_buf_init(data.get(), len)} {} buf{uv_buf_init(data.get(), len)} {}
void write(uv_stream_t *handle) { int write(uv_stream_t *hndl) {
this->invoke(&uv_write, this->get(), handle, &buf, 1, &this->template defaultCallback<WriteEvent>); return this->leak_if(uv_write(this->raw(), hndl, &buf, 1, &write_callback));
} }
void write(uv_stream_t *handle, uv_stream_t *send) { int write(uv_stream_t *hndl, uv_stream_t *send) {
this->invoke(&uv_write2, this->get(), handle, &buf, 1, send, &this->template defaultCallback<WriteEvent>); return this->leak_if(uv_write2(this->raw(), hndl, &buf, 1, send, &write_callback));
} }
private: private:
@ -103,18 +98,23 @@ private:
} // namespace details } // namespace details
/** /**
* @brief The StreamHandle handle. * @brief The stream handle.
* *
* Stream handles provide an abstraction of a duplex communication channel. * Stream handles provide an abstraction of a duplex communication channel.
* StreamHandle is an intermediate type, `uvw` provides three stream * The stream handle is an intermediate type, `uvw` provides three stream
* implementations: TCPHandle, PipeHandle and TTYHandle. * implementations: tcp, pipe and tty handles.
*/ */
template<typename T, typename U> template<typename T, typename U, typename... E>
class StreamHandle: public Handle<T, U> { class stream_handle: public handle<T, U, listen_event, end_event, connect_event, shutdown_event, data_event, write_event, E...> {
using base = handle<T, U, listen_event, end_event, connect_event, shutdown_event, data_event, write_event, E...>;
template<typename, typename, typename...>
friend class stream_handle;
static constexpr unsigned int DEFAULT_BACKLOG = 128; static constexpr unsigned int DEFAULT_BACKLOG = 128;
static void readCallback(uv_stream_t *handle, ssize_t nread, const uv_buf_t *buf) { static void read_callback(uv_stream_t *hndl, ssize_t nread, const uv_buf_t *buf) {
T &ref = *(static_cast<T *>(handle->data)); T &ref = *(static_cast<T *>(hndl->data));
// data will be destroyed no matter of what the value of nread is // data will be destroyed no matter of what the value of nread is
std::unique_ptr<char[]> data{buf->base}; std::unique_ptr<char[]> data{buf->base};
@ -124,30 +124,38 @@ class StreamHandle: public Handle<T, U> {
if(nread == UV_EOF) { if(nread == UV_EOF) {
// end of stream // end of stream
ref.publish(EndEvent{}); ref.publish(end_event{});
} else if(nread > 0) { } else if(nread > 0) {
// data available // data available
ref.publish(DataEvent{std::move(data), static_cast<std::size_t>(nread)}); ref.publish(data_event{std::move(data), static_cast<std::size_t>(nread)});
} else if(nread < 0) { } else if(nread < 0) {
// transmission error // transmission error
ref.publish(ErrorEvent(nread)); ref.publish(error_event(nread));
} }
} }
static void listenCallback(uv_stream_t *handle, int status) { static void listen_callback(uv_stream_t *hndl, int status) {
if(T &ref = *(static_cast<T *>(handle->data)); status) { if(T &ref = *(static_cast<T *>(hndl->data)); status) {
ref.publish(ErrorEvent{status}); ref.publish(error_event{status});
} else { } else {
ref.publish(ListenEvent{}); ref.publish(listen_event{});
} }
} }
uv_stream_t *as_uv_stream() {
return reinterpret_cast<uv_stream_t *>(this->raw());
}
const uv_stream_t *as_uv_stream() const {
return reinterpret_cast<const uv_stream_t *>(this->raw());
}
public: public:
#ifdef _MSC_VER #ifdef _MSC_VER
StreamHandle(typename Handle<T, U>::ConstructorAccess ca, std::shared_ptr<Loop> ref) stream_handle(loop::token token, std::shared_ptr<loop> ref)
: Handle<T, U>{ca, std::move(ref)} {} : base{token, std::move(ref)} {}
#else #else
using Handle<T, U>::Handle; using base::base;
#endif #endif
/** /**
@ -155,75 +163,83 @@ public:
* *
* It waits for pending write requests to complete. The handle should refer * It waits for pending write requests to complete. The handle should refer
* to a initialized stream.<br/> * to a initialized stream.<br/>
* A ShutdownEvent event will be emitted after shutdown is complete. * A shutdown event will be emitted after shutdown is complete.
*
* @return Underlying return value.
*/ */
void shutdown() { int shutdown() {
auto listener = [ptr = this->shared_from_this()](const auto &event, const auto &) { auto listener = [ptr = this->shared_from_this()](const auto &event, const auto &) {
ptr->publish(event); ptr->publish(event);
}; };
auto shutdown = this->loop().template resource<details::ShutdownReq>(); auto shutdown = this->parent().template resource<details::shutdown_req>();
shutdown->template once<ErrorEvent>(listener); shutdown->template on<error_event>(listener);
shutdown->template once<ShutdownEvent>(listener); shutdown->template on<shutdown_event>(listener);
shutdown->shutdown(this->template get<uv_stream_t>());
return shutdown->shutdown(as_uv_stream());
} }
/** /**
* @brief Starts listening for incoming connections. * @brief Starts listening for incoming connections.
* *
* When a new incoming connection is received, a ListenEvent event is * When a new incoming connection is received, a listen event is
* emitted.<br/> * emitted.
* An ErrorEvent event will be emitted in case of errors.
* *
* @param backlog Indicates the number of connections the kernel might * @param backlog Indicates the number of connections the kernel might
* queue, same as listen(2). * queue, same as listen(2).
*
* @return Underlying return value.
*/ */
void listen(int backlog = DEFAULT_BACKLOG) { int listen(int backlog = DEFAULT_BACKLOG) {
this->invoke(&uv_listen, this->template get<uv_stream_t>(), backlog, &listenCallback); return uv_listen(as_uv_stream(), backlog, &listen_callback);
} }
/** /**
* @brief Accepts incoming connections. * @brief Accepts incoming connections.
* *
* This call is used in conjunction with `listen()` to accept incoming * This call is used in conjunction with `listen()` to accept incoming
* connections. Call this function after receiving a ListenEvent event to * connections. Call this function after receiving a listen event to accept
* accept the connection. Before calling this function, the submitted handle * the connection. Before calling this function, the submitted handle must
* must be initialized.<br> * be initialized.
* An ErrorEvent event will be emitted in case of errors.
* *
* When the ListenEvent event is emitted it is guaranteed that this * When the listen event is emitted it is guaranteed that this function will
* function will complete successfully the first time. If you attempt to use * complete successfully the first time. If you attempt to use it more than
* it more than once, it may fail.<br/> * once, it may fail.<br/>
* It is suggested to only call this function once per ListenEvent event. * It is suggested to only call this function once per listen event.
* *
* @note * @note
* Both the handles must be running on the same loop. * Both the handles must be running on the same loop.
* *
* @param ref An initialized handle to be used to accept the connection. * @param ref An initialized handle to be used to accept the connection.
* @return Underlying return value.
*/ */
template<typename S> template<typename S>
void accept(S &ref) { int accept(S &ref) {
this->invoke(&uv_accept, this->template get<uv_stream_t>(), this->template get<uv_stream_t>(ref)); return uv_accept(as_uv_stream(), ref.as_uv_stream());
} }
/** /**
* @brief Starts reading data from an incoming stream. * @brief Starts reading data from an incoming stream.
* *
* A DataEvent event will be emitted several times until there is no more * A data event will be emitted several times until there is no more data to
* data to read or `stop()` is called.<br/> * read or `stop()` is called.<br/>
* An EndEvent event will be emitted when there is no more data to read. * An end event will be emitted when there is no more data to read.
*
* @return Underlying return value.
*/ */
void read() { int read() {
this->invoke(&uv_read_start, this->template get<uv_stream_t>(), &this->allocCallback, &readCallback); return uv_read_start(as_uv_stream(), &details::common_alloc_callback, &read_callback);
} }
/** /**
* @brief Stops reading data from the stream. * @brief Stops reading data from the stream.
* *
* This function is idempotent and may be safely called on a stopped stream. * This function is idempotent and may be safely called on a stopped stream.
*
* @return Underlying return value.
*/ */
void stop() { int stop() {
this->invoke(&uv_read_stop, this->template get<uv_stream_t>()); return uv_read_stop(as_uv_stream());
} }
/** /**
@ -232,22 +248,23 @@ public:
* Data are written in order. The handle takes the ownership of the data and * Data are written in order. The handle takes the ownership of the data and
* it is in charge of delete them. * it is in charge of delete them.
* *
* A WriteEvent event will be emitted when the data have been written.<br/> * A write event will be emitted when the data have been written.
* An ErrorEvent event will be emitted in case of errors.
* *
* @param data The data to be written to the stream. * @param data The data to be written to the stream.
* @param len The lenght of the submitted data. * @param len The lenght of the submitted data.
* @return Underlying return value.
*/ */
template<typename Deleter> template<typename Deleter>
void write(std::unique_ptr<char[], Deleter> data, unsigned int len) { int write(std::unique_ptr<char[], Deleter> data, unsigned int len) {
auto req = this->loop().template resource<details::WriteReq<Deleter>>(std::move(data), len); auto req = this->parent().template resource<details::write_req<Deleter>>(std::move(data), len);
auto listener = [ptr = this->shared_from_this()](const auto &event, const auto &) { auto listener = [ptr = this->shared_from_this()](const auto &event, const auto &) {
ptr->publish(event); ptr->publish(event);
}; };
req->template once<ErrorEvent>(listener); req->template on<error_event>(listener);
req->template once<WriteEvent>(listener); req->template on<write_event>(listener);
req->write(this->template get<uv_stream_t>());
return req->write(as_uv_stream());
} }
/** /**
@ -256,21 +273,22 @@ public:
* Data are written in order. The handle doesn't take the ownership of the * Data are written in order. The handle doesn't take the ownership of the
* data. Be sure that their lifetime overcome the one of the request. * data. Be sure that their lifetime overcome the one of the request.
* *
* A WriteEvent event will be emitted when the data have been written.<br/> * A write event will be emitted when the data have been written.
* An ErrorEvent event will be emitted in case of errors.
* *
* @param data The data to be written to the stream. * @param data The data to be written to the stream.
* @param len The lenght of the submitted data. * @param len The lenght of the submitted data.
* @return Underlying return value.
*/ */
void write(char *data, unsigned int len) { int write(char *data, unsigned int len) {
auto req = this->loop().template resource<details::WriteReq<void (*)(char *)>>(std::unique_ptr<char[], void (*)(char *)>{data, [](char *) {}}, len); auto req = this->parent().template resource<details::write_req<void (*)(char *)>>(std::unique_ptr<char[], void (*)(char *)>{data, [](char *) {}}, len);
auto listener = [ptr = this->shared_from_this()](const auto &event, const auto &) { auto listener = [ptr = this->shared_from_this()](const auto &event, const auto &) {
ptr->publish(event); ptr->publish(event);
}; };
req->template once<ErrorEvent>(listener); req->template on<error_event>(listener);
req->template once<WriteEvent>(listener); req->template on<write_event>(listener);
req->write(this->template get<uv_stream_t>());
return req->write(as_uv_stream());
} }
/** /**
@ -278,30 +296,31 @@ public:
* *
* The pipe must be initialized with `ipc == true`. * The pipe must be initialized with `ipc == true`.
* *
* `send` must be a TCPHandle or PipeHandle handle, which is a server or a * `send` must be a tcp or pipe handle, which is a server or a connection
* connection (listening or connected state). Bound sockets or pipes will be * (listening or connected state). Bound sockets or pipes will be assumed to
* assumed to be servers. * be servers.
* *
* The handle takes the ownership of the data and it is in charge of delete * The handle takes the ownership of the data and it is in charge of delete
* them. * them.
* *
* A WriteEvent event will be emitted when the data have been written.<br/> * A write event will be emitted when the data have been written.
* An ErrorEvent wvent will be emitted in case of errors.
* *
* @param send The handle over which to write data. * @param send The handle over which to write data.
* @param data The data to be written to the stream. * @param data The data to be written to the stream.
* @param len The lenght of the submitted data. * @param len The lenght of the submitted data.
* @return Underlying return value.
*/ */
template<typename S, typename Deleter> template<typename S, typename Deleter>
void write(S &send, std::unique_ptr<char[], Deleter> data, unsigned int len) { int write(S &send, std::unique_ptr<char[], Deleter> data, unsigned int len) {
auto req = this->loop().template resource<details::WriteReq<Deleter>>(std::move(data), len); auto req = this->parent().template resource<details::write_req<Deleter>>(std::move(data), len);
auto listener = [ptr = this->shared_from_this()](const auto &event, const auto &) { auto listener = [ptr = this->shared_from_this()](const auto &event, const auto &) {
ptr->publish(event); ptr->publish(event);
}; };
req->template once<ErrorEvent>(listener); req->template on<error_event>(listener);
req->template once<WriteEvent>(listener); req->template on<write_event>(listener);
req->write(this->template get<uv_stream_t>(), this->template get<uv_stream_t>(send));
return req->write(as_uv_stream(), send.as_uv_stream());
} }
/** /**
@ -309,124 +328,93 @@ public:
* *
* The pipe must be initialized with `ipc == true`. * The pipe must be initialized with `ipc == true`.
* *
* `send` must be a TCPHandle or PipeHandle handle, which is a server or a * `send` must be a tcp or pipe handle, which is a server or a connection
* connection (listening or connected state). Bound sockets or pipes will be * (listening or connected state). Bound sockets or pipes will be assumed to
* assumed to be servers. * be servers.
* *
* The handle doesn't take the ownership of the data. Be sure that their * The handle doesn't take the ownership of the data. Be sure that their
* lifetime overcome the one of the request. * lifetime overcome the one of the request.
* *
* A WriteEvent event will be emitted when the data have been written.<br/> * A write event will be emitted when the data have been written.
* An ErrorEvent wvent will be emitted in case of errors.
* *
* @param send The handle over which to write data. * @param send The handle over which to write data.
* @param data The data to be written to the stream. * @param data The data to be written to the stream.
* @param len The lenght of the submitted data. * @param len The lenght of the submitted data.
* @return Underlying return value.
*/ */
template<typename S> template<typename S>
void write(S &send, char *data, unsigned int len) { int write(S &send, char *data, unsigned int len) {
auto req = this->loop().template resource<details::WriteReq<void (*)(char *)>>(std::unique_ptr<char[], void (*)(char *)>{data, [](char *) {}}, len); auto req = this->parent().template resource<details::write_req<void (*)(char *)>>(std::unique_ptr<char[], void (*)(char *)>{data, [](char *) {}}, len);
auto listener = [ptr = this->shared_from_this()](const auto &event, const auto &) { auto listener = [ptr = this->shared_from_this()](const auto &event, const auto &) {
ptr->publish(event); ptr->publish(event);
}; };
req->template once<ErrorEvent>(listener); req->template on<error_event>(listener);
req->template once<WriteEvent>(listener); req->template on<write_event>(listener);
req->write(this->template get<uv_stream_t>(), this->template get<uv_stream_t>(send));
return req->write(as_uv_stream(), send.as_uv_stream());
} }
/** /**
* @brief Queues a write request if it can be completed immediately. * @brief Queues a write request if it can be completed immediately.
* *
* Same as `write()`, but wont queue a write request if it cant be * Same as `write()`, but wont queue a write request if it cant be
* completed immediately.<br/> * completed immediately.
* An ErrorEvent event will be emitted in case of errors.
* *
* @param data The data to be written to the stream. * @param data The data to be written to the stream.
* @param len The lenght of the submitted data. * @param len The lenght of the submitted data.
* @return Number of bytes written. * @return Underlying return value.
*/ */
int tryWrite(std::unique_ptr<char[]> data, unsigned int len) { int try_write(std::unique_ptr<char[]> data, unsigned int len) {
uv_buf_t bufs[] = {uv_buf_init(data.get(), len)}; uv_buf_t bufs[] = {uv_buf_init(data.get(), len)};
auto bw = uv_try_write(this->template get<uv_stream_t>(), bufs, 1); return uv_try_write(as_uv_stream(), bufs, 1);
if(bw < 0) {
this->publish(ErrorEvent{bw});
bw = 0;
}
return bw;
} }
/** /**
* @brief Queues a write request if it can be completed immediately. * @brief Queues a write request if it can be completed immediately.
* *
* Same as `tryWrite` for sending handles over a pipe.<br/> * Same as `try_write` for sending handles over a pipe.
* An ErrorEvent event will be emitted in case of errors.
* *
* @param data The data to be written to the stream. * @param data The data to be written to the stream.
* @param len The lenght of the submitted data. * @param len The lenght of the submitted data.
* @param send A valid handle suitable for the purpose. * @param send A valid handle suitable for the purpose.
* @return Number of bytes written. * @return Underlying return value.
*/ */
template<typename V, typename W> template<typename V, typename W>
int tryWrite(std::unique_ptr<char[]> data, unsigned int len, StreamHandle<V, W> &send) { int try_write(std::unique_ptr<char[]> data, unsigned int len, stream_handle<V, W> &send) {
uv_buf_t bufs[] = {uv_buf_init(data.get(), len)}; uv_buf_t bufs[] = {uv_buf_init(data.get(), len)};
auto bw = uv_try_write2(this->template get<uv_stream_t>(), bufs, 1, send.raw()); return uv_try_write2(as_uv_stream(), bufs, 1, send.raw());
if(bw < 0) {
this->publish(ErrorEvent{bw});
bw = 0;
}
return bw;
} }
/** /**
* @brief Queues a write request if it can be completed immediately. * @brief Queues a write request if it can be completed immediately.
* *
* Same as `write()`, but wont queue a write request if it cant be * Same as `write()`, but wont queue a write request if it cant be
* completed immediately.<br/> * completed immediately.
* An ErrorEvent event will be emitted in case of errors.
* *
* @param data The data to be written to the stream. * @param data The data to be written to the stream.
* @param len The lenght of the submitted data. * @param len The lenght of the submitted data.
* @return Number of bytes written. * @return Underlying return value.
*/ */
int tryWrite(char *data, unsigned int len) { int try_write(char *data, unsigned int len) {
uv_buf_t bufs[] = {uv_buf_init(data, len)}; uv_buf_t bufs[] = {uv_buf_init(data, len)};
auto bw = uv_try_write(this->template get<uv_stream_t>(), bufs, 1); return uv_try_write(as_uv_stream(), bufs, 1);
if(bw < 0) {
this->publish(ErrorEvent{bw});
bw = 0;
}
return bw;
} }
/** /**
* @brief Queues a write request if it can be completed immediately. * @brief Queues a write request if it can be completed immediately.
* *
* Same as `tryWrite` for sending handles over a pipe.<br/> * Same as `try_write` for sending handles over a pipe.
* An ErrorEvent event will be emitted in case of errors.
* *
* @param data The data to be written to the stream. * @param data The data to be written to the stream.
* @param len The lenght of the submitted data. * @param len The lenght of the submitted data.
* @param send A valid handle suitable for the purpose. * @param send A valid handle suitable for the purpose.
* @return Number of bytes written. * @return Underlying return value.
*/ */
template<typename V, typename W> template<typename V, typename W>
int tryWrite(char *data, unsigned int len, StreamHandle<V, W> &send) { int try_write(char *data, unsigned int len, stream_handle<V, W> &send) {
uv_buf_t bufs[] = {uv_buf_init(data, len)}; uv_buf_t bufs[] = {uv_buf_init(data, len)};
auto bw = uv_try_write2(this->template get<uv_stream_t>(), bufs, 1, send.raw()); return uv_try_write2(as_uv_stream(), bufs, 1, send.raw());
if(bw < 0) {
this->publish(ErrorEvent{bw});
bw = 0;
}
return bw;
} }
/** /**
@ -434,7 +422,7 @@ public:
* @return True if the stream is readable, false otherwise. * @return True if the stream is readable, false otherwise.
*/ */
bool readable() const noexcept { bool readable() const noexcept {
return (uv_is_readable(this->template get<uv_stream_t>()) == 1); return (uv_is_readable(as_uv_stream()) == 1);
} }
/** /**
@ -442,7 +430,7 @@ public:
* @return True if the stream is writable, false otherwise. * @return True if the stream is writable, false otherwise.
*/ */
bool writable() const noexcept { bool writable() const noexcept {
return (uv_is_writable(this->template get<uv_stream_t>()) == 1); return (uv_is_writable(as_uv_stream()) == 1);
} }
/** /**
@ -461,15 +449,15 @@ public:
* @return True in case of success, false otherwise. * @return True in case of success, false otherwise.
*/ */
bool blocking(bool enable = false) { bool blocking(bool enable = false) {
return (0 == uv_stream_set_blocking(this->template get<uv_stream_t>(), enable)); return (0 == uv_stream_set_blocking(as_uv_stream(), enable));
} }
/** /**
* @brief Gets the amount of queued bytes waiting to be sent. * @brief Gets the amount of queued bytes waiting to be sent.
* @return Amount of queued bytes waiting to be sent. * @return Amount of queued bytes waiting to be sent.
*/ */
size_t writeQueueSize() const noexcept { size_t write_queue_size() const noexcept {
return uv_stream_get_write_queue_size(this->template get<uv_stream_t>()); return uv_stream_get_write_queue_size(as_uv_stream());
} }
}; };

View File

@ -6,101 +6,81 @@
namespace uvw { namespace uvw {
UVW_INLINE TCPHandle::TCPHandle(ConstructorAccess ca, std::shared_ptr<Loop> ref, unsigned int f) UVW_INLINE tcp_handle::tcp_handle(loop::token token, std::shared_ptr<loop> ref, unsigned int f)
: StreamHandle{ca, std::move(ref)}, tag{f ? FLAGS : DEFAULT}, flags{f} {} : stream_handle{token, std::move(ref)}, tag{f ? FLAGS : DEFAULT}, flags{f} {}
UVW_INLINE bool TCPHandle::init() { UVW_INLINE int tcp_handle::init() {
return (tag == FLAGS) ? initialize(&uv_tcp_init_ex, flags) : initialize(&uv_tcp_init); if(tag == FLAGS) {
return leak_if(uv_tcp_init_ex(parent().raw(), raw(), flags));
} else {
return leak_if(uv_tcp_init(parent().raw(), raw()));
}
} }
UVW_INLINE void TCPHandle::open(OSSocketHandle socket) { UVW_INLINE int tcp_handle::open(os_socket_handle socket) {
invoke(&uv_tcp_open, get(), socket); return uv_tcp_open(raw(), socket);
} }
UVW_INLINE bool TCPHandle::noDelay(bool value) { UVW_INLINE bool tcp_handle::no_delay(bool value) {
return (0 == uv_tcp_nodelay(get(), value)); return (0 == uv_tcp_nodelay(raw(), value));
} }
UVW_INLINE bool TCPHandle::keepAlive(bool enable, TCPHandle::Time time) { UVW_INLINE bool tcp_handle::keep_alive(bool enable, tcp_handle::time val) {
return (0 == uv_tcp_keepalive(get(), enable, time.count())); return (0 == uv_tcp_keepalive(raw(), enable, val.count()));
} }
UVW_INLINE bool TCPHandle::simultaneousAccepts(bool enable) { UVW_INLINE bool tcp_handle::simultaneous_accepts(bool enable) {
return (0 == uv_tcp_simultaneous_accepts(get(), enable)); return (0 == uv_tcp_simultaneous_accepts(raw(), enable));
} }
UVW_INLINE void TCPHandle::bind(const sockaddr &addr, Flags<Bind> opts) { UVW_INLINE int tcp_handle::bind(const sockaddr &addr, tcp_flags opts) {
invoke(&uv_tcp_bind, get(), &addr, opts); return uv_tcp_bind(raw(), &addr, static_cast<uv_tcp_flags>(opts));
} }
template<typename I> UVW_INLINE int tcp_handle::bind(const std::string &ip, unsigned int port, tcp_flags opts) {
UVW_INLINE void TCPHandle::bind(const std::string &ip, unsigned int port, Flags<Bind> opts) { return bind(details::ip_addr(ip.data(), port), opts);
typename details::IpTraits<I>::Type addr;
details::IpTraits<I>::addrFunc(ip.data(), port, &addr);
bind(reinterpret_cast<const sockaddr &>(addr), std::move(opts));
} }
template<typename I> UVW_INLINE int tcp_handle::bind(socket_address addr, tcp_flags opts) {
UVW_INLINE void TCPHandle::bind(Addr addr, Flags<Bind> opts) { return bind(addr.ip, addr.port, opts);
bind<I>(std::move(addr.ip), addr.port, std::move(opts));
} }
template<typename I> UVW_INLINE socket_address tcp_handle::sock() const noexcept {
UVW_INLINE Addr TCPHandle::sock() const noexcept { sockaddr_storage storage;
return details::address<I>(&uv_tcp_getsockname, get()); int len = sizeof(sockaddr_storage);
uv_tcp_getsockname(raw(), reinterpret_cast<sockaddr *>(&storage), &len);
return details::sock_addr(storage);
} }
template<typename I> UVW_INLINE socket_address tcp_handle::peer() const noexcept {
UVW_INLINE Addr TCPHandle::peer() const noexcept { sockaddr_storage storage;
return details::address<I>(&uv_tcp_getpeername, get()); int len = sizeof(sockaddr_storage);
uv_tcp_getpeername(raw(), reinterpret_cast<sockaddr *>(&storage), &len);
return details::sock_addr(storage);
} }
template<typename I> UVW_INLINE int tcp_handle::connect(const std::string &ip, unsigned int port) {
UVW_INLINE void TCPHandle::connect(const std::string &ip, unsigned int port) { return connect(details::ip_addr(ip.data(), port));
typename details::IpTraits<I>::Type addr;
details::IpTraits<I>::addrFunc(ip.data(), port, &addr);
connect(reinterpret_cast<const sockaddr &>(addr));
} }
template<typename I> UVW_INLINE int tcp_handle::connect(socket_address addr) {
UVW_INLINE void TCPHandle::connect(Addr addr) { return connect(addr.ip, addr.port);
connect<I>(std::move(addr.ip), addr.port);
} }
UVW_INLINE void TCPHandle::connect(const sockaddr &addr) { UVW_INLINE int tcp_handle::connect(const sockaddr &addr) {
auto listener = [ptr = shared_from_this()](const auto &event, const auto &) { auto listener = [ptr = shared_from_this()](const auto &event, const auto &) {
ptr->publish(event); ptr->publish(event);
}; };
auto req = loop().resource<details::ConnectReq>(); auto req = parent().resource<details::connect_req>();
req->once<ErrorEvent>(listener); req->on<error_event>(listener);
req->once<ConnectEvent>(listener); req->on<connect_event>(listener);
req->connect(&uv_tcp_connect, get(), &addr);
return req->connect(&uv_tcp_connect, raw(), &addr);
} }
UVW_INLINE void TCPHandle::closeReset() { UVW_INLINE int tcp_handle::close_reset() {
invoke(&uv_tcp_close_reset, get(), &this->closeCallback); return uv_tcp_close_reset(raw(), &this->close_callback);
} }
// explicit instantiations
#ifdef UVW_AS_LIB
template void TCPHandle::bind<IPv4>(const std::string &, unsigned int, Flags<Bind>);
template void TCPHandle::bind<IPv6>(const std::string &, unsigned int, Flags<Bind>);
template void TCPHandle::bind<IPv4>(Addr, Flags<Bind>);
template void TCPHandle::bind<IPv6>(Addr, Flags<Bind>);
template Addr TCPHandle::sock<IPv4>() const noexcept;
template Addr TCPHandle::sock<IPv6>() const noexcept;
template Addr TCPHandle::peer<IPv4>() const noexcept;
template Addr TCPHandle::peer<IPv6>() const noexcept;
template void TCPHandle::connect<IPv4>(const std::string &, unsigned int);
template void TCPHandle::connect<IPv6>(const std::string &, unsigned int);
template void TCPHandle::connect<IPv4>(Addr addr);
template void TCPHandle::connect<IPv6>(Addr addr);
#endif // UVW_AS_LIB
} // namespace uvw } // namespace uvw

View File

@ -7,6 +7,8 @@
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include <uv.h> #include <uv.h>
#include "config.h"
#include "enum.hpp"
#include "request.hpp" #include "request.hpp"
#include "stream.h" #include "stream.h"
#include "util.h" #include "util.h"
@ -15,20 +17,21 @@ namespace uvw {
namespace details { namespace details {
enum class UVTCPFlags : std::underlying_type_t<uv_tcp_flags> { enum class uvw_tcp_flags : std::underlying_type_t<uv_tcp_flags> {
IPV6ONLY = UV_TCP_IPV6ONLY IPV6ONLY = UV_TCP_IPV6ONLY,
_UVW_ENUM = 0
}; };
} }
/** /**
* @brief The TCPHandle handle. * @brief The TCP handle.
* *
* TCP handles are used to represent both TCP streams and servers.<br/> * TCP handles are used to represent both TCP streams and servers.<br/>
* By default, _IPv4_ is used as a template parameter. The handle already * By default, _ipv4_ is used as a template parameter. The handle already
* supports _IPv6_ out-of-the-box by using `uvw::IPv6`. * supports _IPv6_ out-of-the-box by using `uvw::ipv6`.
* *
* To create a `TCPHandle` through a `Loop`, arguments follow: * To create a `tcp_handle` through a `loop`, arguments follow:
* *
* * An optional integer value that indicates the flags used to initialize * * An optional integer value that indicates the flags used to initialize
* the socket. * the socket.
@ -37,20 +40,20 @@ enum class UVTCPFlags : std::underlying_type_t<uv_tcp_flags> {
* [documentation](http://docs.libuv.org/en/v1.x/tcp.html#c.uv_tcp_init_ex) * [documentation](http://docs.libuv.org/en/v1.x/tcp.html#c.uv_tcp_init_ex)
* for further details. * for further details.
*/ */
class TCPHandle final: public StreamHandle<TCPHandle, uv_tcp_t> { class tcp_handle final: public stream_handle<tcp_handle, uv_tcp_t> {
public: public:
using Time = std::chrono::duration<unsigned int>; using time = std::chrono::duration<unsigned int>;
using Bind = details::UVTCPFlags; using tcp_flags = details::uvw_tcp_flags;
using IPv4 = uvw::IPv4; using ipv4 = uvw::ipv4;
using IPv6 = uvw::IPv6; using ipv6 = uvw::ipv6;
explicit TCPHandle(ConstructorAccess ca, std::shared_ptr<Loop> ref, unsigned int f = {}); explicit tcp_handle(loop::token token, std::shared_ptr<loop> ref, unsigned int f = {});
/** /**
* @brief Initializes the handle. No socket is created as of yet. * @brief Initializes the handle. No socket is created as of yet.
* @return True in case of success, false otherwise. * @return Underlying return value.
*/ */
bool init(); int init() final;
/** /**
* @brief Opens an existing file descriptor or SOCKET as a TCP handle. * @brief Opens an existing file descriptor or SOCKET as a TCP handle.
@ -58,25 +61,28 @@ public:
* The passed file descriptor or SOCKET is not checked for its type, but * The passed file descriptor or SOCKET is not checked for its type, but
* its required that it represents a valid stream socket. * its required that it represents a valid stream socket.
* *
* @param socket A valid socket handle (either a file descriptor or a SOCKET). * @param socket A valid socket handle (either a file descriptor or a
* SOCKET).
*
* @return Underlying return value.
*/ */
void open(OSSocketHandle socket); int open(os_socket_handle socket);
/** /**
* @brief Enables/Disables Nagles algorithm. * @brief Enables/Disables Nagles algorithm.
* @param value True to enable it, false otherwise. * @param value True to enable it, false otherwise.
* @return True in case of success, false otherwise. * @return True in case of success, false otherwise.
*/ */
bool noDelay(bool value = false); bool no_delay(bool value = false);
/** /**
* @brief Enables/Disables TCP keep-alive. * @brief Enables/Disables TCP keep-alive.
* @param enable True to enable it, false otherwise. * @param enable True to enable it, false otherwise.
* @param time Initial delay in seconds (use * @param val Initial delay in seconds (use
* `std::chrono::duration<unsigned int>`). * `std::chrono::duration<unsigned int>`).
* @return True in case of success, false otherwise. * @return True in case of success, false otherwise.
*/ */
bool keepAlive(bool enable = false, Time time = Time{0}); bool keep_alive(bool enable = false, time val = time{0});
/** /**
* @brief Enables/Disables simultaneous asynchronous accept requests. * @brief Enables/Disables simultaneous asynchronous accept requests.
@ -92,78 +98,73 @@ public:
* @param enable True to enable it, false otherwise. * @param enable True to enable it, false otherwise.
* @return True in case of success, false otherwise. * @return True in case of success, false otherwise.
*/ */
bool simultaneousAccepts(bool enable = true); bool simultaneous_accepts(bool enable = true);
/** /**
* @brief Binds the handle to an address and port. * @brief Binds the handle to an address and port.
* *
* A successful call to this function does not guarantee that the call to * A successful call to this function does not guarantee that the call to
* `listen()` or `connect()` will work properly.<br/> * `listen()` or `connect()` will work properly.
* ErrorEvent events can be emitted because of either this function or the
* ones mentioned above.
* *
* Available flags are: * Available flags are:
* *
* * `TCPHandle::Bind::IPV6ONLY`: it disables dual-stack support and only * * `tcp_handle::tcp_flags::IPV6ONLY`: it disables dual-stack support and
* IPv6 is used. * only IPv6 is used.
* *
* @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure. * @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
* @param opts Optional additional flags. * @param opts Optional additional flags.
* @return Underlying return value.
*/ */
void bind(const sockaddr &addr, Flags<Bind> opts = Flags<Bind>{}); int bind(const sockaddr &addr, tcp_flags opts = tcp_flags::_UVW_ENUM);
/** /**
* @brief Binds the handle to an address and port. * @brief Binds the handle to an address and port.
* *
* A successful call to this function does not guarantee that the call to * A successful call to this function does not guarantee that the call to
* `listen()` or `connect()` will work properly.<br/> * `listen()` or `connect()` will work properly.
* ErrorEvent events can be emitted because of either this function or the
* ones mentioned above.
* *
* Available flags are: * Available flags are:
* *
* * `TCPHandle::Bind::IPV6ONLY`: it disables dual-stack support and only * * `tcp_handle::tcp_flags::IPV6ONLY`: it disables dual-stack support and
* IPv6 is used. * only IPv6 is used.
* *
* @param ip The address to which to bind. * @param ip The address to which to bind.
* @param port The port to which to bind. * @param port The port to which to bind.
* @param opts Optional additional flags. * @param opts Optional additional flags.
* @return Underlying return value.
*/ */
template<typename I = IPv4> int bind(const std::string &ip, unsigned int port, tcp_flags opts = tcp_flags::_UVW_ENUM);
void bind(const std::string &ip, unsigned int port, Flags<Bind> opts = Flags<Bind>{});
/** /**
* @brief Binds the handle to an address and port. * @brief Binds the handle to an address and port.
* *
* A successful call to this function does not guarantee that the call to * A successful call to this function does not guarantee that the call to
* `listen()` or `connect()` will work properly.<br/> * `listen()` or `connect()` will work properly.
* ErrorEvent events can be emitted because of either this function or the
* ones mentioned above.
* *
* Available flags are: * Available flags are:
* *
* * `TCPHandle::Bind::IPV6ONLY`: it disables dual-stack support and only * * `tcp_handle::tcp_flags::IPV6ONLY`: it disables dual-stack support and
* IPv6 is used. * only IPv6 is used.
* *
* @param addr A valid instance of Addr. * @param addr A valid instance of socket_address.
* @param opts Optional additional flags. * @param opts Optional additional flags.
* @return Underlying return value.
*/ */
template<typename I = IPv4> int bind(socket_address addr, tcp_flags opts = tcp_flags::_UVW_ENUM);
void bind(Addr addr, Flags<Bind> opts = Flags<Bind>{});
/** /**
* @brief Gets the current address to which the handle is bound. * @brief Gets the current address to which the handle is bound.
* @return A valid instance of Addr, an empty one in case of errors. * @return A valid instance of socket_address, an empty one in case of
* errors.
*/ */
template<typename I = IPv4> socket_address sock() const noexcept;
Addr sock() const noexcept;
/** /**
* @brief Gets the address of the peer connected to the handle. * @brief Gets the address of the peer connected to the handle.
* @return A valid instance of Addr, an empty one in case of errors. * @return A valid instance of socket_address, an empty one in case of
* errors.
*/ */
template<typename I = IPv4> socket_address peer() const noexcept;
Addr peer() const noexcept;
/** /**
* @brief Establishes an IPv4 or IPv6 TCP connection. * @brief Establishes an IPv4 or IPv6 TCP connection.
@ -172,38 +173,33 @@ public:
* (`0.0.0.0` or `::`) it will be changed to point to localhost. This is * (`0.0.0.0` or `::`) it will be changed to point to localhost. This is
* done to match the behavior of Linux systems. * done to match the behavior of Linux systems.
* *
* A ConnectEvent event is emitted when the connection has been * A connect event is emitted when the connection has been established.
* established.<br/>
* An ErrorEvent event is emitted in case of errors during the connection.
* *
* @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure. * @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
* @return Underlying return value.
*/ */
void connect(const sockaddr &addr); int connect(const sockaddr &addr);
/** /**
* @brief Establishes an IPv4 or IPv6 TCP connection. * @brief Establishes an IPv4 or IPv6 TCP connection.
* *
* A ConnectEvent event is emitted when the connection has been * A connect event is emitted when the connection has been established.
* established.<br/>
* An ErrorEvent event is emitted in case of errors during the connection.
* *
* @param ip The address to which to bind. * @param ip The address to which to bind.
* @param port The port to which to bind. * @param port The port to which to bind.
* @return Underlying return value.
*/ */
template<typename I = IPv4> int connect(const std::string &ip, unsigned int port);
void connect(const std::string &ip, unsigned int port);
/** /**
* @brief Establishes an IPv4 or IPv6 TCP connection. * @brief Establishes an IPv4 or IPv6 TCP connection.
* *
* A ConnectEvent event is emitted when the connection has been * A connect event is emitted when the connection has been established.
* established.<br/>
* An ErrorEvent event is emitted in case of errors during the connection.
* *
* @param addr A valid instance of Addr. * @param addr A valid instance of socket_address.
* @return Underlying return value.
*/ */
template<typename I = IPv4> int connect(socket_address addr);
void connect(Addr addr);
/** /**
* @brief Resets a TCP connection by sending a RST packet. * @brief Resets a TCP connection by sending a RST packet.
@ -211,12 +207,13 @@ public:
* This is accomplished by setting the `SO_LINGER` socket option with a * This is accomplished by setting the `SO_LINGER` socket option with a
* linger interval of zero and then calling `close`.<br/> * linger interval of zero and then calling `close`.<br/>
* Due to some platform inconsistencies, mixing of `shutdown` and * Due to some platform inconsistencies, mixing of `shutdown` and
* `closeReset` calls is not allowed. * `close_reset` calls is not allowed.
* *
* A CloseEvent event is emitted when the connection has been reset.<br/> * A close event is emitted when the connection has been reset.
* An ErrorEvent event is emitted in case of errors. *
* @return Underlying return value.
*/ */
void closeReset(); int close_reset();
private: private:
enum { enum {
@ -227,37 +224,6 @@ private:
unsigned int flags; unsigned int flags;
}; };
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
// (extern) explicit instantiations
#ifdef UVW_AS_LIB
extern template void TCPHandle::bind<IPv4>(const std::string &, unsigned int, Flags<Bind>);
extern template void TCPHandle::bind<IPv6>(const std::string &, unsigned int, Flags<Bind>);
extern template void TCPHandle::bind<IPv4>(Addr, Flags<Bind>);
extern template void TCPHandle::bind<IPv6>(Addr, Flags<Bind>);
extern template Addr TCPHandle::sock<IPv4>() const noexcept;
extern template Addr TCPHandle::sock<IPv6>() const noexcept;
extern template Addr TCPHandle::peer<IPv4>() const noexcept;
extern template Addr TCPHandle::peer<IPv6>() const noexcept;
extern template void TCPHandle::connect<IPv4>(const std::string &, unsigned int);
extern template void TCPHandle::connect<IPv6>(const std::string &, unsigned int);
extern template void TCPHandle::connect<IPv4>(Addr addr);
extern template void TCPHandle::connect<IPv6>(Addr addr);
#endif // UVW_AS_LIB
/**
* Internal details not to be documented.
* @endcond
*/
} // namespace uvw } // namespace uvw
#ifndef UVW_AS_LIB #ifndef UVW_AS_LIB

View File

@ -6,168 +6,170 @@
namespace uvw { namespace uvw {
UVW_INLINE Thread::Thread(ConstructorAccess ca, std::shared_ptr<Loop> ref, Task t, std::shared_ptr<void> d) noexcept UVW_INLINE thread::thread(loop::token token, std::shared_ptr<loop> ref, task t, std::shared_ptr<void> d) noexcept
: UnderlyingType{ca, std::move(ref)}, data{std::move(d)}, task{std::move(t)} {} : uv_type{token, std::move(ref)},
data{std::move(d)},
func{std::move(t)} {}
UVW_INLINE void Thread::createCallback(void *arg) { UVW_INLINE void thread::create_callback(void *arg) {
Thread &thread = *(static_cast<Thread *>(arg)); thread &curr = *(static_cast<thread *>(arg));
thread.task(thread.data); curr.func(curr.data);
} }
UVW_INLINE Thread::Type Thread::self() noexcept { UVW_INLINE thread::type thread::self() noexcept {
return uv_thread_self(); return uv_thread_self();
} }
UVW_INLINE bool Thread::equal(const Thread &tl, const Thread &tr) noexcept { UVW_INLINE bool thread::equal(const thread &tl, const thread &tr) noexcept {
return !(0 == uv_thread_equal(tl.get(), tr.get())); return !(0 == uv_thread_equal(tl.raw(), tr.raw()));
} }
UVW_INLINE Thread::~Thread() noexcept { UVW_INLINE thread::~thread() noexcept {
join(); join();
} }
UVW_INLINE bool Thread::run() noexcept { UVW_INLINE bool thread::run() noexcept {
return (0 == uv_thread_create(get(), &createCallback, this)); return (0 == uv_thread_create(raw(), &create_callback, this));
} }
UVW_INLINE bool Thread::run(Flags<Options> opts, std::size_t stack) noexcept { UVW_INLINE bool thread::run(create_flags opts, std::size_t stack) noexcept {
uv_thread_options_t params{static_cast<unsigned int>(opts), stack}; uv_thread_options_t params{static_cast<unsigned int>(opts), stack};
return (0 == uv_thread_create_ex(get(), &params, &createCallback, this)); return (0 == uv_thread_create_ex(raw(), &params, &create_callback, this));
} }
UVW_INLINE bool Thread::join() noexcept { UVW_INLINE bool thread::join() noexcept {
return (0 == uv_thread_join(get())); return (0 == uv_thread_join(raw()));
} }
UVW_INLINE ThreadLocalStorage::ThreadLocalStorage(UnderlyingType<ThreadLocalStorage, uv_key_t>::ConstructorAccess ca, std::shared_ptr<Loop> ref) noexcept UVW_INLINE thread_local_storage::thread_local_storage(loop::token token, std::shared_ptr<loop> ref) noexcept
: UnderlyingType{ca, std::move(ref)} { : uv_type{token, std::move(ref)} {
uv_key_create(UnderlyingType::get()); uv_key_create(uv_type::raw());
} }
UVW_INLINE ThreadLocalStorage::~ThreadLocalStorage() noexcept { UVW_INLINE thread_local_storage::~thread_local_storage() noexcept {
uv_key_delete(UnderlyingType::get()); uv_key_delete(uv_type::raw());
} }
UVW_INLINE uv_once_t *Once::guard() noexcept { UVW_INLINE uv_once_t *once::guard() noexcept {
static uv_once_t once = UV_ONCE_INIT; static uv_once_t once = UV_ONCE_INIT;
return &once; return &once;
} }
UVW_INLINE Mutex::Mutex(UnderlyingType<Mutex, uv_mutex_t>::ConstructorAccess ca, std::shared_ptr<Loop> ref, bool recursive) noexcept UVW_INLINE mutex::mutex(loop::token token, std::shared_ptr<loop> ref, bool recursive) noexcept
: UnderlyingType{ca, std::move(ref)} { : uv_type{token, std::move(ref)} {
if(recursive) { if(recursive) {
uv_mutex_init_recursive(get()); uv_mutex_init_recursive(raw());
} else { } else {
uv_mutex_init(get()); uv_mutex_init(raw());
} }
} }
UVW_INLINE Mutex::~Mutex() noexcept { UVW_INLINE mutex::~mutex() noexcept {
uv_mutex_destroy(get()); uv_mutex_destroy(raw());
} }
UVW_INLINE void Mutex::lock() noexcept { UVW_INLINE void mutex::lock() noexcept {
uv_mutex_lock(get()); uv_mutex_lock(raw());
} }
UVW_INLINE bool Mutex::tryLock() noexcept { UVW_INLINE bool mutex::try_lock() noexcept {
return (0 == uv_mutex_trylock(get())); return (0 == uv_mutex_trylock(raw()));
} }
UVW_INLINE void Mutex::unlock() noexcept { UVW_INLINE void mutex::unlock() noexcept {
uv_mutex_unlock(get()); uv_mutex_unlock(raw());
} }
UVW_INLINE RWLock::RWLock(UnderlyingType<RWLock, uv_rwlock_t>::ConstructorAccess ca, std::shared_ptr<Loop> ref) noexcept UVW_INLINE rwlock::rwlock(loop::token token, std::shared_ptr<loop> ref) noexcept
: UnderlyingType{ca, std::move(ref)} { : uv_type{token, std::move(ref)} {
uv_rwlock_init(get()); uv_rwlock_init(raw());
} }
UVW_INLINE RWLock::~RWLock() noexcept { UVW_INLINE rwlock::~rwlock() noexcept {
uv_rwlock_destroy(get()); uv_rwlock_destroy(raw());
} }
UVW_INLINE void RWLock::rdLock() noexcept { UVW_INLINE void rwlock::rdlock() noexcept {
uv_rwlock_rdlock(get()); uv_rwlock_rdlock(raw());
} }
UVW_INLINE bool RWLock::tryRdLock() noexcept { UVW_INLINE bool rwlock::try_rdlock() noexcept {
return (0 == uv_rwlock_tryrdlock(get())); return (0 == uv_rwlock_tryrdlock(raw()));
} }
UVW_INLINE void RWLock::rdUnlock() noexcept { UVW_INLINE void rwlock::rdunlock() noexcept {
uv_rwlock_rdunlock(get()); uv_rwlock_rdunlock(raw());
} }
UVW_INLINE void RWLock::wrLock() noexcept { UVW_INLINE void rwlock::wrlock() noexcept {
uv_rwlock_wrlock(get()); uv_rwlock_wrlock(raw());
} }
UVW_INLINE bool RWLock::tryWrLock() noexcept { UVW_INLINE bool rwlock::try_wrlock() noexcept {
return (0 == uv_rwlock_trywrlock(get())); return (0 == uv_rwlock_trywrlock(raw()));
} }
UVW_INLINE void RWLock::wrUnlock() noexcept { UVW_INLINE void rwlock::wrunlock() noexcept {
uv_rwlock_wrunlock(get()); uv_rwlock_wrunlock(raw());
} }
UVW_INLINE Semaphore::Semaphore(UnderlyingType<Semaphore, uv_sem_t>::ConstructorAccess ca, std::shared_ptr<Loop> ref, unsigned int value) noexcept UVW_INLINE semaphore::semaphore(loop::token token, std::shared_ptr<loop> ref, unsigned int value) noexcept
: UnderlyingType{ca, std::move(ref)} { : uv_type{token, std::move(ref)} {
uv_sem_init(get(), value); uv_sem_init(raw(), value);
} }
UVW_INLINE Semaphore::~Semaphore() noexcept { UVW_INLINE semaphore::~semaphore() noexcept {
uv_sem_destroy(get()); uv_sem_destroy(raw());
} }
UVW_INLINE void Semaphore::post() noexcept { UVW_INLINE void semaphore::post() noexcept {
uv_sem_post(get()); uv_sem_post(raw());
} }
UVW_INLINE void Semaphore::wait() noexcept { UVW_INLINE void semaphore::wait() noexcept {
uv_sem_wait(get()); uv_sem_wait(raw());
} }
UVW_INLINE bool Semaphore::tryWait() noexcept { UVW_INLINE bool semaphore::try_wait() noexcept {
return (0 == uv_sem_trywait(get())); return (0 == uv_sem_trywait(raw()));
} }
UVW_INLINE Condition::Condition(UnderlyingType<Condition, uv_cond_t>::ConstructorAccess ca, std::shared_ptr<Loop> ref) noexcept UVW_INLINE condition::condition(loop::token token, std::shared_ptr<loop> ref) noexcept
: UnderlyingType{ca, std::move(ref)} { : uv_type{token, std::move(ref)} {
uv_cond_init(get()); uv_cond_init(raw());
} }
UVW_INLINE Condition::~Condition() noexcept { UVW_INLINE condition::~condition() noexcept {
uv_cond_destroy(get()); uv_cond_destroy(raw());
} }
UVW_INLINE void Condition::signal() noexcept { UVW_INLINE void condition::signal() noexcept {
uv_cond_signal(get()); uv_cond_signal(raw());
} }
UVW_INLINE void Condition::broadcast() noexcept { UVW_INLINE void condition::broadcast() noexcept {
uv_cond_broadcast(get()); uv_cond_broadcast(raw());
} }
UVW_INLINE void Condition::wait(Mutex &mutex) noexcept { UVW_INLINE void condition::wait(mutex &mtx) noexcept {
uv_cond_wait(get(), mutex.get()); uv_cond_wait(raw(), mtx.raw());
} }
UVW_INLINE bool Condition::timedWait(Mutex &mutex, uint64_t timeout) noexcept { UVW_INLINE bool condition::timed_wait(mutex &mtx, uint64_t timeout) noexcept {
return (0 == uv_cond_timedwait(get(), mutex.get(), timeout)); return (0 == uv_cond_timedwait(raw(), mtx.raw(), timeout));
} }
UVW_INLINE Barrier::Barrier(UnderlyingType<Barrier, uv_barrier_t>::ConstructorAccess ca, std::shared_ptr<Loop> ref, unsigned int count) noexcept UVW_INLINE barrier::barrier(loop::token token, std::shared_ptr<loop> ref, unsigned int count) noexcept
: UnderlyingType{ca, std::move(ref)} { : uv_type{token, std::move(ref)} {
uv_barrier_init(get(), count); uv_barrier_init(raw(), count);
} }
UVW_INLINE Barrier::~Barrier() noexcept { UVW_INLINE barrier::~barrier() noexcept {
uv_barrier_destroy(get()); uv_barrier_destroy(raw());
} }
UVW_INLINE bool Barrier::wait() noexcept { UVW_INLINE bool barrier::wait() noexcept {
return (0 == uv_barrier_wait(get())); return (0 == uv_barrier_wait(raw()));
} }
} // namespace uvw } // namespace uvw

View File

@ -8,55 +8,57 @@
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include <uv.h> #include <uv.h>
#include "config.h"
#include "enum.hpp"
#include "loop.h" #include "loop.h"
#include "underlying_type.hpp" #include "uv_type.hpp"
namespace uvw { namespace uvw {
namespace details { namespace details {
enum class UVThreadCreateFlags : std::underlying_type_t<uv_thread_create_flags> { enum class uvw_thread_create_flags : std::underlying_type_t<uv_thread_create_flags> {
THREAD_NO_FLAGS = UV_THREAD_NO_FLAGS, THREAD_NO_FLAGS = UV_THREAD_NO_FLAGS,
THREAD_HAS_STACK_SIZE = UV_THREAD_HAS_STACK_SIZE THREAD_HAS_STACK_SIZE = UV_THREAD_HAS_STACK_SIZE
}; };
} }
class Thread; class thread;
class ThreadLocalStorage; class thread_local_storage;
class Once; class once;
class Mutex; class mutex;
class RWLock; class rwlock;
class Semaphore; class semaphore;
class Condition; class condition;
class Barrier; class barrier;
/** /**
* @brief The Thread wrapper. * @brief The thread wrapper.
* *
* To create a `Thread` through a `Loop`, arguments follow: * To create a `thread` through a `loop`, arguments follow:
* *
* * A callback invoked to initialize thread execution. The type must be such * * A callback invoked to initialize thread execution. The type must be such
* that it can be assigned to an `std::function<void(std::shared_ptr<void>)>`. * that it can be assigned to an `std::function<void(std::shared_ptr<void>)>`.
* * An optional payload the type of which is `std::shared_ptr<void>`. * * An optional payload the type of which is `std::shared_ptr<void>`.
*/ */
class Thread final: public UnderlyingType<Thread, uv_thread_t> { class thread final: public uv_type<uv_thread_t> {
using InternalTask = std::function<void(std::shared_ptr<void>)>; using internal_task = std::function<void(std::shared_ptr<void>)>;
static void createCallback(void *arg); static void create_callback(void *arg);
public: public:
using Options = details::UVThreadCreateFlags; using create_flags = details::uvw_thread_create_flags;
using Task = InternalTask; using task = internal_task;
using Type = uv_thread_t; using type = uv_thread_t;
explicit Thread(ConstructorAccess ca, std::shared_ptr<Loop> ref, Task t, std::shared_ptr<void> d = nullptr) noexcept; explicit thread(loop::token token, std::shared_ptr<loop> ref, task t, std::shared_ptr<void> d = nullptr) noexcept;
/** /**
* @brief Obtains the identifier of the calling thread. * @brief Obtains the identifier of the calling thread.
* @return The identifier of the calling thread. * @return The identifier of the calling thread.
*/ */
static Type self() noexcept; static type self() noexcept;
/** /**
* @brief Compares thread by means of their identifiers. * @brief Compares thread by means of their identifiers.
@ -64,9 +66,9 @@ public:
* @param tr A valid instance of a thread. * @param tr A valid instance of a thread.
* @return True if the two threads are the same thread, false otherwise. * @return True if the two threads are the same thread, false otherwise.
*/ */
static bool equal(const Thread &tl, const Thread &tr) noexcept; static bool equal(const thread &tl, const thread &tr) noexcept;
~Thread() noexcept; ~thread() noexcept;
/** /**
* @brief Creates a new thread. * @brief Creates a new thread.
@ -79,15 +81,15 @@ public:
* *
* Available flags are: * Available flags are:
* *
* * `Thread::Options::THREAD_NO_FLAGS`: no flags set. * * `thread::create_flags::THREAD_NO_FLAGS`: no flags set.
* * `Thread::Options::THREAD_HAS_STACK_SIZE`: if set, `stack` specifies a * * `thread::create_flags::THREAD_HAS_STACK_SIZE`: if set, `stack` specifies a
* stack size for the new thread. 0 indicates that the default value should * stack size for the new thread. 0 indicates that the default value should
* be used (it behaves as if the flag was not set). Other values will be * be used (it behaves as if the flag was not set). Other values will be
* rounded up to the nearest page boundary. * rounded up to the nearest page boundary.
* *
* @return True in case of success, false otherwise. * @return True in case of success, false otherwise.
*/ */
bool run(Flags<Options> opts, std::size_t stack = {}) noexcept; bool run(create_flags opts, std::size_t stack = {}) noexcept;
/** /**
* @brief Joins with a terminated thread. * @brief Joins with a terminated thread.
@ -97,21 +99,21 @@ public:
private: private:
std::shared_ptr<void> data; std::shared_ptr<void> data;
Task task; task func;
}; };
/** /**
* @brief The ThreadLocalStorage wrapper. * @brief The thread local storage wrapper.
* *
* A storage area that can only be accessed by one thread. The variable can be * A storage area that can only be accessed by one thread. The variable can be
* seen as a global variable that is only visible to a particular thread and not * seen as a global variable that is only visible to a particular thread and not
* the whole program. * the whole program.
*/ */
class ThreadLocalStorage final: public UnderlyingType<ThreadLocalStorage, uv_key_t> { class thread_local_storage final: public uv_type<uv_key_t> {
public: public:
explicit ThreadLocalStorage(ConstructorAccess ca, std::shared_ptr<Loop> ref) noexcept; explicit thread_local_storage(loop::token token, std::shared_ptr<loop> ref) noexcept;
~ThreadLocalStorage() noexcept; ~thread_local_storage() noexcept;
/** /**
* @brief Gets the value of a given variable. * @brief Gets the value of a given variable.
@ -120,7 +122,7 @@ public:
*/ */
template<typename T> template<typename T>
T *get() noexcept { T *get() noexcept {
return static_cast<T *>(uv_key_get(UnderlyingType::get())); return static_cast<T *>(uv_key_get(uv_type::raw()));
} }
/** /**
@ -130,21 +132,21 @@ public:
*/ */
template<typename T> template<typename T>
void set(T *value) noexcept { void set(T *value) noexcept {
return uv_key_set(UnderlyingType::get(), value); return uv_key_set(uv_type::raw(), value);
} }
}; };
/** /**
* @brief The Once wrapper. * @brief The once wrapper.
* *
* Runs a function once and only once. Concurrent calls to `once` will block all * Runs a function once and only once. Concurrent calls to `once` will block all
* callers except one (its unspecified which one). * callers except one (its unspecified which one).
*/ */
class Once final: public UnderlyingType<Once, uv_once_t> { class once final: public uv_type<uv_once_t> {
static uv_once_t *guard() noexcept; static uv_once_t *guard() noexcept;
public: public:
using UnderlyingType::UnderlyingType; using uv_type::uv_type;
/** /**
* @brief Runs a function once and only once. * @brief Runs a function once and only once.
@ -156,29 +158,29 @@ public:
* @param f A valid callback function. * @param f A valid callback function.
*/ */
template<typename F> template<typename F>
static void once(F &&f) noexcept { static void run(F &&f) noexcept {
using CallbackType = void (*)(void); using callback_type = void (*)(void);
static_assert(std::is_convertible_v<F, CallbackType>); static_assert(std::is_convertible_v<F, callback_type>);
CallbackType cb = f; callback_type cb = f;
uv_once(guard(), cb); uv_once(guard(), cb);
} }
}; };
/** /**
* @brief The Mutex wrapper. * @brief The mutex wrapper.
* *
* To create a `Mutex` through a `Loop`, arguments follow: * To create a `mutex` through a `loop`, arguments follow:
* *
* * An option boolean that specifies if the mutex is a recursive one. The * * An option boolean that specifies if the mutex is a recursive one. The
* default value is false, the mutex isn't recursive. * default value is false, the mutex isn't recursive.
*/ */
class Mutex final: public UnderlyingType<Mutex, uv_mutex_t> { class mutex final: public uv_type<uv_mutex_t> {
friend class Condition; friend class condition;
public: public:
explicit Mutex(ConstructorAccess ca, std::shared_ptr<Loop> ref, bool recursive = false) noexcept; explicit mutex(loop::token token, std::shared_ptr<loop> ref, bool recursive = false) noexcept;
~Mutex() noexcept; ~mutex() noexcept;
/** /**
* @brief Locks the mutex. * @brief Locks the mutex.
@ -189,7 +191,7 @@ public:
* @brief Tries to lock the mutex. * @brief Tries to lock the mutex.
* @return True in case of success, false otherwise. * @return True in case of success, false otherwise.
*/ */
bool tryLock() noexcept; bool try_lock() noexcept;
/** /**
* @brief Unlocks the mutex. * @brief Unlocks the mutex.
@ -198,59 +200,59 @@ public:
}; };
/** /**
* @brief The RWLock wrapper. * @brief The rwlock wrapper.
*/ */
class RWLock final: public UnderlyingType<RWLock, uv_rwlock_t> { class rwlock final: public uv_type<uv_rwlock_t> {
public: public:
explicit RWLock(ConstructorAccess ca, std::shared_ptr<Loop> ref) noexcept; explicit rwlock(loop::token token, std::shared_ptr<loop> ref) noexcept;
~RWLock() noexcept; ~rwlock() noexcept;
/** /**
* @brief Locks a read-write lock object for reading. * @brief Locks a read-write lock object for reading.
*/ */
void rdLock() noexcept; void rdlock() noexcept;
/** /**
* @brief Tries to lock a read-write lock object for reading. * @brief Tries to lock a read-write lock object for reading.
* @return True in case of success, false otherwise. * @return True in case of success, false otherwise.
*/ */
bool tryRdLock() noexcept; bool try_rdlock() noexcept;
/** /**
* @brief Unlocks a read-write lock object previously locked for reading. * @brief Unlocks a read-write lock object previously locked for reading.
*/ */
void rdUnlock() noexcept; void rdunlock() noexcept;
/** /**
* @brief Locks a read-write lock object for writing. * @brief Locks a read-write lock object for writing.
*/ */
void wrLock() noexcept; void wrlock() noexcept;
/** /**
* @brief Tries to lock a read-write lock object for writing. * @brief Tries to lock a read-write lock object for writing.
* @return True in case of success, false otherwise. * @return True in case of success, false otherwise.
*/ */
bool tryWrLock() noexcept; bool try_wrlock() noexcept;
/** /**
* @brief Unlocks a read-write lock object previously locked for writing. * @brief Unlocks a read-write lock object previously locked for writing.
*/ */
void wrUnlock() noexcept; void wrunlock() noexcept;
}; };
/** /**
* @brief The Semaphore wrapper. * @brief The semaphore wrapper.
* *
* To create a `Semaphore` through a `Loop`, arguments follow: * To create a `semaphore` through a `loop`, arguments follow:
* *
* * An unsigned integer that specifies the initial value for the semaphore. * * An unsigned integer that specifies the initial value for the semaphore.
*/ */
class Semaphore final: public UnderlyingType<Semaphore, uv_sem_t> { class semaphore final: public uv_type<uv_sem_t> {
public: public:
explicit Semaphore(ConstructorAccess ca, std::shared_ptr<Loop> ref, unsigned int value) noexcept; explicit semaphore(loop::token token, std::shared_ptr<loop> ref, unsigned int value) noexcept;
~Semaphore() noexcept; ~semaphore() noexcept;
/** /**
* @brief Unlocks a semaphore. * @brief Unlocks a semaphore.
@ -266,17 +268,17 @@ public:
* @brief Tries to lock a semaphore. * @brief Tries to lock a semaphore.
* @return True in case of success, false otherwise. * @return True in case of success, false otherwise.
*/ */
bool tryWait() noexcept; bool try_wait() noexcept;
}; };
/** /**
* @brief The Condition wrapper. * @brief The condition wrapper.
*/ */
class Condition final: public UnderlyingType<Condition, uv_cond_t> { class condition final: public uv_type<uv_cond_t> {
public: public:
explicit Condition(ConstructorAccess ca, std::shared_ptr<Loop> ref) noexcept; explicit condition(loop::token token, std::shared_ptr<loop> ref) noexcept;
~Condition() noexcept; ~condition() noexcept;
/** /**
* @brief Signals a condition. * @brief Signals a condition.
@ -299,10 +301,10 @@ public:
* These function atomically releases the mutex and causes the calling * These function atomically releases the mutex and causes the calling
* thread to block on the condition variable. * thread to block on the condition variable.
* *
* @param mutex A mutex locked by the calling thread, otherwise expect * @param mtx A mutex locked by the calling thread, otherwise expect
* undefined behavior. * undefined behavior.
*/ */
void wait(Mutex &mutex) noexcept; void wait(mutex &mtx) noexcept;
/** /**
* @brief Waits on a condition. * @brief Waits on a condition.
@ -314,28 +316,28 @@ public:
* signaled or broadcasted, or if the absolute time specified has already * signaled or broadcasted, or if the absolute time specified has already
* been passed at the time of the call. * been passed at the time of the call.
* *
* @param mutex A mutex locked by the calling thread, otherwise expect * @param mtx A mutex locked by the calling thread, otherwise expect
* undefined behavior. * undefined behavior.
* @param timeout The maximum time to wait before to return. * @param timeout The maximum time to wait before to return.
* @return True in case of success, false otherwise. * @return True in case of success, false otherwise.
*/ */
bool timedWait(Mutex &mutex, uint64_t timeout) noexcept; bool timed_wait(mutex &mtx, uint64_t timeout) noexcept;
}; };
/** /**
* @brief The Barrier wrapper. * @brief The barrier wrapper.
* *
* To create a `Barrier` through a `Loop`, arguments follow: * To create a `barrier` through a `loop`, arguments follow:
* *
* * An unsigned integer that specifies the number of threads that must call * * An unsigned integer that specifies the number of threads that must call
* `wait` before any of them successfully return from the call. The value * `wait` before any of them successfully return from the call. The value
* specified must be greater than zero. * specified must be greater than zero.
*/ */
class Barrier final: public UnderlyingType<Barrier, uv_barrier_t> { class barrier final: public uv_type<uv_barrier_t> {
public: public:
explicit Barrier(ConstructorAccess ca, std::shared_ptr<Loop> ref, unsigned int count) noexcept; explicit barrier(loop::token token, std::shared_ptr<loop> ref, unsigned int count) noexcept;
~Barrier() noexcept; ~barrier() noexcept;
/** /**
* @brief Synchronizes at a barrier. * @brief Synchronizes at a barrier.

View File

@ -6,37 +6,37 @@
namespace uvw { namespace uvw {
UVW_INLINE void TimerHandle::startCallback(uv_timer_t *handle) { UVW_INLINE void timer_handle::start_callback(uv_timer_t *hndl) {
TimerHandle &timer = *(static_cast<TimerHandle *>(handle->data)); timer_handle &timer = *(static_cast<timer_handle *>(hndl->data));
timer.publish(TimerEvent{}); timer.publish(timer_event{});
} }
UVW_INLINE bool TimerHandle::init() { UVW_INLINE int timer_handle::init() {
return initialize(&uv_timer_init); return leak_if(uv_timer_init(parent().raw(), raw()));
} }
UVW_INLINE void TimerHandle::start(TimerHandle::Time timeout, TimerHandle::Time repeat) { UVW_INLINE int timer_handle::start(timer_handle::time timeout, timer_handle::time repeat) {
invoke(&uv_timer_start, get(), &startCallback, timeout.count(), repeat.count()); return uv_timer_start(raw(), &start_callback, timeout.count(), repeat.count());
} }
UVW_INLINE void TimerHandle::stop() { UVW_INLINE int timer_handle::stop() {
invoke(&uv_timer_stop, get()); return uv_timer_stop(raw());
} }
UVW_INLINE void TimerHandle::again() { UVW_INLINE int timer_handle::again() {
invoke(&uv_timer_again, get()); return uv_timer_again(raw());
} }
UVW_INLINE void TimerHandle::repeat(TimerHandle::Time repeat) { UVW_INLINE void timer_handle::repeat(timer_handle::time repeat) {
uv_timer_set_repeat(get(), repeat.count()); uv_timer_set_repeat(raw(), repeat.count());
} }
UVW_INLINE TimerHandle::Time TimerHandle::repeat() { UVW_INLINE timer_handle::time timer_handle::repeat() {
return Time{uv_timer_get_repeat(get())}; return time{uv_timer_get_repeat(raw())};
} }
UVW_INLINE TimerHandle::Time TimerHandle::dueIn() { UVW_INLINE timer_handle::time timer_handle::due_in() {
return Time{uv_timer_get_due_in(get())}; return time{uv_timer_get_due_in(raw())};
} }
} // namespace uvw } // namespace uvw

View File

@ -9,61 +9,61 @@
namespace uvw { namespace uvw {
/** /*! @brief Timer event. */
* @brief TimerEvent event. struct timer_event {};
*
* It will be emitted by TimerHandle according with its functionalities.
*/
struct TimerEvent {};
/** /**
* @brief The TimerHandle handle. * @brief The timer handle.
* *
* Timer handles are used to schedule events to be emitted in the future. * Timer handles are used to schedule events to be emitted in the future.
* *
* To create a `TimerHandle` through a `Loop`, no arguments are required. * To create a `timer_handle` through a `loop`, no arguments are required.
*/ */
class TimerHandle final: public Handle<TimerHandle, uv_timer_t> { class timer_handle final: public handle<timer_handle, uv_timer_t, timer_event> {
static void startCallback(uv_timer_t *handle); static void start_callback(uv_timer_t *hndl);
public: public:
using Time = std::chrono::duration<uint64_t, std::milli>; using time = std::chrono::duration<uint64_t, std::milli>;
using Handle::Handle; using handle::handle;
/** /**
* @brief Initializes the handle. * @brief Initializes the handle.
* @return True in case of success, false otherwise. * @return Underlying return value.
*/ */
bool init(); int init() final;
/** /**
* @brief Starts the timer. * @brief Starts the timer.
* *
* If timeout is zero, a TimerEvent event is emitted on the next event loop * If timeout is zero, a timer event is emitted on the next event loop
* iteration. If repeat is non-zero, a TimerEvent event is emitted first * iteration. If repeat is non-zero, a timer event is emitted first after
* after timeout milliseconds and then repeatedly after repeat milliseconds. * timeout milliseconds and then repeatedly after repeat milliseconds.
* *
* @param timeout Milliseconds before to emit an event (use * @param timeout Milliseconds before to emit an event (use
* `std::chrono::duration<uint64_t, std::milli>`). * `std::chrono::duration<uint64_t, std::milli>`).
* @param repeat Milliseconds between successive events (use * @param repeat Milliseconds between successive events (use
* `std::chrono::duration<uint64_t, std::milli>`). * `std::chrono::duration<uint64_t, std::milli>`).
*
* @return Underlying return value.
*/ */
void start(Time timeout, Time repeat); int start(time timeout, time repeat);
/** /**
* @brief Stops the handle. * @brief Stops the handle.
* @return Underlying return value.
*/ */
void stop(); int stop();
/** /**
* @brief Stops the timer and restarts it if it was repeating. * @brief Stops the timer and restarts it if it was repeating.
* *
* Stop the timer, and if it is repeating restart it using the repeat value * Stop the timer, and if it is repeating restart it using the repeat value
* as the timeout.<br/> * as the timeout.
* If the timer has never been started before it emits an ErrorEvent event. *
* @return Underlying return value.
*/ */
void again(); int again();
/** /**
* @brief Sets the repeat interval value. * @brief Sets the repeat interval value.
@ -83,23 +83,23 @@ public:
* @param repeat Repeat interval in milliseconds (use * @param repeat Repeat interval in milliseconds (use
* `std::chrono::duration<uint64_t, std::milli>`). * `std::chrono::duration<uint64_t, std::milli>`).
*/ */
void repeat(Time repeat); void repeat(time repeat);
/** /**
* @brief Gets the timer repeat value. * @brief Gets the timer repeat value.
* @return Timer repeat value in milliseconds (as a * @return Timer repeat value in milliseconds (as a
* `std::chrono::duration<uint64_t, std::milli>`). * `std::chrono::duration<uint64_t, std::milli>`).
*/ */
Time repeat(); time repeat();
/** /**
* @brief Gets the timer due value. * @brief Gets the timer due value.
* *
* The time is relative to `Loop::now()`. * The time is relative to `loop::now()`.
* *
* @return The timer due value or 0 if it has expired. * @return The timer due value or 0 if it has expired.
*/ */
Time dueIn(); time due_in();
}; };
} // namespace uvw } // namespace uvw

View File

@ -3,44 +3,43 @@
#endif #endif
#include <utility> #include <utility>
#include "config.h" #include "config.h"
namespace uvw { namespace uvw {
UVW_INLINE details::ResetModeMemo::~ResetModeMemo() { UVW_INLINE details::reset_mode_memo::~reset_mode_memo() {
uv_tty_reset_mode(); uv_tty_reset_mode();
} }
UVW_INLINE TTYHandle::TTYHandle(ConstructorAccess ca, std::shared_ptr<Loop> ref, FileHandle desc, bool readable) UVW_INLINE tty_handle::tty_handle(loop::token token, std::shared_ptr<loop> ref, file_handle desc, bool readable)
: StreamHandle{ca, std::move(ref)}, : stream_handle{token, std::move(ref)},
memo{resetModeMemo()}, memo{mode_memo_handler()},
fd{desc}, fd{desc},
rw{readable} {} rw{readable} {}
UVW_INLINE std::shared_ptr<details::ResetModeMemo> TTYHandle::resetModeMemo() { UVW_INLINE std::shared_ptr<details::reset_mode_memo> tty_handle::mode_memo_handler() {
static std::weak_ptr<details::ResetModeMemo> weak; static std::weak_ptr<details::reset_mode_memo> weak;
auto shared = weak.lock(); auto shared = weak.lock();
if(!shared) { weak = shared = std::make_shared<details::ResetModeMemo>(); } if(!shared) { weak = shared = std::make_shared<details::reset_mode_memo>(); }
return shared; return shared;
}; };
UVW_INLINE bool TTYHandle::init() { UVW_INLINE int tty_handle::init() {
return initialize(&uv_tty_init, fd, rw); return leak_if(uv_tty_init(parent().raw(), raw(), fd, rw));
} }
UVW_INLINE bool TTYHandle::mode(TTYHandle::Mode m) { UVW_INLINE bool tty_handle::mode(tty_handle::tty_mode m) {
return (0 == uv_tty_set_mode(get(), static_cast<std::underlying_type_t<Mode>>(m))); return (0 == uv_tty_set_mode(raw(), static_cast<uv_tty_mode_t>(m)));
} }
UVW_INLINE bool TTYHandle::reset() noexcept { UVW_INLINE bool tty_handle::reset_mode() noexcept {
return (0 == uv_tty_reset_mode()); return (0 == uv_tty_reset_mode());
} }
UVW_INLINE WinSize TTYHandle::getWinSize() { UVW_INLINE win_size tty_handle::get_win_size() {
WinSize size; win_size size;
if(0 != uv_tty_get_winsize(get(), &size.width, &size.height)) { if(0 != uv_tty_get_winsize(raw(), &size.width, &size.height)) {
size.width = -1; size.width = -1;
size.height = -1; size.height = -1;
} }
@ -48,21 +47,21 @@ UVW_INLINE WinSize TTYHandle::getWinSize() {
return size; return size;
} }
UVW_INLINE void TTYHandle::vtermState(TTYHandle::VTermState s) const noexcept { UVW_INLINE void tty_handle::vterm_state(tty_handle::tty_vtermstate s) const noexcept {
switch(s) { switch(s) {
case VTermState::SUPPORTED: case tty_vtermstate::SUPPORTED:
uv_tty_set_vterm_state(uv_tty_vtermstate_t::UV_TTY_SUPPORTED); uv_tty_set_vterm_state(uv_tty_vtermstate_t::UV_TTY_SUPPORTED);
break; break;
case VTermState::UNSUPPORTED: case tty_vtermstate::UNSUPPORTED:
uv_tty_set_vterm_state(uv_tty_vtermstate_t::UV_TTY_UNSUPPORTED); uv_tty_set_vterm_state(uv_tty_vtermstate_t::UV_TTY_UNSUPPORTED);
break; break;
} }
} }
UVW_INLINE TTYHandle::VTermState TTYHandle::vtermState() const noexcept { UVW_INLINE tty_handle::tty_vtermstate tty_handle::vterm_state() const noexcept {
uv_tty_vtermstate_t state; uv_tty_vtermstate_t state;
uv_tty_get_vterm_state(&state); uv_tty_get_vterm_state(&state);
return VTermState{state}; return tty_vtermstate{state};
} }
} // namespace uvw } // namespace uvw

View File

@ -4,6 +4,7 @@
#include <memory> #include <memory>
#include <type_traits> #include <type_traits>
#include <uv.h> #include <uv.h>
#include "config.h"
#include "stream.h" #include "stream.h"
#include "util.h" #include "util.h"
@ -11,17 +12,17 @@ namespace uvw {
namespace details { namespace details {
struct ResetModeMemo { struct reset_mode_memo {
~ResetModeMemo(); ~reset_mode_memo();
}; };
enum class UVTTYModeT : std::underlying_type_t<uv_tty_mode_t> { enum class uvw_tty_mode_t : std::underlying_type_t<uv_tty_mode_t> {
NORMAL = UV_TTY_MODE_NORMAL, NORMAL = UV_TTY_MODE_NORMAL,
RAW = UV_TTY_MODE_RAW, RAW = UV_TTY_MODE_RAW,
IO = UV_TTY_MODE_IO IO = UV_TTY_MODE_IO
}; };
enum class UVTTYVTermStateT : std::underlying_type_t<uv_tty_vtermstate_t> { enum class uvw_tty_vtermstate_t : std::underlying_type_t<uv_tty_vtermstate_t> {
SUPPORTED = UV_TTY_SUPPORTED, SUPPORTED = UV_TTY_SUPPORTED,
UNSUPPORTED = UV_TTY_UNSUPPORTED UNSUPPORTED = UV_TTY_UNSUPPORTED
}; };
@ -29,16 +30,16 @@ enum class UVTTYVTermStateT : std::underlying_type_t<uv_tty_vtermstate_t> {
} // namespace details } // namespace details
/** /**
* @brief The TTYHandle handle. * @brief The tty handle.
* *
* TTY handles represent a stream for the console. * TTY handles represent a stream for the console.
* *
* To create a `TTYHandle` through a `Loop`, arguments follow: * To create a `tty_handle` through a `loop`, arguments follow:
* *
* * A valid FileHandle. Usually the file descriptor will be: * * A valid file_handle. Usually the file descriptor will be:
* * `uvw::StdIN` or `0` for `stdin` * * `uvw::std_in` or `0` for `stdin`
* * `uvw::StdOUT` or `1` for `stdout` * * `uvw::std_out` or `1` for `stdout`
* * `uvw::StdERR` or `2` for `stderr` * * `uvw::std_err` or `2` for `stderr`
* * A boolean value that specifies the plan on calling `read()` with this * * A boolean value that specifies the plan on calling `read()` with this
* stream. Remember that `stdin` is readable, `stdout` is not. * stream. Remember that `stdin` is readable, `stdout` is not.
* *
@ -46,29 +47,29 @@ enum class UVTTYVTermStateT : std::underlying_type_t<uv_tty_vtermstate_t> {
* [documentation](http://docs.libuv.org/en/v1.x/tty.html#c.uv_tty_init) * [documentation](http://docs.libuv.org/en/v1.x/tty.html#c.uv_tty_init)
* for further details. * for further details.
*/ */
class TTYHandle final: public StreamHandle<TTYHandle, uv_tty_t> { class tty_handle final: public stream_handle<tty_handle, uv_tty_t> {
static std::shared_ptr<details::ResetModeMemo> resetModeMemo(); static std::shared_ptr<details::reset_mode_memo> mode_memo_handler();
public: public:
using Mode = details::UVTTYModeT; using tty_mode = details::uvw_tty_mode_t;
using VTermState = details::UVTTYVTermStateT; using tty_vtermstate = details::uvw_tty_vtermstate_t;
explicit TTYHandle(ConstructorAccess ca, std::shared_ptr<Loop> ref, FileHandle desc, bool readable); explicit tty_handle(loop::token token, std::shared_ptr<loop> ref, file_handle desc, bool readable);
/** /**
* @brief Initializes the handle. * @brief Initializes the handle.
* @return True in case of success, false otherwise. * @return Underlying return value.
*/ */
bool init(); int init() final;
/** /**
* @brief Sets the TTY using the specified terminal mode. * @brief Sets the TTY using the specified terminal mode.
* *
* Available modes are: * Available modes are:
* *
* * `TTY::Mode::NORMAL` * * `TTY::tty_mode::NORMAL`
* * `TTY::Mode::RAW` * * `TTY::tty_mode::RAW`
* * `TTY::Mode::IO` * * `TTY::tty_mode::IO`
* *
* See the official * See the official
* [documentation](http://docs.libuv.org/en/v1.x/tty.html#c.uv_tty_mode_t) * [documentation](http://docs.libuv.org/en/v1.x/tty.html#c.uv_tty_mode_t)
@ -77,19 +78,19 @@ public:
* @param m The mode to be set. * @param m The mode to be set.
* @return True in case of success, false otherwise. * @return True in case of success, false otherwise.
*/ */
bool mode(Mode m); bool mode(tty_mode m);
/** /**
* @brief Resets TTY settings to default values. * @brief Resets TTY settings to default values.
* @return True in case of success, false otherwise. * @return True in case of success, false otherwise.
*/ */
bool reset() noexcept; bool reset_mode() noexcept;
/** /**
* @brief Gets the current Window size. * @brief Gets the current Window size.
* @return The current Window size or `{-1, -1}` in case of errors. * @return The current Window size or `{-1, -1}` in case of errors.
*/ */
WinSize getWinSize(); win_size get_win_size();
/** /**
* @brief Controls whether console virtual terminal sequences are processed * @brief Controls whether console virtual terminal sequences are processed
@ -100,8 +101,8 @@ public:
* *
* Available states are: * Available states are:
* *
* * `TTY::VTermState::SUPPORTED` * * `TTY::tty_vtermstate::SUPPORTED`
* * `TTY::VTermState::UNSUPPORTED` * * `TTY::tty_vtermstate::UNSUPPORTED`
* *
* See the official * See the official
* [documentation](http://docs.libuv.org/en/v1.x/tty.html#c.uv_tty_vtermstate_t) * [documentation](http://docs.libuv.org/en/v1.x/tty.html#c.uv_tty_vtermstate_t)
@ -109,7 +110,7 @@ public:
* *
* @param s The state to be set. * @param s The state to be set.
*/ */
void vtermState(VTermState s) const noexcept; void vterm_state(tty_vtermstate s) const noexcept;
/** /**
* @brief Gets the current state of whether console virtual terminal * @brief Gets the current state of whether console virtual terminal
@ -119,8 +120,8 @@ public:
* *
* Available states are: * Available states are:
* *
* * `TTY::VTermState::SUPPORTED` * * `TTY::tty_vtermstate::SUPPORTED`
* * `TTY::VTermState::UNSUPPORTED` * * `TTY::tty_vtermstate::UNSUPPORTED`
* *
* See the official * See the official
* [documentation](http://docs.libuv.org/en/v1.x/tty.html#c.uv_tty_vtermstate_t) * [documentation](http://docs.libuv.org/en/v1.x/tty.html#c.uv_tty_vtermstate_t)
@ -128,11 +129,11 @@ public:
* *
* @return The current state. * @return The current state.
*/ */
VTermState vtermState() const noexcept; tty_vtermstate vterm_state() const noexcept;
private: private:
std::shared_ptr<details::ResetModeMemo> memo; std::shared_ptr<details::reset_mode_memo> memo;
FileHandle::Type fd; file_handle fd;
int rw; int rw;
}; };

View File

@ -1,9 +1,8 @@
#ifndef UVW_TYPE_INFO_INCLUDE_HPP #ifndef UVW_TYPE_INFO_INCLUDE_HPP
#define UVW_TYPE_INFO_INCLUDE_HPP #define UVW_TYPE_INFO_INCLUDE_HPP
#include <cstddef>
#include <cstdint> #include <cstdint>
#include <string_view> #include "config.h"
namespace uvw { namespace uvw {

View File

@ -6,274 +6,211 @@
namespace uvw { namespace uvw {
UVW_INLINE UDPDataEvent::UDPDataEvent(Addr sndr, std::unique_ptr<char[]> buf, std::size_t len, bool part) noexcept UVW_INLINE udp_data_event::udp_data_event(socket_address sndr, std::unique_ptr<char[]> buf, std::size_t len, bool part) noexcept
: data{std::move(buf)}, length{len}, sender{std::move(sndr)}, partial{part} {} : data{std::move(buf)},
length{len},
sender{std::move(sndr)},
partial{part} {}
UVW_INLINE details::SendReq::SendReq(ConstructorAccess ca, std::shared_ptr<Loop> loop, std::unique_ptr<char[], Deleter> dt, unsigned int len) UVW_INLINE void details::send_req::udp_send_callback(uv_udp_send_t *req, int status) {
: Request<SendReq, uv_udp_send_t>{ca, std::move(loop)}, if(auto ptr = reserve(req); status) {
ptr->publish(error_event{status});
} else {
ptr->publish(send_event{});
}
}
UVW_INLINE details::send_req::send_req(loop::token token, std::shared_ptr<loop> parent, std::unique_ptr<char[], deleter> dt, unsigned int len)
: request{token, std::move(parent)},
data{std::move(dt)}, data{std::move(dt)},
buf{uv_buf_init(data.get(), len)} {} buf{uv_buf_init(data.get(), len)} {}
UVW_INLINE void details::SendReq::send(uv_udp_t *handle, const struct sockaddr *addr) { UVW_INLINE int details::send_req::send(uv_udp_t *hndl, const struct sockaddr *addr) {
invoke(&uv_udp_send, get(), handle, &buf, 1, addr, &defaultCallback<SendEvent>); return this->leak_if(uv_udp_send(raw(), hndl, &buf, 1, addr, &udp_send_callback));
} }
UVW_INLINE UDPHandle::UDPHandle(ConstructorAccess ca, std::shared_ptr<Loop> ref, unsigned int f) UVW_INLINE void udp_handle::recv_callback(uv_udp_t *hndl, ssize_t nread, const uv_buf_t *buf, const sockaddr *addr, unsigned flags) {
: Handle{ca, std::move(ref)}, tag{FLAGS}, flags{f} {} udp_handle &udp = *(static_cast<udp_handle *>(hndl->data));
// data will be destroyed no matter of what the value of nread is
std::unique_ptr<char[]> data{buf->base};
UVW_INLINE bool UDPHandle::init() { if(nread > 0) {
return (tag == FLAGS) ? initialize(&uv_udp_init_ex, flags) : initialize(&uv_udp_init); // data available (can be truncated)
udp.publish(udp_data_event{details::sock_addr(*addr), std::move(data), static_cast<std::size_t>(nread), !(0 == (flags & UV_UDP_PARTIAL))});
} else if(nread == 0 && addr == nullptr) {
// no more data to be read, doing nothing is fine
} else if(nread == 0 && addr != nullptr) {
// empty udp packet
udp.publish(udp_data_event{details::sock_addr(*addr), std::move(data), static_cast<std::size_t>(nread), false});
} else {
// transmission error
udp.publish(error_event(nread));
}
} }
UVW_INLINE void UDPHandle::open(OSSocketHandle socket) { UVW_INLINE udp_handle::udp_handle(loop::token token, std::shared_ptr<loop> ref, unsigned int f)
invoke(&uv_udp_open, get(), socket); : handle{token, std::move(ref)}, tag{FLAGS}, flags{f} {}
UVW_INLINE int udp_handle::init() {
if(tag == FLAGS) {
return leak_if(uv_udp_init_ex(parent().raw(), raw(), flags));
} else {
return leak_if(uv_udp_init(parent().raw(), raw()));
}
} }
UVW_INLINE void UDPHandle::bind(const sockaddr &addr, Flags<UDPHandle::Bind> opts) { UVW_INLINE int udp_handle::open(os_socket_handle socket) {
invoke(&uv_udp_bind, get(), &addr, opts); return uv_udp_open(raw(), socket);
} }
UVW_INLINE void UDPHandle::connect(const sockaddr &addr) { UVW_INLINE int udp_handle::connect(const sockaddr &addr) {
invoke(&uv_udp_connect, get(), &addr); return uv_udp_connect(raw(), &addr);
} }
template<typename I> UVW_INLINE int udp_handle::connect(const std::string &ip, unsigned int port) {
UVW_INLINE void UDPHandle::connect(const std::string &ip, unsigned int port) { return connect(details::ip_addr(ip.data(), port));
typename details::IpTraits<I>::Type addr;
details::IpTraits<I>::addrFunc(ip.data(), port, &addr);
connect(reinterpret_cast<const sockaddr &>(addr));
} }
template<typename I> UVW_INLINE int udp_handle::connect(socket_address addr) {
UVW_INLINE void UDPHandle::connect(Addr addr) { return connect(addr.ip, addr.port);
connect<I>(std::move(addr.ip), addr.port);
} }
UVW_INLINE void UDPHandle::disconnect() { UVW_INLINE int udp_handle::disconnect() {
invoke(&uv_udp_connect, get(), nullptr); return uv_udp_connect(raw(), nullptr);
} }
template<typename I> UVW_INLINE socket_address udp_handle::peer() const noexcept {
UVW_INLINE Addr UDPHandle::peer() const noexcept { sockaddr_storage storage;
return details::address<I>(&uv_udp_getpeername, get()); int len = sizeof(sockaddr_storage);
uv_udp_getpeername(raw(), reinterpret_cast<sockaddr *>(&storage), &len);
return details::sock_addr(storage);
} }
template<typename I> UVW_INLINE int udp_handle::bind(const sockaddr &addr, udp_handle::udp_flags opts) {
UVW_INLINE void UDPHandle::bind(const std::string &ip, unsigned int port, Flags<Bind> opts) { return uv_udp_bind(raw(), &addr, static_cast<uv_udp_flags>(opts));
typename details::IpTraits<I>::Type addr;
details::IpTraits<I>::addrFunc(ip.data(), port, &addr);
bind(reinterpret_cast<const sockaddr &>(addr), std::move(opts));
} }
template<typename I> UVW_INLINE int udp_handle::bind(const std::string &ip, unsigned int port, udp_flags opts) {
UVW_INLINE void UDPHandle::bind(Addr addr, Flags<Bind> opts) { return bind(details::ip_addr(ip.data(), port), opts);
bind<I>(std::move(addr.ip), addr.port, std::move(opts));
} }
template<typename I> UVW_INLINE int udp_handle::bind(socket_address addr, udp_flags opts) {
UVW_INLINE Addr UDPHandle::sock() const noexcept { return bind(addr.ip, addr.port, opts);
return details::address<I>(&uv_udp_getsockname, get());
} }
template<typename I> UVW_INLINE socket_address udp_handle::sock() const noexcept {
UVW_INLINE bool UDPHandle::multicastMembership(const std::string &multicast, const std::string &iface, Membership membership) { sockaddr_storage storage;
return (0 == uv_udp_set_membership(get(), multicast.data(), iface.data(), static_cast<uv_membership>(membership))); int len = sizeof(sockaddr_storage);
uv_udp_getsockname(raw(), reinterpret_cast<sockaddr *>(&storage), &len);
return details::sock_addr(storage);
} }
UVW_INLINE bool UDPHandle::multicastLoop(bool enable) { UVW_INLINE bool udp_handle::multicast_membership(const std::string &multicast, const std::string &iface, membership ms) {
return (0 == uv_udp_set_multicast_loop(get(), enable)); return (0 == uv_udp_set_membership(raw(), multicast.data(), iface.data(), static_cast<uv_membership>(ms)));
} }
UVW_INLINE bool UDPHandle::multicastTtl(int val) { UVW_INLINE bool udp_handle::multicast_loop(bool enable) {
return (0 == uv_udp_set_multicast_ttl(get(), val > 255 ? 255 : val)); return (0 == uv_udp_set_multicast_loop(raw(), enable));
} }
template<typename I> UVW_INLINE bool udp_handle::multicast_ttl(int val) {
UVW_INLINE bool UDPHandle::multicastInterface(const std::string &iface) { return (0 == uv_udp_set_multicast_ttl(raw(), val > 255 ? 255 : val));
return (0 == uv_udp_set_multicast_interface(get(), iface.data()));
} }
UVW_INLINE bool UDPHandle::broadcast(bool enable) { UVW_INLINE bool udp_handle::multicast_interface(const std::string &iface) {
return (0 == uv_udp_set_broadcast(get(), enable)); return (0 == uv_udp_set_multicast_interface(raw(), iface.data()));
} }
UVW_INLINE bool UDPHandle::ttl(int val) { UVW_INLINE bool udp_handle::broadcast(bool enable) {
return (0 == uv_udp_set_ttl(get(), val > 255 ? 255 : val)); return (0 == uv_udp_set_broadcast(raw(), enable));
} }
UVW_INLINE void UDPHandle::send(const sockaddr &addr, std::unique_ptr<char[]> data, unsigned int len) { UVW_INLINE bool udp_handle::ttl(int val) {
auto req = loop().resource<details::SendReq>(std::unique_ptr<char[], details::SendReq::Deleter>{data.release(), [](char *ptr) { delete[] ptr; }}, len); return (0 == uv_udp_set_ttl(raw(), val > 255 ? 255 : val));
}
UVW_INLINE int udp_handle::send(const sockaddr &addr, std::unique_ptr<char[]> data, unsigned int len) {
auto req = parent().resource<details::send_req>(std::unique_ptr<char[], details::send_req::deleter>{data.release(), [](char *ptr) { delete[] ptr; }}, len);
auto listener = [ptr = shared_from_this()](const auto &event, const auto &) { auto listener = [ptr = shared_from_this()](const auto &event, const auto &) {
ptr->publish(event); ptr->publish(event);
}; };
req->once<ErrorEvent>(listener); req->on<error_event>(listener);
req->once<SendEvent>(listener); req->on<send_event>(listener);
req->send(get(), &addr);
return req->send(raw(), &addr);
} }
template<typename I> UVW_INLINE int udp_handle::send(const std::string &ip, unsigned int port, std::unique_ptr<char[]> data, unsigned int len) {
UVW_INLINE void UDPHandle::send(const std::string &ip, unsigned int port, std::unique_ptr<char[]> data, unsigned int len) { return send(details::ip_addr(ip.data(), port), std::move(data), len);
typename details::IpTraits<I>::Type addr;
details::IpTraits<I>::addrFunc(ip.data(), port, &addr);
send(reinterpret_cast<const sockaddr &>(addr), std::move(data), len);
} }
template<typename I> UVW_INLINE int udp_handle::send(socket_address addr, std::unique_ptr<char[]> data, unsigned int len) {
UVW_INLINE void UDPHandle::send(Addr addr, std::unique_ptr<char[]> data, unsigned int len) { return send(addr.ip, addr.port, std::move(data), len);
send<I>(std::move(addr.ip), addr.port, std::move(data), len);
} }
UVW_INLINE void UDPHandle::send(const sockaddr &addr, char *data, unsigned int len) { UVW_INLINE int udp_handle::send(const sockaddr &addr, char *data, unsigned int len) {
auto req = loop().resource<details::SendReq>(std::unique_ptr<char[], details::SendReq::Deleter>{data, [](char *) {}}, len); auto req = parent().resource<details::send_req>(std::unique_ptr<char[], details::send_req::deleter>{data, [](char *) {}}, len);
auto listener = [ptr = shared_from_this()](const auto &event, const auto &) { auto listener = [ptr = shared_from_this()](const auto &event, const auto &) {
ptr->publish(event); ptr->publish(event);
}; };
req->once<ErrorEvent>(listener); req->on<error_event>(listener);
req->once<SendEvent>(listener); req->on<send_event>(listener);
req->send(get(), &addr);
return req->send(raw(), &addr);
} }
template<typename I> UVW_INLINE int udp_handle::send(const std::string &ip, unsigned int port, char *data, unsigned int len) {
UVW_INLINE void UDPHandle::send(const std::string &ip, unsigned int port, char *data, unsigned int len) { return send(details::ip_addr(ip.data(), port), data, len);
typename details::IpTraits<I>::Type addr;
details::IpTraits<I>::addrFunc(ip.data(), port, &addr);
send(reinterpret_cast<const sockaddr &>(addr), data, len);
} }
template<typename I> UVW_INLINE int udp_handle::send(socket_address addr, char *data, unsigned int len) {
UVW_INLINE void UDPHandle::send(Addr addr, char *data, unsigned int len) { return send(addr.ip, addr.port, data, len);
send<I>(std::move(addr.ip), addr.port, data, len);
} }
template<typename I> UVW_INLINE int udp_handle::try_send(const sockaddr &addr, std::unique_ptr<char[]> data, unsigned int len) {
UVW_INLINE int UDPHandle::trySend(const sockaddr &addr, std::unique_ptr<char[]> data, unsigned int len) {
uv_buf_t bufs[] = {uv_buf_init(data.get(), len)}; uv_buf_t bufs[] = {uv_buf_init(data.get(), len)};
auto bw = uv_udp_try_send(get(), bufs, 1, &addr); return uv_udp_try_send(raw(), bufs, 1, &addr);
if(bw < 0) {
publish(ErrorEvent{bw});
bw = 0;
}
return bw;
} }
template<typename I> UVW_INLINE int udp_handle::try_send(const std::string &ip, unsigned int port, std::unique_ptr<char[]> data, unsigned int len) {
UVW_INLINE int UDPHandle::trySend(const std::string &ip, unsigned int port, std::unique_ptr<char[]> data, unsigned int len) { return try_send(details::ip_addr(ip.data(), port), std::move(data), len);
typename details::IpTraits<I>::Type addr;
details::IpTraits<I>::addrFunc(ip.data(), port, &addr);
return trySend(reinterpret_cast<const sockaddr &>(addr), std::move(data), len);
} }
template<typename I> UVW_INLINE int udp_handle::try_send(socket_address addr, std::unique_ptr<char[]> data, unsigned int len) {
UVW_INLINE int UDPHandle::trySend(Addr addr, std::unique_ptr<char[]> data, unsigned int len) { return try_send(addr.ip, addr.port, std::move(data), len);
return trySend<I>(std::move(addr.ip), addr.port, std::move(data), len);
} }
template<typename I> UVW_INLINE int udp_handle::try_send(const sockaddr &addr, char *data, unsigned int len) {
UVW_INLINE int UDPHandle::trySend(const sockaddr &addr, char *data, unsigned int len) {
uv_buf_t bufs[] = {uv_buf_init(data, len)}; uv_buf_t bufs[] = {uv_buf_init(data, len)};
auto bw = uv_udp_try_send(get(), bufs, 1, &addr); return uv_udp_try_send(raw(), bufs, 1, &addr);
if(bw < 0) {
publish(ErrorEvent{bw});
bw = 0;
}
return bw;
} }
template<typename I> UVW_INLINE int udp_handle::try_send(const std::string &ip, unsigned int port, char *data, unsigned int len) {
UVW_INLINE int UDPHandle::trySend(const std::string &ip, unsigned int port, char *data, unsigned int len) { return try_send(details::ip_addr(ip.data(), port), data, len);
typename details::IpTraits<I>::Type addr;
details::IpTraits<I>::addrFunc(ip.data(), port, &addr);
return trySend(reinterpret_cast<const sockaddr &>(addr), data, len);
} }
template<typename I> UVW_INLINE int udp_handle::try_send(socket_address addr, char *data, unsigned int len) {
UVW_INLINE int UDPHandle::trySend(Addr addr, char *data, unsigned int len) { return try_send(addr.ip, addr.port, data, len);
return trySend<I>(std::move(addr.ip), addr.port, data, len);
} }
template<typename I> UVW_INLINE int udp_handle::recv() {
UVW_INLINE void UDPHandle::recv() { return uv_udp_recv_start(raw(), &details::common_alloc_callback, &recv_callback);
invoke(&uv_udp_recv_start, get(), &allocCallback, &recvCallback<I>);
} }
UVW_INLINE void UDPHandle::stop() { UVW_INLINE int udp_handle::stop() {
invoke(&uv_udp_recv_stop, get()); return uv_udp_recv_stop(raw());
} }
UVW_INLINE size_t UDPHandle::sendQueueSize() const noexcept { UVW_INLINE size_t udp_handle::send_queue_size() const noexcept {
return uv_udp_get_send_queue_size(get()); return uv_udp_get_send_queue_size(raw());
} }
UVW_INLINE size_t UDPHandle::sendQueueCount() const noexcept { UVW_INLINE size_t udp_handle::send_queue_count() const noexcept {
return uv_udp_get_send_queue_count(get()); return uv_udp_get_send_queue_count(raw());
} }
// explicit instantiations
#ifdef UVW_AS_LIB
template void UDPHandle::connect<IPv4>(const std::string &, unsigned int);
template void UDPHandle::connect<IPv6>(const std::string &, unsigned int);
template void UDPHandle::connect<IPv4>(Addr);
template void UDPHandle::connect<IPv6>(Addr);
template Addr UDPHandle::peer<IPv4>() const noexcept;
template Addr UDPHandle::peer<IPv6>() const noexcept;
template void UDPHandle::bind<IPv4>(const std::string &, unsigned int, Flags<Bind>);
template void UDPHandle::bind<IPv6>(const std::string &, unsigned int, Flags<Bind>);
template void UDPHandle::bind<IPv4>(Addr, Flags<Bind>);
template void UDPHandle::bind<IPv6>(Addr, Flags<Bind>);
template Addr UDPHandle::sock<IPv4>() const noexcept;
template Addr UDPHandle::sock<IPv6>() const noexcept;
template bool UDPHandle::multicastMembership<IPv4>(const std::string &, const std::string &, Membership);
template bool UDPHandle::multicastMembership<IPv6>(const std::string &, const std::string &, Membership);
template bool UDPHandle::multicastInterface<IPv4>(const std::string &);
template bool UDPHandle::multicastInterface<IPv6>(const std::string &);
template void UDPHandle::send<IPv4>(const std::string &, unsigned int, std::unique_ptr<char[]>, unsigned int);
template void UDPHandle::send<IPv6>(const std::string &, unsigned int, std::unique_ptr<char[]>, unsigned int);
template void UDPHandle::send<IPv4>(Addr, std::unique_ptr<char[]>, unsigned int);
template void UDPHandle::send<IPv6>(Addr, std::unique_ptr<char[]>, unsigned int);
template void UDPHandle::send<IPv4>(const std::string &, unsigned int, char *, unsigned int);
template void UDPHandle::send<IPv6>(const std::string &, unsigned int, char *, unsigned int);
template void UDPHandle::send<IPv4>(Addr, char *, unsigned int);
template void UDPHandle::send<IPv6>(Addr, char *, unsigned int);
template int UDPHandle::trySend<IPv4>(const sockaddr &, std::unique_ptr<char[]>, unsigned int);
template int UDPHandle::trySend<IPv6>(const sockaddr &, std::unique_ptr<char[]>, unsigned int);
template int UDPHandle::trySend<IPv4>(const std::string &, unsigned int, std::unique_ptr<char[]>, unsigned int);
template int UDPHandle::trySend<IPv6>(const std::string &, unsigned int, std::unique_ptr<char[]>, unsigned int);
template int UDPHandle::trySend<IPv4>(Addr, std::unique_ptr<char[]>, unsigned int);
template int UDPHandle::trySend<IPv6>(Addr, std::unique_ptr<char[]>, unsigned int);
template int UDPHandle::trySend<IPv4>(const sockaddr &, char *, unsigned int);
template int UDPHandle::trySend<IPv6>(const sockaddr &, char *, unsigned int);
template int UDPHandle::trySend<IPv4>(const std::string &, unsigned int, char *, unsigned int);
template int UDPHandle::trySend<IPv6>(const std::string &, unsigned int, char *, unsigned int);
template int UDPHandle::trySend<IPv4>(Addr, char *, unsigned int);
template int UDPHandle::trySend<IPv6>(Addr, char *, unsigned int);
template void UDPHandle::recv<IPv4>();
template void UDPHandle::recv<IPv6>();
#endif // UVW_AS_LIB
} // namespace uvw } // namespace uvw

View File

@ -7,73 +7,70 @@
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include <uv.h> #include <uv.h>
#include "config.h"
#include "enum.hpp"
#include "handle.hpp" #include "handle.hpp"
#include "request.hpp" #include "request.hpp"
#include "util.h" #include "util.h"
namespace uvw { namespace uvw {
/** /*! @brief Send event. */
* @brief SendEvent event. struct send_event {};
*
* It will be emitted by UDPHandle according with its functionalities.
*/
struct SendEvent {};
/** /*! @brief UDP data event. */
* @brief UDPDataEvent event. struct udp_data_event {
* explicit udp_data_event(socket_address sndr, std::unique_ptr<char[]> buf, std::size_t len, bool part) noexcept;
* It will be emitted by UDPHandle according with its functionalities.
*/
struct UDPDataEvent {
explicit UDPDataEvent(Addr sndr, std::unique_ptr<char[]> buf, std::size_t len, bool part) noexcept;
std::unique_ptr<char[]> data; /*!< A bunch of data read on the stream. */ std::unique_ptr<char[]> data; /*!< A bunch of data read on the stream. */
std::size_t length; /*!< The amount of data read on the stream. */ std::size_t length; /*!< The amount of data read on the stream. */
Addr sender; /*!< A valid instance of Addr. */ socket_address sender; /*!< A valid instance of socket_address. */
bool partial; /*!< True if the message was truncated, false otherwise. */ bool partial; /*!< True if the message was truncated, false otherwise. */
}; };
namespace details { namespace details {
enum class UVUDPFlags : std::underlying_type_t<uv_udp_flags> { enum class uvw_udp_flags : std::underlying_type_t<uv_udp_flags> {
IPV6ONLY = UV_UDP_IPV6ONLY, IPV6ONLY = UV_UDP_IPV6ONLY,
UDP_PARTIAL = UV_UDP_PARTIAL, UDP_PARTIAL = UV_UDP_PARTIAL,
REUSEADDR = UV_UDP_REUSEADDR, REUSEADDR = UV_UDP_REUSEADDR,
UDP_MMSG_CHUNK = UV_UDP_MMSG_CHUNK, UDP_MMSG_CHUNK = UV_UDP_MMSG_CHUNK,
UDP_MMSG_FREE = UV_UDP_MMSG_FREE, UDP_MMSG_FREE = UV_UDP_MMSG_FREE,
UDP_LINUX_RECVERR = UV_UDP_LINUX_RECVERR, UDP_LINUX_RECVERR = UV_UDP_LINUX_RECVERR,
UDP_RECVMMSG = UV_UDP_RECVMMSG UDP_RECVMMSG = UV_UDP_RECVMMSG,
_UVW_ENUM = 0
}; };
enum class UVMembership : std::underlying_type_t<uv_membership> { enum class uvw_membership : std::underlying_type_t<uv_membership> {
LEAVE_GROUP = UV_LEAVE_GROUP, LEAVE_GROUP = UV_LEAVE_GROUP,
JOIN_GROUP = UV_JOIN_GROUP JOIN_GROUP = UV_JOIN_GROUP
}; };
class SendReq final: public Request<SendReq, uv_udp_send_t> { class send_req final: public request<send_req, uv_udp_send_t, send_event> {
static void udp_send_callback(uv_udp_send_t *req, int status);
public: public:
using Deleter = void (*)(char *); using deleter = void (*)(char *);
SendReq(ConstructorAccess ca, std::shared_ptr<Loop> loop, std::unique_ptr<char[], Deleter> dt, unsigned int len); send_req(loop::token token, std::shared_ptr<loop> parent, std::unique_ptr<char[], deleter> dt, unsigned int len);
void send(uv_udp_t *handle, const struct sockaddr *addr); int send(uv_udp_t *hndl, const struct sockaddr *addr);
private: private:
std::unique_ptr<char[], Deleter> data; std::unique_ptr<char[], deleter> data;
uv_buf_t buf; uv_buf_t buf;
}; };
} // namespace details } // namespace details
/** /**
* @brief The UDPHandle handle. * @brief The UDP handle.
* *
* UDP handles encapsulate UDP communication for both clients and servers.<br/> * UDP handles encapsulate UDP communication for both clients and servers.<br/>
* By default, _IPv4_ is used as a template parameter. The handle already * By default, _ipv4_ is used as a template parameter. The handle already
* supports _IPv6_ out-of-the-box by using `uvw::IPv6`. * supports _IPv6_ out-of-the-box by using `uvw::ipv6`.
* *
* To create an `UDPHandle` through a `Loop`, arguments follow: * To create an `udp_handle` through a `loop`, arguments follow:
* *
* * An optional integer value that indicates optional flags used to initialize * * An optional integer value that indicates optional flags used to initialize
* the socket. * the socket.
@ -82,42 +79,22 @@ private:
* [documentation](http://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_init_ex) * [documentation](http://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_init_ex)
* for further details. * for further details.
*/ */
class UDPHandle final: public Handle<UDPHandle, uv_udp_t> { class udp_handle final: public handle<udp_handle, uv_udp_t, send_event, udp_data_event> {
template<typename I> static void recv_callback(uv_udp_t *hndl, ssize_t nread, const uv_buf_t *buf, const sockaddr *addr, unsigned flags);
static void recvCallback(uv_udp_t *handle, ssize_t nread, const uv_buf_t *buf, const sockaddr *addr, unsigned flags) {
const typename details::IpTraits<I>::Type *aptr = reinterpret_cast<const typename details::IpTraits<I>::Type *>(addr);
UDPHandle &udp = *(static_cast<UDPHandle *>(handle->data));
// data will be destroyed no matter of what the value of nread is
std::unique_ptr<char[]> data{buf->base};
if(nread > 0) {
// data available (can be truncated)
udp.publish(UDPDataEvent{details::address<I>(aptr), std::move(data), static_cast<std::size_t>(nread), !(0 == (flags & UV_UDP_PARTIAL))});
} else if(nread == 0 && addr == nullptr) {
// no more data to be read, doing nothing is fine
} else if(nread == 0 && addr != nullptr) {
// empty udp packet
udp.publish(UDPDataEvent{details::address<I>(aptr), std::move(data), static_cast<std::size_t>(nread), false});
} else {
// transmission error
udp.publish(ErrorEvent(nread));
}
}
public: public:
using Membership = details::UVMembership; using membership = details::uvw_membership;
using Bind = details::UVUDPFlags; using udp_flags = details::uvw_udp_flags;
using IPv4 = uvw::IPv4; using ipv4 = uvw::ipv4;
using IPv6 = uvw::IPv6; using ipv6 = uvw::ipv6;
explicit UDPHandle(ConstructorAccess ca, std::shared_ptr<Loop> ref, unsigned int f = {}); explicit udp_handle(loop::token token, std::shared_ptr<loop> ref, unsigned int f = {});
/** /**
* @brief Initializes the handle. The actual socket is created lazily. * @brief Initializes the handle. The actual socket is created lazily.
* @return True in case of success, false otherwise. * @return Underlying return value.
*/ */
bool init(); int init() final;
/** /**
* @brief Opens an existing file descriptor or SOCKET as a UDP handle. * @brief Opens an existing file descriptor or SOCKET as a UDP handle.
@ -129,22 +106,84 @@ public:
* [documentation](http://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_open) * [documentation](http://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_open)
* for further details. * for further details.
* *
* @param socket A valid socket handle (either a file descriptor or a SOCKET). * @param socket A valid socket handle (either a file descriptor or a
* SOCKET).
*
* @return Underlying return value.
*/ */
void open(OSSocketHandle socket); int open(os_socket_handle socket);
/**
* @brief Associates the handle to a remote address and port (either IPv4 or
* IPv6).
*
* Every message sent by this handle is automatically sent to the given
* destination.<br/>
* Trying to call this function on an already connected handle isn't
* allowed.
*
* @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
* @return Underlying return value.
*/
int connect(const sockaddr &addr);
/**
* @brief Associates the handle to a remote address and port (either IPv4 or
* IPv6).
*
* Every message sent by this handle is automatically sent to the given
* destination.<br/>
* Trying to call this function on an already connected handle isn't
* allowed.
*
* @param ip The address to which to bind.
* @param port The port to which to bind.
* @return Underlying return value.
*/
int connect(const std::string &ip, unsigned int port);
/**
* @brief Associates the handle to a remote address and port (either IPv4 or
* IPv6).
*
* Every message sent by this handle is automatically sent to the given
* destination.<br/>
* Trying to call this function on an already connected handle isn't
* allowed.
*
* @param addr A valid instance of socket_address.
* @return Underlying return value.
*/
int connect(socket_address addr);
/**
* @brief Disconnects the handle.
*
* Trying to disconnect a handle that is not connected isn't allowed.
*
* @return Underlying return value.
*/
int disconnect();
/**
* @brief Gets the remote address to which the handle is connected, if any.
* @return A valid instance of socket_address, an empty one in case of
* errors.
*/
socket_address peer() const noexcept;
/** /**
* @brief Binds the UDP handle to an IP address and port. * @brief Binds the UDP handle to an IP address and port.
* *
* Available flags are: * Available flags are:
* *
* * `UDPHandle::Bind::IPV6ONLY` * * `udp_handle::udp_flags::IPV6ONLY`
* * `UDPHandle::Bind::UDP_PARTIAL` * * `udp_handle::udp_flags::UDP_PARTIAL`
* * `UDPHandle::Bind::REUSEADDR` * * `udp_handle::udp_flags::REUSEADDR`
* * `UDPHandle::Bind::UDP_MMSG_CHUNK` * * `udp_handle::udp_flags::UDP_MMSG_CHUNK`
* * `UDPHandle::Bind::UDP_MMSG_FREE` * * `udp_handle::udp_flags::UDP_MMSG_FREE`
* * `UDPHandle::Bind::UDP_LINUX_RECVERR` * * `udp_handle::udp_flags::UDP_LINUX_RECVERR`
* * `UDPHandle::Bind::UDP_RECVMMSG` * * `udp_handle::udp_flags::UDP_RECVMMSG`
* *
* See the official * See the official
* [documentation](http://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_flags) * [documentation](http://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_flags)
@ -152,85 +191,22 @@ public:
* *
* @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure. * @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
* @param opts Optional additional flags. * @param opts Optional additional flags.
* @return Underlying return value.
*/ */
void bind(const sockaddr &addr, Flags<Bind> opts = Flags<Bind>{}); int bind(const sockaddr &addr, udp_flags opts = udp_flags::_UVW_ENUM);
/**
* @brief Associates the handle to a remote address and port (either IPv4 or
* IPv6).
*
* Every message sent by this handle is automatically sent to the given
* destination.<br/>
* Trying to call this function on an already connected handle isn't
* allowed.
*
* An ErrorEvent event is emitted in case of errors during the connection.
*
* @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
*/
void connect(const sockaddr &addr);
/**
* @brief Associates the handle to a remote address and port (either IPv4 or
* IPv6).
*
* Every message sent by this handle is automatically sent to the given
* destination.<br/>
* Trying to call this function on an already connected handle isn't
* allowed.
*
* An ErrorEvent event is emitted in case of errors during the connection.
*
* @param ip The address to which to bind.
* @param port The port to which to bind.
*/
template<typename I = IPv4>
void connect(const std::string &ip, unsigned int port);
/**
* @brief Associates the handle to a remote address and port (either IPv4 or
* IPv6).
*
* Every message sent by this handle is automatically sent to the given
* destination.<br/>
* Trying to call this function on an already connected handle isn't
* allowed.
*
* An ErrorEvent event is emitted in case of errors during the connection.
*
* @param addr A valid instance of Addr.
*/
template<typename I = IPv4>
void connect(Addr addr);
/**
* @brief Disconnects the handle.
*
* Trying to disconnect a handle that is not connected isn't allowed.
*
* An ErrorEvent event is emitted in case of errors.
*/
void disconnect();
/**
* @brief Gets the remote address to which the handle is connected, if any.
* @return A valid instance of Addr, an empty one in case of errors.
*/
template<typename I = IPv4>
Addr peer() const noexcept;
/** /**
* @brief Binds the UDP handle to an IP address and port. * @brief Binds the UDP handle to an IP address and port.
* *
* Available flags are: * Available flags are:
* *
* * `UDPHandle::Bind::IPV6ONLY` * * `udp_handle::udp_flags::IPV6ONLY`
* * `UDPHandle::Bind::UDP_PARTIAL` * * `udp_handle::udp_flags::UDP_PARTIAL`
* * `UDPHandle::Bind::REUSEADDR` * * `udp_handle::udp_flags::REUSEADDR`
* * `UDPHandle::Bind::UDP_MMSG_CHUNK` * * `udp_handle::udp_flags::UDP_MMSG_CHUNK`
* * `UDPHandle::Bind::UDP_MMSG_FREE` * * `udp_handle::udp_flags::UDP_MMSG_FREE`
* * `UDPHandle::Bind::UDP_LINUX_RECVERR` * * `udp_handle::udp_flags::UDP_LINUX_RECVERR`
* * `UDPHandle::Bind::UDP_RECVMMSG` * * `udp_handle::udp_flags::UDP_RECVMMSG`
* *
* See the official * See the official
* [documentation](http://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_flags) * [documentation](http://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_flags)
@ -239,55 +215,54 @@ public:
* @param ip The IP address to which to bind. * @param ip The IP address to which to bind.
* @param port The port to which to bind. * @param port The port to which to bind.
* @param opts Optional additional flags. * @param opts Optional additional flags.
* @return Underlying return value.
*/ */
template<typename I = IPv4> int bind(const std::string &ip, unsigned int port, udp_flags opts = udp_flags::_UVW_ENUM);
void bind(const std::string &ip, unsigned int port, Flags<Bind> opts = Flags<Bind>{});
/** /**
* @brief Binds the UDP handle to an IP address and port. * @brief Binds the UDP handle to an IP address and port.
* *
* Available flags are: * Available flags are:
* *
* * `UDPHandle::Bind::IPV6ONLY` * * `udp_handle::udp_flags::IPV6ONLY`
* * `UDPHandle::Bind::UDP_PARTIAL` * * `udp_handle::udp_flags::UDP_PARTIAL`
* * `UDPHandle::Bind::REUSEADDR` * * `udp_handle::udp_flags::REUSEADDR`
* * `UDPHandle::Bind::UDP_MMSG_CHUNK` * * `udp_handle::udp_flags::UDP_MMSG_CHUNK`
* * `UDPHandle::Bind::UDP_MMSG_FREE` * * `udp_handle::udp_flags::UDP_MMSG_FREE`
* * `UDPHandle::Bind::UDP_LINUX_RECVERR` * * `udp_handle::udp_flags::UDP_LINUX_RECVERR`
* * `UDPHandle::Bind::UDP_RECVMMSG` * * `udp_handle::udp_flags::UDP_RECVMMSG`
* *
* See the official * See the official
* [documentation](http://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_flags) * [documentation](http://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_flags)
* for further details. * for further details.
* *
* @param addr A valid instance of Addr. * @param addr A valid instance of socket_address.
* @param opts Optional additional flags. * @param opts Optional additional flags.
* @return Underlying return value.
*/ */
template<typename I = IPv4> int bind(socket_address addr, udp_flags opts = udp_flags::_UVW_ENUM);
void bind(Addr addr, Flags<Bind> opts = Flags<Bind>{});
/** /**
* @brief Get the local IP and port of the UDP handle. * @brief Get the local IP and port of the UDP handle.
* @return A valid instance of Addr, an empty one in case of errors. * @return A valid instance of socket_address, an empty one in case of
* errors.
*/ */
template<typename I = IPv4> socket_address sock() const noexcept;
Addr sock() const noexcept;
/** /**
* @brief Sets membership for a multicast address. * @brief Sets membership for a multicast address.
* *
* Available values for `membership` are: * Available values for `ms` are:
* *
* * `UDPHandle::Membership::LEAVE_GROUP` * * `udp_handle::membership::LEAVE_GROUP`
* * `UDPHandle::Membership::JOIN_GROUP` * * `udp_handle::membership::JOIN_GROUP`
* *
* @param multicast Multicast address to set membership for. * @param multicast Multicast address to set membership for.
* @param iface Interface address. * @param iface Interface address.
* @param membership Action to be performed. * @param ms Action to be performed.
* @return True in case of success, false otherwise. * @return True in case of success, false otherwise.
*/ */
template<typename I = IPv4> bool multicast_membership(const std::string &multicast, const std::string &iface, membership ms);
bool multicastMembership(const std::string &multicast, const std::string &iface, Membership membership);
/** /**
* @brief Sets IP multicast loop flag. * @brief Sets IP multicast loop flag.
@ -297,22 +272,21 @@ public:
* @param enable True to enable multicast loop, false otherwise. * @param enable True to enable multicast loop, false otherwise.
* @return True in case of success, false otherwise. * @return True in case of success, false otherwise.
*/ */
bool multicastLoop(bool enable = true); bool multicast_loop(bool enable = true);
/** /**
* @brief Sets the multicast ttl. * @brief Sets the multicast ttl.
* @param val A value in the range `[1, 255]`. * @param val A value in the range `[1, 255]`.
* @return True in case of success, false otherwise. * @return True in case of success, false otherwise.
*/ */
bool multicastTtl(int val); bool multicast_ttl(int val);
/** /**
* @brief Sets the multicast interface to send or receive data on. * @brief Sets the multicast interface to send or receive data on.
* @param iface Interface address. * @param iface Interface address.
* @return True in case of success, false otherwise. * @return True in case of success, false otherwise.
*/ */
template<typename I = IPv4> bool multicast_interface(const std::string &iface);
bool multicastInterface(const std::string &iface);
/** /**
* @brief Sets broadcast on or off. * @brief Sets broadcast on or off.
@ -338,14 +312,14 @@ public:
* The handle takes the ownership of the data and it is in charge of delete * The handle takes the ownership of the data and it is in charge of delete
* them. * them.
* *
* A SendEvent event will be emitted when the data have been sent.<br/> * A send event will be emitted when the data have been sent.
* An ErrorEvent event will be emitted in case of errors.
* *
* @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure. * @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
* @param data The data to be sent. * @param data The data to be sent.
* @param len The lenght of the submitted data. * @param len The lenght of the submitted data.
* @return Underlying return value.
*/ */
void send(const sockaddr &addr, std::unique_ptr<char[]> data, unsigned int len); int send(const sockaddr &addr, std::unique_ptr<char[]> data, unsigned int len);
/** /**
* @brief Sends data over the UDP socket. * @brief Sends data over the UDP socket.
@ -357,16 +331,15 @@ public:
* The handle takes the ownership of the data and it is in charge of delete * The handle takes the ownership of the data and it is in charge of delete
* them. * them.
* *
* A SendEvent event will be emitted when the data have been sent.<br/> * A send event will be emitted when the data have been sent.
* An ErrorEvent event will be emitted in case of errors.
* *
* @param ip The address to which to send data. * @param ip The address to which to send data.
* @param port The port to which to send data. * @param port The port to which to send data.
* @param data The data to be sent. * @param data The data to be sent.
* @param len The lenght of the submitted data. * @param len The lenght of the submitted data.
* @return Underlying return value.
*/ */
template<typename I = IPv4> int send(const std::string &ip, unsigned int port, std::unique_ptr<char[]> data, unsigned int len);
void send(const std::string &ip, unsigned int port, std::unique_ptr<char[]> data, unsigned int len);
/** /**
* @brief Sends data over the UDP socket. * @brief Sends data over the UDP socket.
@ -378,15 +351,14 @@ public:
* The handle takes the ownership of the data and it is in charge of delete * The handle takes the ownership of the data and it is in charge of delete
* them. * them.
* *
* A SendEvent event will be emitted when the data have been sent.<br/> * A send event will be emitted when the data have been sent.
* An ErrorEvent event will be emitted in case of errors.
* *
* @param addr A valid instance of Addr. * @param addr A valid instance of socket_address.
* @param data The data to be sent. * @param data The data to be sent.
* @param len The lenght of the submitted data. * @param len The lenght of the submitted data.
* @return Underlying return value.
*/ */
template<typename I = IPv4> int send(socket_address addr, std::unique_ptr<char[]> data, unsigned int len);
void send(Addr addr, std::unique_ptr<char[]> data, unsigned int len);
/** /**
* @brief Sends data over the UDP socket. * @brief Sends data over the UDP socket.
@ -398,14 +370,14 @@ public:
* The handle doesn't take the ownership of the data. Be sure that their * The handle doesn't take the ownership of the data. Be sure that their
* lifetime overcome the one of the request. * lifetime overcome the one of the request.
* *
* A SendEvent event will be emitted when the data have been sent.<br/> * A send event will be emitted when the data have been sent.
* An ErrorEvent event will be emitted in case of errors.
* *
* @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure. * @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
* @param data The data to be sent. * @param data The data to be sent.
* @param len The lenght of the submitted data. * @param len The lenght of the submitted data.
* @return Underlying return value.
*/ */
void send(const sockaddr &addr, char *data, unsigned int len); int send(const sockaddr &addr, char *data, unsigned int len);
/** /**
* @brief Sends data over the UDP socket. * @brief Sends data over the UDP socket.
@ -417,16 +389,15 @@ public:
* The handle doesn't take the ownership of the data. Be sure that their * The handle doesn't take the ownership of the data. Be sure that their
* lifetime overcome the one of the request. * lifetime overcome the one of the request.
* *
* A SendEvent event will be emitted when the data have been sent.<br/> * A send event will be emitted when the data have been sent.
* An ErrorEvent event will be emitted in case of errors.
* *
* @param ip The address to which to send data. * @param ip The address to which to send data.
* @param port The port to which to send data. * @param port The port to which to send data.
* @param data The data to be sent. * @param data The data to be sent.
* @param len The lenght of the submitted data. * @param len The lenght of the submitted data.
* @return Underlying return value.
*/ */
template<typename I = IPv4> int send(const std::string &ip, unsigned int port, char *data, unsigned int len);
void send(const std::string &ip, unsigned int port, char *data, unsigned int len);
/** /**
* @brief Sends data over the UDP socket. * @brief Sends data over the UDP socket.
@ -438,15 +409,14 @@ public:
* The handle doesn't take the ownership of the data. Be sure that their * The handle doesn't take the ownership of the data. Be sure that their
* lifetime overcome the one of the request. * lifetime overcome the one of the request.
* *
* A SendEvent event will be emitted when the data have been sent.<br/> * A send event will be emitted when the data have been sent.
* An ErrorEvent event will be emitted in case of errors.
* *
* @param addr A valid instance of Addr. * @param addr A valid instance of socket_address.
* @param data The data to be sent. * @param data The data to be sent.
* @param len The lenght of the submitted data. * @param len The lenght of the submitted data.
* @return Underlying return value.
*/ */
template<typename I = IPv4> int send(socket_address addr, char *data, unsigned int len);
void send(Addr addr, char *data, unsigned int len);
/** /**
* @brief Sends data over the UDP socket. * @brief Sends data over the UDP socket.
@ -457,10 +427,9 @@ public:
* @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure. * @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
* @param data The data to be sent. * @param data The data to be sent.
* @param len The lenght of the submitted data. * @param len The lenght of the submitted data.
* @return Number of bytes written. * @return Underlying return value.
*/ */
template<typename I = IPv4> int try_send(const sockaddr &addr, std::unique_ptr<char[]> data, unsigned int len);
int trySend(const sockaddr &addr, std::unique_ptr<char[]> data, unsigned int len);
/** /**
* @brief Sends data over the UDP socket. * @brief Sends data over the UDP socket.
@ -472,10 +441,9 @@ public:
* @param port The port to which to send data. * @param port The port to which to send data.
* @param data The data to be sent. * @param data The data to be sent.
* @param len The lenght of the submitted data. * @param len The lenght of the submitted data.
* @return Number of bytes written. * @return Underlying return value.
*/ */
template<typename I = IPv4> int try_send(const std::string &ip, unsigned int port, std::unique_ptr<char[]> data, unsigned int len);
int trySend(const std::string &ip, unsigned int port, std::unique_ptr<char[]> data, unsigned int len);
/** /**
* @brief Sends data over the UDP socket. * @brief Sends data over the UDP socket.
@ -483,13 +451,12 @@ public:
* Same as `send()`, but it wont queue a send request if it cant be * Same as `send()`, but it wont queue a send request if it cant be
* completed immediately. * completed immediately.
* *
* @param addr A valid instance of Addr. * @param addr A valid instance of socket_address.
* @param data The data to be sent. * @param data The data to be sent.
* @param len The lenght of the submitted data. * @param len The lenght of the submitted data.
* @return Number of bytes written. * @return Underlying return value.
*/ */
template<typename I = IPv4> int try_send(socket_address addr, std::unique_ptr<char[]> data, unsigned int len);
int trySend(Addr addr, std::unique_ptr<char[]> data, unsigned int len);
/** /**
* @brief Sends data over the UDP socket. * @brief Sends data over the UDP socket.
@ -500,10 +467,9 @@ public:
* @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure. * @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
* @param data The data to be sent. * @param data The data to be sent.
* @param len The lenght of the submitted data. * @param len The lenght of the submitted data.
* @return Number of bytes written. * @return Underlying return value.
*/ */
template<typename I = IPv4> int try_send(const sockaddr &addr, char *data, unsigned int len);
int trySend(const sockaddr &addr, char *data, unsigned int len);
/** /**
* @brief Sends data over the UDP socket. * @brief Sends data over the UDP socket.
@ -515,10 +481,9 @@ public:
* @param port The port to which to send data. * @param port The port to which to send data.
* @param data The data to be sent. * @param data The data to be sent.
* @param len The lenght of the submitted data. * @param len The lenght of the submitted data.
* @return Number of bytes written. * @return Underlying return value.
*/ */
template<typename I = IPv4> int try_send(const std::string &ip, unsigned int port, char *data, unsigned int len);
int trySend(const std::string &ip, unsigned int port, char *data, unsigned int len);
/** /**
* @brief Sends data over the UDP socket. * @brief Sends data over the UDP socket.
@ -526,13 +491,12 @@ public:
* Same as `send()`, but it wont queue a send request if it cant be * Same as `send()`, but it wont queue a send request if it cant be
* completed immediately. * completed immediately.
* *
* @param addr A valid instance of Addr. * @param addr A valid instance of socket_address.
* @param data The data to be sent. * @param data The data to be sent.
* @param len The lenght of the submitted data. * @param len The lenght of the submitted data.
* @return Number of bytes written. * @return Underlying return value.
*/ */
template<typename I = IPv4> int try_send(socket_address addr, char *data, unsigned int len);
int trySend(Addr addr, char *data, unsigned int len);
/** /**
* @brief Prepares for receiving data. * @brief Prepares for receiving data.
@ -541,16 +505,17 @@ public:
* is bound to `0.0.0.0` (the _all interfaces_ IPv4 address) and a random * is bound to `0.0.0.0` (the _all interfaces_ IPv4 address) and a random
* port number. * port number.
* *
* An UDPDataEvent event will be emitted when the handle receives data.<br/> * An UDP data event will be emitted when the handle receives data.
* An ErrorEvent event will be emitted in case of errors. *
* @return Underlying return value.
*/ */
template<typename I = IPv4> int recv();
void recv();
/** /**
* @brief Stops listening for incoming datagrams. * @brief Stops listening for incoming datagrams.
* @return Underlying return value.
*/ */
void stop(); int stop();
/** /**
* @brief Gets the number of bytes queued for sending. * @brief Gets the number of bytes queued for sending.
@ -559,13 +524,14 @@ public:
* *
* @return Number of bytes queued for sending. * @return Number of bytes queued for sending.
*/ */
size_t sendQueueSize() const noexcept; size_t send_queue_size() const noexcept;
/** /**
* @brief Number of send requests currently in the queue awaiting to be processed. * @brief Number of send requests currently in the queue awaiting to be
* processed.
* @return Number of send requests currently in the queue. * @return Number of send requests currently in the queue.
*/ */
size_t sendQueueCount() const noexcept; size_t send_queue_count() const noexcept;
private: private:
enum { enum {
@ -576,76 +542,6 @@ private:
unsigned int flags{}; unsigned int flags{};
}; };
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
// (extern) explicit instantiations
#ifdef UVW_AS_LIB
extern template void UDPHandle::connect<IPv4>(const std::string &, unsigned int);
extern template void UDPHandle::connect<IPv6>(const std::string &, unsigned int);
extern template void UDPHandle::connect<IPv4>(Addr);
extern template void UDPHandle::connect<IPv6>(Addr);
extern template Addr UDPHandle::peer<IPv4>() const noexcept;
extern template Addr UDPHandle::peer<IPv6>() const noexcept;
extern template void UDPHandle::bind<IPv4>(const std::string &, unsigned int, Flags<Bind>);
extern template void UDPHandle::bind<IPv6>(const std::string &, unsigned int, Flags<Bind>);
extern template void UDPHandle::bind<IPv4>(Addr, Flags<Bind>);
extern template void UDPHandle::bind<IPv6>(Addr, Flags<Bind>);
extern template Addr UDPHandle::sock<IPv4>() const noexcept;
extern template Addr UDPHandle::sock<IPv6>() const noexcept;
extern template bool UDPHandle::multicastMembership<IPv4>(const std::string &, const std::string &, Membership);
extern template bool UDPHandle::multicastMembership<IPv6>(const std::string &, const std::string &, Membership);
extern template bool UDPHandle::multicastInterface<IPv4>(const std::string &);
extern template bool UDPHandle::multicastInterface<IPv6>(const std::string &);
extern template void UDPHandle::send<IPv4>(const std::string &, unsigned int, std::unique_ptr<char[]>, unsigned int);
extern template void UDPHandle::send<IPv6>(const std::string &, unsigned int, std::unique_ptr<char[]>, unsigned int);
extern template void UDPHandle::send<IPv4>(Addr, std::unique_ptr<char[]>, unsigned int);
extern template void UDPHandle::send<IPv6>(Addr, std::unique_ptr<char[]>, unsigned int);
extern template void UDPHandle::send<IPv4>(const std::string &, unsigned int, char *, unsigned int);
extern template void UDPHandle::send<IPv6>(const std::string &, unsigned int, char *, unsigned int);
extern template void UDPHandle::send<IPv4>(Addr, char *, unsigned int);
extern template void UDPHandle::send<IPv6>(Addr, char *, unsigned int);
extern template int UDPHandle::trySend<IPv4>(const sockaddr &, std::unique_ptr<char[]>, unsigned int);
extern template int UDPHandle::trySend<IPv6>(const sockaddr &, std::unique_ptr<char[]>, unsigned int);
extern template int UDPHandle::trySend<IPv4>(const std::string &, unsigned int, std::unique_ptr<char[]>, unsigned int);
extern template int UDPHandle::trySend<IPv6>(const std::string &, unsigned int, std::unique_ptr<char[]>, unsigned int);
extern template int UDPHandle::trySend<IPv4>(Addr, std::unique_ptr<char[]>, unsigned int);
extern template int UDPHandle::trySend<IPv6>(Addr, std::unique_ptr<char[]>, unsigned int);
extern template int UDPHandle::trySend<IPv4>(const sockaddr &, char *, unsigned int);
extern template int UDPHandle::trySend<IPv6>(const sockaddr &, char *, unsigned int);
extern template int UDPHandle::trySend<IPv4>(const std::string &, unsigned int, char *, unsigned int);
extern template int UDPHandle::trySend<IPv6>(const std::string &, unsigned int, char *, unsigned int);
extern template int UDPHandle::trySend<IPv4>(Addr, char *, unsigned int);
extern template int UDPHandle::trySend<IPv6>(Addr, char *, unsigned int);
extern template void UDPHandle::recv<IPv4>();
extern template void UDPHandle::recv<IPv6>();
#endif // UVW_AS_LIB
/**
* Internal details not to be documented.
* @endcond
*/
} // namespace uvw } // namespace uvw
#ifndef UVW_AS_LIB #ifndef UVW_AS_LIB

View File

@ -1,118 +0,0 @@
#ifndef UVW_UNDERLYING_TYPE_INCLUDE_H
#define UVW_UNDERLYING_TYPE_INCLUDE_H
#include <memory>
#include <type_traits>
#include <utility>
#include "loop.h"
namespace uvw {
/**
* @brief Wrapper class for underlying types.
*
* It acts mainly as a wrapper around data structures of the underlying library.
*/
template<typename T, typename U>
class UnderlyingType {
template<typename, typename>
friend class UnderlyingType;
protected:
struct ConstructorAccess {
explicit ConstructorAccess(int) {}
};
template<typename R = U>
auto get() noexcept {
return reinterpret_cast<R *>(&resource);
}
template<typename R = U>
auto get() const noexcept {
return reinterpret_cast<const R *>(&resource);
}
template<typename R, typename... P>
auto get(UnderlyingType<P...> &other) noexcept {
return reinterpret_cast<R *>(&other.resource);
}
public:
explicit UnderlyingType(ConstructorAccess, std::shared_ptr<Loop> ref) noexcept
: pLoop{std::move(ref)}, resource{} {}
UnderlyingType(const UnderlyingType &) = delete;
UnderlyingType(UnderlyingType &&) = delete;
virtual ~UnderlyingType() {
static_assert(std::is_base_of_v<UnderlyingType<T, U>, T>);
}
UnderlyingType &operator=(const UnderlyingType &) = delete;
UnderlyingType &operator=(UnderlyingType &&) = delete;
/**
* @brief Creates a new resource of the given type.
* @param args Arguments to be forwarded to the actual constructor (if any).
* @return A pointer to the newly created resource.
*/
template<typename... Args>
static std::shared_ptr<T> create(Args &&...args) {
return std::make_shared<T>(ConstructorAccess{0}, std::forward<Args>(args)...);
}
/**
* @brief Gets the loop from which the resource was originated.
* @return A reference to a loop instance.
*/
Loop &loop() const noexcept {
return *pLoop;
}
/**
* @brief Gets the underlying raw data structure.
*
* This function should not be used, unless you know exactly what you are
* doing and what are the risks.<br/>
* Going raw is dangerous, mainly because the lifetime management of a loop,
* a handle or a request is in charge to the library itself and users should
* not work around it.
*
* @warning
* Use this function at your own risk, but do not expect any support in case
* of bugs.
*
* @return The underlying raw data structure.
*/
const U *raw() const noexcept {
return &resource;
}
/**
* @brief Gets the underlying raw data structure.
*
* This function should not be used, unless you know exactly what you are
* doing and what are the risks.<br/>
* Going raw is dangerous, mainly because the lifetime management of a loop,
* a handle or a request is in charge to the library itself and users should
* not work around it.
*
* @warning
* Use this function at your own risk, but do not expect any support in case
* of bugs.
*
* @return The underlying raw data structure.
*/
U *raw() noexcept {
return const_cast<U *>(const_cast<const UnderlyingType *>(this)->raw());
}
private:
std::shared_ptr<Loop> pLoop;
U resource;
};
} // namespace uvw
#endif // UVW_UNDERLYING_TYPE_INCLUDE_H

View File

@ -2,93 +2,146 @@
# include "util.h" # include "util.h"
#endif #endif
#include <algorithm>
#include "config.h" #include "config.h"
namespace uvw { namespace uvw {
UVW_INLINE Passwd::Passwd(std::shared_ptr<uv_passwd_t> pwd) UVW_INLINE passwd_info::passwd_info(std::shared_ptr<uv_passwd_t> pwd)
: passwd{pwd} {} : value{pwd} {}
UVW_INLINE std::string Passwd::username() const noexcept { UVW_INLINE std::string passwd_info::username() const noexcept {
return ((passwd && passwd->username) ? passwd->username : ""); return ((value && value->username) ? value->username : "");
} }
UVW_INLINE decltype(uv_passwd_t::uid) Passwd::uid() const noexcept { UVW_INLINE decltype(uv_passwd_t::uid) passwd_info::uid() const noexcept {
return (passwd ? passwd->uid : decltype(uv_passwd_t::uid){}); return (value ? value->uid : decltype(uv_passwd_t::uid){});
} }
UVW_INLINE decltype(uv_passwd_t::gid) Passwd::gid() const noexcept { UVW_INLINE decltype(uv_passwd_t::gid) passwd_info::gid() const noexcept {
return (passwd ? passwd->gid : decltype(uv_passwd_t::gid){}); return (value ? value->gid : decltype(uv_passwd_t::gid){});
} }
UVW_INLINE std::string Passwd::shell() const noexcept { UVW_INLINE std::string passwd_info::shell() const noexcept {
return ((passwd && passwd->shell) ? passwd->shell : ""); return ((value && value->shell) ? value->shell : "");
} }
UVW_INLINE std::string Passwd::homedir() const noexcept { UVW_INLINE std::string passwd_info::homedir() const noexcept {
return ((passwd && passwd->homedir) ? passwd->homedir : ""); return ((value && value->homedir) ? value->homedir : "");
} }
UVW_INLINE Passwd::operator bool() const noexcept { UVW_INLINE passwd_info::operator bool() const noexcept {
return static_cast<bool>(passwd); return static_cast<bool>(value);
} }
UVW_INLINE UtsName::UtsName(std::shared_ptr<uv_utsname_t> utsname) UVW_INLINE uts_name::uts_name(std::shared_ptr<uv_utsname_t> init)
: utsname{utsname} {} : uname{init} {}
UVW_INLINE std::string UtsName::sysname() const noexcept { UVW_INLINE std::string uts_name::sysname() const noexcept {
return utsname ? utsname->sysname : ""; return uname ? uname->sysname : "";
} }
UVW_INLINE std::string UtsName::release() const noexcept { UVW_INLINE std::string uts_name::release() const noexcept {
return utsname ? utsname->release : ""; return uname ? uname->release : "";
} }
UVW_INLINE std::string UtsName::version() const noexcept { UVW_INLINE std::string uts_name::version() const noexcept {
return utsname ? utsname->version : ""; return uname ? uname->version : "";
} }
UVW_INLINE std::string UtsName::machine() const noexcept { UVW_INLINE std::string uts_name::machine() const noexcept {
return utsname ? utsname->machine : ""; return uname ? uname->machine : "";
} }
UVW_INLINE PidType Utilities::OS::pid() noexcept { namespace details {
UVW_INLINE void common_alloc_callback(uv_handle_t *, std::size_t suggested, uv_buf_t *buf) {
auto size = static_cast<unsigned int>(suggested);
*buf = uv_buf_init(new char[size], size);
}
UVW_INLINE sockaddr ip_addr(const char *addr, unsigned int port) {
if(sockaddr_in addr_in; uv_ip4_addr(addr, port, &addr_in) == 0) {
return reinterpret_cast<const sockaddr &>(addr_in);
} else if(sockaddr_in6 addr_in6; uv_ip6_addr(addr, port, &addr_in6) == 0) {
return reinterpret_cast<const sockaddr &>(addr_in6);
}
return {};
}
UVW_INLINE socket_address sock_addr(const sockaddr_in &addr) {
if(char name[details::DEFAULT_SIZE]; uv_ip4_name(&addr, name, details::DEFAULT_SIZE) == 0) {
return socket_address{std::string{name}, ntohs(addr.sin_port)};
}
return socket_address{};
}
UVW_INLINE socket_address sock_addr(const sockaddr_in6 &addr) {
if(char name[details::DEFAULT_SIZE]; uv_ip6_name(&addr, name, details::DEFAULT_SIZE) == 0) {
return socket_address{std::string{name}, ntohs(addr.sin6_port)};
}
return socket_address{};
}
UVW_INLINE socket_address sock_addr(const sockaddr &addr) {
if(addr.sa_family == AF_INET) {
return sock_addr(reinterpret_cast<const sockaddr_in &>(addr));
} else if(addr.sa_family == AF_INET6) {
return sock_addr(reinterpret_cast<const sockaddr_in6 &>(addr));
}
return socket_address{};
}
UVW_INLINE socket_address sock_addr(const sockaddr_storage &storage) {
if(storage.ss_family == AF_INET) {
return sock_addr(reinterpret_cast<const sockaddr_in &>(storage));
} else if(storage.ss_family == AF_INET6) {
return sock_addr(reinterpret_cast<const sockaddr_in6 &>(storage));
}
return socket_address{};
}
} // namespace details
UVW_INLINE pid_type utilities::os::pid() noexcept {
return uv_os_getpid(); return uv_os_getpid();
} }
UVW_INLINE PidType Utilities::OS::parent() noexcept { UVW_INLINE pid_type utilities::os::ppid() noexcept {
return uv_os_getppid(); return uv_os_getppid();
} }
UVW_INLINE std::string Utilities::OS::homedir() noexcept { UVW_INLINE std::string utilities::os::homedir() noexcept {
return details::tryRead(&uv_os_homedir); return details::try_read(&uv_os_homedir);
} }
UVW_INLINE std::string Utilities::OS::tmpdir() noexcept { UVW_INLINE std::string utilities::os::tmpdir() noexcept {
return details::tryRead(&uv_os_tmpdir); return details::try_read(&uv_os_tmpdir);
} }
UVW_INLINE std::string Utilities::OS::env(const std::string &name) noexcept { UVW_INLINE std::string utilities::os::env(const std::string &name) noexcept {
return details::tryRead(&uv_os_getenv, name.c_str()); return details::try_read(&uv_os_getenv, name.c_str());
} }
UVW_INLINE bool Utilities::OS::env(const std::string &name, const std::string &value) noexcept { UVW_INLINE bool utilities::os::env(const std::string &name, const std::string &value) noexcept {
return (0 == (value.empty() ? uv_os_unsetenv(name.c_str()) : uv_os_setenv(name.c_str(), value.c_str()))); return (0 == (value.empty() ? uv_os_unsetenv(name.c_str()) : uv_os_setenv(name.c_str(), value.c_str())));
} }
UVW_INLINE std::string Utilities::OS::hostname() noexcept { UVW_INLINE std::string utilities::os::hostname() noexcept {
return details::tryRead(&uv_os_gethostname); return details::try_read(&uv_os_gethostname);
} }
UVW_INLINE UtsName Utilities::OS::uname() noexcept { UVW_INLINE uts_name utilities::os::uname() noexcept {
auto ptr = std::make_shared<uv_utsname_t>(); auto ptr = std::make_shared<uv_utsname_t>();
uv_os_uname(ptr.get()); uv_os_uname(ptr.get());
return ptr; return ptr;
} }
UVW_INLINE Passwd Utilities::OS::passwd() noexcept { UVW_INLINE passwd_info utilities::os::passwd() noexcept {
auto deleter = [](uv_passwd_t *passwd) { auto deleter = [](uv_passwd_t *passwd) {
uv_os_free_passwd(passwd); uv_os_free_passwd(passwd);
delete passwd; delete passwd;
@ -99,7 +152,7 @@ UVW_INLINE Passwd Utilities::OS::passwd() noexcept {
return ptr; return ptr;
} }
UVW_INLINE int Utilities::OS::priority(PidType pid) { UVW_INLINE int utilities::os::priority(pid_type pid) {
int prio = 0; int prio = 0;
if(uv_os_getpriority(pid, &prio)) { if(uv_os_getpriority(pid, &prio)) {
@ -109,66 +162,66 @@ UVW_INLINE int Utilities::OS::priority(PidType pid) {
return prio; return prio;
} }
UVW_INLINE bool Utilities::OS::priority(PidType pid, int prio) { UVW_INLINE bool utilities::os::priority(pid_type pid, int prio) {
return 0 == uv_os_setpriority(pid, prio); return 0 == uv_os_setpriority(pid, prio);
} }
UVW_INLINE HandleType Utilities::guessHandle(HandleCategory category) noexcept { UVW_INLINE handle_type utilities::guess_handle(handle_category category) noexcept {
switch(category) { switch(category) {
case UV_ASYNC: case UV_ASYNC:
return HandleType::ASYNC; return handle_type::ASYNC;
case UV_CHECK: case UV_CHECK:
return HandleType::CHECK; return handle_type::CHECK;
case UV_FS_EVENT: case UV_FS_EVENT:
return HandleType::FS_EVENT; return handle_type::FS_EVENT;
case UV_FS_POLL: case UV_FS_POLL:
return HandleType::FS_POLL; return handle_type::FS_POLL;
case UV_HANDLE: case UV_HANDLE:
return HandleType::HANDLE; return handle_type::HANDLE;
case UV_IDLE: case UV_IDLE:
return HandleType::IDLE; return handle_type::IDLE;
case UV_NAMED_PIPE: case UV_NAMED_PIPE:
return HandleType::PIPE; return handle_type::PIPE;
case UV_POLL: case UV_POLL:
return HandleType::POLL; return handle_type::POLL;
case UV_PREPARE: case UV_PREPARE:
return HandleType::PREPARE; return handle_type::PREPARE;
case UV_PROCESS: case UV_PROCESS:
return HandleType::PROCESS; return handle_type::PROCESS;
case UV_STREAM: case UV_STREAM:
return HandleType::STREAM; return handle_type::STREAM;
case UV_TCP: case UV_TCP:
return HandleType::TCP; return handle_type::TCP;
case UV_TIMER: case UV_TIMER:
return HandleType::TIMER; return handle_type::TIMER;
case UV_TTY: case UV_TTY:
return HandleType::TTY; return handle_type::TTY;
case UV_UDP: case UV_UDP:
return HandleType::UDP; return handle_type::UDP;
case UV_SIGNAL: case UV_SIGNAL:
return HandleType::SIGNAL; return handle_type::SIGNAL;
case UV_FILE: case UV_FILE:
return HandleType::FILE; return handle_type::FILE;
default: default:
return HandleType::UNKNOWN; return handle_type::UNKNOWN;
} }
} }
UVW_INLINE HandleType Utilities::guessHandle(FileHandle file) noexcept { UVW_INLINE handle_type utilities::guess_handle(file_handle file) noexcept {
HandleCategory category = uv_guess_handle(file); handle_category category = uv_guess_handle(file);
return guessHandle(category); return guess_handle(category);
} }
UVW_INLINE std::vector<CPUInfo> Utilities::cpuInfo() noexcept { UVW_INLINE std::vector<cpu_info> utilities::cpu() noexcept {
std::vector<CPUInfo> cpuinfos; std::vector<cpu_info> cpuinfos;
uv_cpu_info_t *infos; uv_cpu_info_t *infos;
int count; int count;
if(0 == uv_cpu_info(&infos, &count)) { if(0 == uv_cpu_info(&infos, &count)) {
std::for_each(infos, infos + count, [&cpuinfos](const auto &info) { for (int next = 0; next < count; ++next) {
cpuinfos.push_back({info.model, info.speed, info.cpu_times}); cpuinfos.push_back({infos[next].model, infos[next].speed, infos[next].cpu_times});
}); }
uv_free_cpu_info(infos, count); uv_free_cpu_info(infos, count);
} }
@ -176,30 +229,30 @@ UVW_INLINE std::vector<CPUInfo> Utilities::cpuInfo() noexcept {
return cpuinfos; return cpuinfos;
} }
UVW_INLINE std::vector<InterfaceAddress> Utilities::interfaceAddresses() noexcept { UVW_INLINE std::vector<interface_address> utilities::interface_addresses() noexcept {
std::vector<InterfaceAddress> interfaces; std::vector<interface_address> interfaces;
uv_interface_address_t *ifaces{nullptr}; uv_interface_address_t *ifaces{nullptr};
int count{0}; int count{0};
if(0 == uv_interface_addresses(&ifaces, &count)) { if(0 == uv_interface_addresses(&ifaces, &count)) {
std::for_each(ifaces, ifaces + count, [&interfaces](const auto &iface) { for(int next = 0; next < count; ++next) {
InterfaceAddress interfaceAddress; interface_address iface_addr;
interfaceAddress.name = iface.name; iface_addr.name = ifaces[next].name;
std::copy(iface.phys_addr, (iface.phys_addr + 6), interfaceAddress.physical); std::copy(ifaces[next].phys_addr, (ifaces[next].phys_addr + 6), iface_addr.physical);
interfaceAddress.internal = iface.is_internal == 0 ? false : true; iface_addr.internal = ifaces[next].is_internal == 0 ? false : true;
if(iface.address.address4.sin_family == AF_INET) { if(ifaces[next].address.address4.sin_family == AF_INET) {
interfaceAddress.address = details::address<IPv4>(&iface.address.address4); iface_addr.address = details::sock_addr(ifaces[next].address.address4);
interfaceAddress.netmask = details::address<IPv4>(&iface.netmask.netmask4); iface_addr.netmask = details::sock_addr(ifaces[next].netmask.netmask4);
} else if(iface.address.address4.sin_family == AF_INET6) { } else if(ifaces[next].address.address4.sin_family == AF_INET6) {
interfaceAddress.address = details::address<IPv6>(&iface.address.address6); iface_addr.address = details::sock_addr(ifaces[next].address.address6);
interfaceAddress.netmask = details::address<IPv6>(&iface.netmask.netmask6); iface_addr.netmask = details::sock_addr(ifaces[next].netmask.netmask6);
} }
interfaces.push_back(std::move(interfaceAddress)); interfaces.push_back(std::move(iface_addr));
}); }
uv_free_interface_addresses(ifaces, count); uv_free_interface_addresses(ifaces, count);
} }
@ -207,29 +260,29 @@ UVW_INLINE std::vector<InterfaceAddress> Utilities::interfaceAddresses() noexcep
return interfaces; return interfaces;
} }
UVW_INLINE std::string Utilities::indexToName(unsigned int index) noexcept { UVW_INLINE std::string utilities::index_to_name(unsigned int index) noexcept {
return details::tryRead(&uv_if_indextoname, index); return details::try_read(&uv_if_indextoname, index);
} }
UVW_INLINE std::string Utilities::indexToIid(unsigned int index) noexcept { UVW_INLINE std::string utilities::index_to_iid(unsigned int index) noexcept {
return details::tryRead(&uv_if_indextoiid, index); return details::try_read(&uv_if_indextoiid, index);
} }
UVW_INLINE bool Utilities::replaceAllocator(MallocFuncType mallocFunc, ReallocFuncType reallocFunc, CallocFuncType callocFunc, FreeFuncType freeFunc) noexcept { UVW_INLINE bool utilities::replace_allocator(malloc_func_type malloc_func, realloc_func_type realloc_func, calloc_func_type calloc_func, free_func_type free_func) noexcept {
return (0 == uv_replace_allocator(mallocFunc, reallocFunc, callocFunc, freeFunc)); return (0 == uv_replace_allocator(malloc_func, realloc_func, calloc_func, free_func));
} }
UVW_INLINE std::array<double, 3> Utilities::loadAverage() noexcept { UVW_INLINE std::array<double, 3> utilities::load_average() noexcept {
std::array<double, 3> avg; std::array<double, 3> avg;
uv_loadavg(avg.data()); uv_loadavg(avg.data());
return avg; return avg;
} }
UVW_INLINE char **Utilities::setupArgs(int argc, char **argv) { UVW_INLINE char **utilities::setup_args(int argc, char **argv) {
return uv_setup_args(argc, argv); return uv_setup_args(argc, argv);
} }
UVW_INLINE std::string Utilities::processTitle() { UVW_INLINE std::string utilities::process_title() {
std::size_t size = details::DEFAULT_SIZE; std::size_t size = details::DEFAULT_SIZE;
char buf[details::DEFAULT_SIZE]; char buf[details::DEFAULT_SIZE];
std::string str{}; std::string str{};
@ -241,19 +294,19 @@ UVW_INLINE std::string Utilities::processTitle() {
return str; return str;
} }
UVW_INLINE bool Utilities::processTitle(const std::string &title) { UVW_INLINE bool utilities::process_title(const std::string &title) {
return (0 == uv_set_process_title(title.c_str())); return (0 == uv_set_process_title(title.c_str()));
} }
UVW_INLINE uint64_t Utilities::totalMemory() noexcept { UVW_INLINE uint64_t utilities::total_memory() noexcept {
return uv_get_total_memory(); return uv_get_total_memory();
} }
UVW_INLINE uint64_t Utilities::constrainedMemory() noexcept { UVW_INLINE uint64_t utilities::constrained_memory() noexcept {
return uv_get_constrained_memory(); return uv_get_constrained_memory();
} }
UVW_INLINE double Utilities::uptime() noexcept { UVW_INLINE double utilities::uptime() noexcept {
double ret; double ret;
if(0 != uv_uptime(&ret)) { if(0 != uv_uptime(&ret)) {
@ -263,39 +316,39 @@ UVW_INLINE double Utilities::uptime() noexcept {
return ret; return ret;
} }
UVW_INLINE RUsage Utilities::rusage() noexcept { UVW_INLINE resource_usage utilities::rusage() noexcept {
RUsage ru; resource_usage ru;
auto err = uv_getrusage(&ru); auto err = uv_getrusage(&ru);
return err ? RUsage{} : ru; return err ? resource_usage{} : ru;
} }
UVW_INLINE uint64_t Utilities::hrtime() noexcept { UVW_INLINE uint64_t utilities::hrtime() noexcept {
return uv_hrtime(); return uv_hrtime();
} }
UVW_INLINE std::string Utilities::path() noexcept { UVW_INLINE std::string utilities::path() noexcept {
return details::tryRead(&uv_exepath); return details::try_read(&uv_exepath);
} }
UVW_INLINE std::string Utilities::cwd() noexcept { UVW_INLINE std::string utilities::cwd() noexcept {
return details::tryRead(&uv_cwd); return details::try_read(&uv_cwd);
} }
UVW_INLINE bool Utilities::chdir(const std::string &dir) noexcept { UVW_INLINE bool utilities::chdir(const std::string &dir) noexcept {
return (0 == uv_chdir(dir.data())); return (0 == uv_chdir(dir.data()));
} }
UVW_INLINE TimeVal64 Utilities::timeOfDay() noexcept { UVW_INLINE timeval64 utilities::time_of_day() noexcept {
uv_timeval64_t ret; uv_timeval64_t ret;
uv_gettimeofday(&ret); uv_gettimeofday(&ret);
return ret; return ret;
} }
UVW_INLINE void Utilities::sleep(unsigned int msec) noexcept { UVW_INLINE void utilities::sleep(unsigned int msec) noexcept {
uv_sleep(msec); uv_sleep(msec);
} }
UVW_INLINE unsigned int Utilities::availableParallelism() noexcept { UVW_INLINE unsigned int utilities::available_parallelism() noexcept {
return uv_available_parallelism(); return uv_available_parallelism();
} }

View File

@ -11,12 +11,13 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <uv.h> #include <uv.h>
#include "config.h"
namespace uvw { namespace uvw {
namespace details { namespace details {
enum class UVHandleType : std::underlying_type_t<uv_handle_type> { enum class uvw_handle_type : std::underlying_type_t<uv_handle_type> {
UNKNOWN = UV_UNKNOWN_HANDLE, UNKNOWN = UV_UNKNOWN_HANDLE,
ASYNC = UV_ASYNC, ASYNC = UV_ASYNC,
CHECK = UV_CHECK, CHECK = UV_CHECK,
@ -38,20 +39,20 @@ enum class UVHandleType : std::underlying_type_t<uv_handle_type> {
}; };
template<typename T> template<typename T>
struct UVTypeWrapper { struct uv_type_wrapper {
using Type = T; using Type = T;
constexpr UVTypeWrapper() constexpr uv_type_wrapper()
: value{} {} : value{} {}
constexpr UVTypeWrapper(Type val) constexpr uv_type_wrapper(Type val)
: value{val} {} : value{val} {}
constexpr operator Type() const noexcept { constexpr operator Type() const noexcept {
return value; return value;
} }
bool operator==(UVTypeWrapper other) const noexcept { bool operator==(uv_type_wrapper other) const noexcept {
return value == other.value; return value == other.value;
} }
@ -60,166 +61,40 @@ private:
}; };
template<typename T> template<typename T>
bool operator==(UVTypeWrapper<T> lhs, UVTypeWrapper<T> rhs) { bool operator==(uv_type_wrapper<T> lhs, uv_type_wrapper<T> rhs) {
return !(lhs == rhs); return !(lhs == rhs);
} }
} // namespace details } // namespace details
/**
* @brief Utility class to handle flags.
*
* This class can be used to handle flags of a same enumeration type.<br/>
* It is meant to be used as an argument for functions and member methods and
* as part of events.<br/>
* `Flags<E>` objects can be easily _or-ed_ and _and-ed_ with other instances of
* the same type or with instances of the type `E` (that is, the actual flag
* type), thus converted to the underlying type when needed.
*/
template<typename E>
class Flags final {
static_assert(std::is_enum_v<E>);
using InnerType = std::underlying_type_t<E>;
constexpr InnerType toInnerType(E flag) const noexcept {
return static_cast<InnerType>(flag);
}
public:
using Type = InnerType;
/**
* @brief Utility factory method to pack a set of values all at once.
* @return A valid instance of Flags instantiated from values `V`.
*/
template<E... V>
static constexpr Flags<E> from() {
return (Flags<E>{} | ... | V);
}
/**
* @brief Constructs a Flags object from a value of the enum `E`.
* @param flag A value of the enum `E`.
*/
constexpr Flags(E flag) noexcept
: flags{toInnerType(flag)} {}
/**
* @brief Constructs a Flags object from an instance of the underlying type
* of the enum `E`.
* @param f An instance of the underlying type of the enum `E`.
*/
constexpr Flags(Type f)
: flags{f} {}
/**
* @brief Constructs an uninitialized Flags object.
*/
constexpr Flags()
: flags{} {}
constexpr Flags(const Flags &f) noexcept
: flags{f.flags} {}
constexpr Flags(Flags &&f) noexcept
: flags{std::move(f.flags)} {}
constexpr Flags &operator=(const Flags &f) noexcept {
flags = f.flags;
return *this;
}
constexpr Flags &operator=(Flags &&f) noexcept {
flags = std::move(f.flags);
return *this;
}
/**
* @brief Or operator.
* @param f A valid instance of Flags.
* @return This instance _or-ed_ with `f`.
*/
constexpr Flags operator|(const Flags &f) const noexcept {
return Flags{flags | f.flags};
}
/**
* @brief Or operator.
* @param flag A value of the enum `E`.
* @return This instance _or-ed_ with `flag`.
*/
constexpr Flags operator|(E flag) const noexcept {
return Flags{flags | toInnerType(flag)};
}
/**
* @brief And operator.
* @param f A valid instance of Flags.
* @return This instance _and-ed_ with `f`.
*/
constexpr Flags operator&(const Flags &f) const noexcept {
return Flags{flags & f.flags};
}
/**
* @brief And operator.
* @param flag A value of the enum `E`.
* @return This instance _and-ed_ with `flag`.
*/
constexpr Flags operator&(E flag) const noexcept {
return Flags{flags & toInnerType(flag)};
}
/**
* @brief Checks if this instance is initialized.
* @return False if it's uninitialized, true otherwise.
*/
explicit constexpr operator bool() const noexcept {
return !(flags == InnerType{});
}
/**
* @brief Casts the instance to the underlying type of `E`.
* @return An integral representation of the contained flags.
*/
constexpr operator Type() const noexcept {
return flags;
}
private:
InnerType flags;
};
/** /**
* @brief Windows size representation. * @brief Windows size representation.
*/ */
struct WinSize { struct win_size {
int width; /*!< The _width_ of the given window. */ int width; /*!< The _width_ of the given window. */
int height; /*!< The _height_ of the given window. */ int height; /*!< The _height_ of the given window. */
}; };
using HandleType = details::UVHandleType; /*!< The type of a handle. */ using handle_type = details::uvw_handle_type; /*!< The type of a handle. */
using handle_category = details::uv_type_wrapper<uv_handle_type>; /*!< Utility class that wraps an internal handle type. */
using file_handle = details::uv_type_wrapper<uv_file>; /*!< Utility class that wraps an internal file handle. */
using os_socket_handle = details::uv_type_wrapper<uv_os_sock_t>; /*!< Utility class that wraps an os socket handle. */
using os_file_descriptor = details::uv_type_wrapper<uv_os_fd_t>; /*!< Utility class that wraps an os file descriptor. */
using pid_type = details::uv_type_wrapper<uv_pid_t>; /*!< Utility class that wraps a cross platform representation of a pid. */
using HandleCategory = details::UVTypeWrapper<uv_handle_type>; /*!< Utility class that wraps an internal handle type. */ constexpr file_handle std_in{0}; /*!< Placeholder for stdin descriptor. */
using FileHandle = details::UVTypeWrapper<uv_file>; /*!< Utility class that wraps an internal file handle. */ constexpr file_handle std_out{1}; /*!< Placeholder for stdout descriptor. */
using OSSocketHandle = details::UVTypeWrapper<uv_os_sock_t>; /*!< Utility class that wraps an os socket handle. */ constexpr file_handle std_err{2}; /*!< Placeholder for stderr descriptor. */
using OSFileDescriptor = details::UVTypeWrapper<uv_os_fd_t>; /*!< Utility class that wraps an os file descriptor. */
using PidType = details::UVTypeWrapper<uv_pid_t>; /*!< Utility class that wraps a cross platform representation of a pid. */
constexpr FileHandle StdIN{0}; /*!< Placeholder for stdin descriptor. */ using time_spec = uv_timespec_t; /*!< Library equivalent for uv_timespec_t. */
constexpr FileHandle StdOUT{1}; /*!< Placeholder for stdout descriptor. */ using file_info = uv_stat_t; /*!< Library equivalent for uv_stat_t. */
constexpr FileHandle StdERR{2}; /*!< Placeholder for stderr descriptor. */ using fs_info = uv_statfs_t; /*!< Library equivalent for uv_statfs_t. */
using uid_type = uv_uid_t; /*!< Library equivalent for uv_uid_t. */
using gid_type = uv_gid_t; /*!< Library equivalent for uv_gid_t. */
using TimeSpec = uv_timespec_t; /*!< Library equivalent for uv_timespec_t. */ using timeval = uv_timeval_t; /*!< Library equivalent for uv_timeval_t. */
using Stat = uv_stat_t; /*!< Library equivalent for uv_stat_t. */ using timeval64 = uv_timeval64_t; /*!< Library equivalent for uv_timeval64_t. */
using Statfs = uv_statfs_t; /*!< Library equivalent for uv_statfs_t. */ using resource_usage = uv_rusage_t; /*!< Library equivalent for uv_rusage_t. */
using Uid = uv_uid_t; /*!< Library equivalent for uv_uid_t. */
using Gid = uv_gid_t; /*!< Library equivalent for uv_gid_t. */
using TimeVal = uv_timeval_t; /*!< Library equivalent for uv_timeval_t. */
using TimeVal64 = uv_timeval64_t; /*!< Library equivalent for uv_timeval64_t. */
using RUsage = uv_rusage_t; /*!< Library equivalent for uv_rusage_t. */
/** /**
* @brief Utility class. * @brief Utility class.
@ -227,10 +102,10 @@ using RUsage = uv_rusage_t; /*!< Library equivalent for uv_rusage_t. */
* This class can be used to query the subset of the password file entry for the * This class can be used to query the subset of the password file entry for the
* current effective uid (not the real uid). * current effective uid (not the real uid).
* *
* \sa Utilities::passwd * \sa utilities::passwd
*/ */
struct Passwd { struct passwd_info {
Passwd(std::shared_ptr<uv_passwd_t> pwd); passwd_info(std::shared_ptr<uv_passwd_t> pwd);
/** /**
* @brief Gets the username. * @brief Gets the username.
@ -269,7 +144,7 @@ struct Passwd {
operator bool() const noexcept; operator bool() const noexcept;
private: private:
std::shared_ptr<uv_passwd_t> passwd; std::shared_ptr<uv_passwd_t> value;
}; };
/** /**
@ -279,10 +154,10 @@ private:
* The populated data includes the operating system name, release, version, and * The populated data includes the operating system name, release, version, and
* machine. * machine.
* *
* \sa Utilities::uname * \sa utilities::uname
*/ */
struct UtsName { struct uts_name {
UtsName(std::shared_ptr<uv_utsname_t> utsname); uts_name(std::shared_ptr<uv_utsname_t> init);
/** /**
* @brief Gets the operating system name (like "Linux"). * @brief Gets the operating system name (like "Linux").
@ -309,7 +184,7 @@ struct UtsName {
std::string machine() const noexcept; std::string machine() const noexcept;
private: private:
std::shared_ptr<uv_utsname_t> utsname; std::shared_ptr<uv_utsname_t> uname;
}; };
/** /**
@ -317,19 +192,19 @@ private:
* *
* To be used as template parameter to switch between IPv4 and IPv6. * To be used as template parameter to switch between IPv4 and IPv6.
*/ */
struct IPv4 {}; struct ipv4 {};
/** /**
* @brief The IPv6 tag. * @brief The IPv6 tag.
* *
* To be used as template parameter to switch between IPv4 and IPv6. * To be used as template parameter to switch between IPv4 and IPv6.
*/ */
struct IPv6 {}; struct ipv6 {};
/** /**
* @brief Address representation. * @brief Address representation.
*/ */
struct Addr { struct socket_address {
std::string ip; /*!< Either an IPv4 or an IPv6. */ std::string ip; /*!< Either an IPv4 or an IPv6. */
unsigned int port; /*!< A valid service identifier. */ unsigned int port; /*!< A valid service identifier. */
}; };
@ -337,8 +212,8 @@ struct Addr {
/** /**
* \brief CPU information. * \brief CPU information.
*/ */
struct CPUInfo { struct cpu_info {
using CPUTime = decltype(uv_cpu_info_t::cpu_times); using cpu_time = decltype(uv_cpu_info_t::cpu_times);
std::string model; /*!< The model of the CPU. */ std::string model; /*!< The model of the CPU. */
int speed; /*!< The frequency of the CPU. */ int speed; /*!< The frequency of the CPU. */
@ -349,88 +224,26 @@ struct CPUInfo {
* It is built up of the following data members: `user`, `nice`, `sys`, * It is built up of the following data members: `user`, `nice`, `sys`,
* `idle`, `irq`, all of them having type `uint64_t`. * `idle`, `irq`, all of them having type `uint64_t`.
*/ */
CPUTime times; cpu_time times;
}; };
/** /**
* \brief Interface address. * \brief Interface address.
*/ */
struct InterfaceAddress { struct interface_address {
std::string name; /*!< The name of the interface (as an example _eth0_). */ std::string name; /*!< The name of the interface (as an example _eth0_). */
char physical[6]; /*!< The physical address. */ char physical[6]; /*!< The physical address. */
bool internal; /*!< True if it is an internal interface (as an example _loopback_), false otherwise. */ bool internal; /*!< True if it is an internal interface (as an example _loopback_), false otherwise. */
Addr address; /*!< The address of the given interface. */ socket_address address; /*!< The address of the given interface. */
Addr netmask; /*!< The netmask of the given interface. */ socket_address netmask; /*!< The netmask of the given interface. */
}; };
namespace details { namespace details {
static constexpr std::size_t DEFAULT_SIZE = 128; static constexpr std::size_t DEFAULT_SIZE = 128;
template<typename>
struct IpTraits;
template<>
struct IpTraits<IPv4> {
using Type = sockaddr_in;
using AddrFuncType = int (*)(const char *, int, Type *);
using NameFuncType = int (*)(const Type *, char *, std::size_t);
inline static const AddrFuncType addrFunc = &uv_ip4_addr;
inline static const NameFuncType nameFunc = &uv_ip4_name;
static constexpr auto sinPort(const Type *addr) {
return addr->sin_port;
}
};
template<>
struct IpTraits<IPv6> {
using Type = sockaddr_in6;
using AddrFuncType = int (*)(const char *, int, Type *);
using NameFuncType = int (*)(const Type *, char *, std::size_t);
inline static const AddrFuncType addrFunc = &uv_ip6_addr;
inline static const NameFuncType nameFunc = &uv_ip6_name;
static constexpr auto sinPort(const Type *addr) {
return addr->sin6_port;
}
};
template<typename I>
Addr address(const typename details::IpTraits<I>::Type *aptr) noexcept {
Addr addr{};
char name[DEFAULT_SIZE];
int err = details::IpTraits<I>::nameFunc(aptr, name, DEFAULT_SIZE);
if(0 == err) {
addr.port = ntohs(details::IpTraits<I>::sinPort(aptr));
addr.ip = std::string{name};
}
return addr;
}
template<typename I, typename F, typename H>
Addr address(F &&f, const H *handle) noexcept {
sockaddr_storage ssto;
int len = sizeof(ssto);
Addr addr{};
int err = std::forward<F>(f)(handle, reinterpret_cast<sockaddr *>(&ssto), &len);
if(0 == err) {
typename IpTraits<I>::Type *aptr = reinterpret_cast<typename IpTraits<I>::Type *>(&ssto);
addr = address<I>(aptr);
}
return addr;
}
template<typename F, typename... Args> template<typename F, typename... Args>
std::string tryRead(F &&f, Args &&...args) noexcept { std::string try_read(F &&f, Args &&...args) noexcept {
std::size_t size = DEFAULT_SIZE; std::size_t size = DEFAULT_SIZE;
char buf[DEFAULT_SIZE]; char buf[DEFAULT_SIZE];
std::string str{}; std::string str{};
@ -450,6 +263,14 @@ std::string tryRead(F &&f, Args &&...args) noexcept {
return str; return str;
} }
void common_alloc_callback(uv_handle_t *, std::size_t suggested, uv_buf_t *buf);
sockaddr ip_addr(const char *addr, unsigned int port);
socket_address sock_addr(const sockaddr_in &addr);
socket_address sock_addr(const sockaddr_in6 &addr);
socket_address sock_addr(const sockaddr &addr);
socket_address sock_addr(const sockaddr_storage &storage);
} // namespace details } // namespace details
/** /**
@ -457,16 +278,16 @@ std::string tryRead(F &&f, Args &&...args) noexcept {
* *
* Miscellaneous functions that dont really belong to any other class. * Miscellaneous functions that dont really belong to any other class.
*/ */
struct Utilities { struct utilities {
using MallocFuncType = void *(*)(size_t); using malloc_func_type = void *(*)(size_t);
using ReallocFuncType = void *(*)(void *, size_t); using realloc_func_type = void *(*)(void *, size_t);
using CallocFuncType = void *(*)(size_t, size_t); using calloc_func_type = void *(*)(size_t, size_t);
using FreeFuncType = void (*)(void *); using free_func_type = void (*)(void *);
/** /**
* @brief OS dedicated utilities. * @brief OS dedicated utilities.
*/ */
struct OS { struct os {
/** /**
* @brief Returns the current process id. * @brief Returns the current process id.
* *
@ -476,7 +297,7 @@ struct Utilities {
* *
* @return The current process id. * @return The current process id.
*/ */
static PidType pid() noexcept; static pid_type pid() noexcept;
/** /**
* @brief Returns the parent process id. * @brief Returns the parent process id.
@ -487,7 +308,7 @@ struct Utilities {
* *
* @return The parent process id. * @return The parent process id.
*/ */
static PidType parent() noexcept; static pid_type ppid() noexcept;
/** /**
* @brief Gets the current user's home directory. * @brief Gets the current user's home directory.
@ -576,7 +397,7 @@ struct Utilities {
* *
* @return Name and information about the current kernel. * @return Name and information about the current kernel.
*/ */
static UtsName uname() noexcept; static uts_name uname() noexcept;
/** /**
* @brief Gets a subset of the password file entry. * @brief Gets a subset of the password file entry.
@ -590,7 +411,7 @@ struct Utilities {
* *
* @return The accessible subset of the password file entry. * @return The accessible subset of the password file entry.
*/ */
static Passwd passwd() noexcept; static passwd_info passwd() noexcept;
/** /**
* @brief Retrieves the scheduling priority of a process. * @brief Retrieves the scheduling priority of a process.
@ -605,7 +426,7 @@ struct Utilities {
* @param pid A valid process id. * @param pid A valid process id.
* @return The scheduling priority of the process. * @return The scheduling priority of the process.
*/ */
static int priority(PidType pid); static int priority(pid_type pid);
/** /**
* @brief Sets the scheduling priority of a process. * @brief Sets the scheduling priority of a process.
@ -622,15 +443,15 @@ struct Utilities {
* @param prio The scheduling priority to set to the process. * @param prio The scheduling priority to set to the process.
* @return True in case of success, false otherwise. * @return True in case of success, false otherwise.
*/ */
static bool priority(PidType pid, int prio); static bool priority(pid_type pid, int prio);
}; };
/** /**
* @brief Gets the type of the handle given a category. * @brief Gets the type of the handle given a category.
* @param category A properly initialized handle category. * @param category A properly initialized handle category.
* @return The actual type of the handle as defined by HandleType * @return The actual type of the handle as defined by handle_type
*/ */
static HandleType guessHandle(HandleCategory category) noexcept; static handle_type guess_handle(handle_category category) noexcept;
/** /**
* @brief Gets the type of the stream to be used with the given descriptor. * @brief Gets the type of the stream to be used with the given descriptor.
@ -643,14 +464,14 @@ struct Utilities {
* @param file A valid descriptor. * @param file A valid descriptor.
* @return One of the following types: * @return One of the following types:
* *
* * `HandleType::UNKNOWN` * * `handle_type::UNKNOWN`
* * `HandleType::PIPE` * * `handle_type::PIPE`
* * `HandleType::TCP` * * `handle_type::TCP`
* * `HandleType::TTY` * * `handle_type::TTY`
* * `HandleType::UDP` * * `handle_type::UDP`
* * `HandleType::FILE` * * `handle_type::FILE`
*/ */
static HandleType guessHandle(FileHandle file) noexcept; static handle_type guess_handle(file_handle file) noexcept;
/** @brief Gets information about the CPUs on the system. /** @brief Gets information about the CPUs on the system.
* *
@ -659,7 +480,7 @@ struct Utilities {
* *
* @return A set of descriptors of all the available CPUs. * @return A set of descriptors of all the available CPUs.
*/ */
static std::vector<CPUInfo> cpuInfo() noexcept; static std::vector<cpu_info> cpu() noexcept;
/** /**
* @brief Gets a set of descriptors of all the available interfaces. * @brief Gets a set of descriptors of all the available interfaces.
@ -669,7 +490,7 @@ struct Utilities {
* *
* @return A set of descriptors of all the available interfaces. * @return A set of descriptors of all the available interfaces.
*/ */
static std::vector<InterfaceAddress> interfaceAddresses() noexcept; static std::vector<interface_address> interface_addresses() noexcept;
/** /**
* @brief IPv6-capable implementation of * @brief IPv6-capable implementation of
@ -684,7 +505,7 @@ struct Utilities {
* @param index Network interface index. * @param index Network interface index.
* @return Network interface name. * @return Network interface name.
*/ */
static std::string indexToName(unsigned int index) noexcept; static std::string index_to_name(unsigned int index) noexcept;
/** /**
* @brief Retrieves a network interface identifier. * @brief Retrieves a network interface identifier.
@ -696,7 +517,7 @@ struct Utilities {
* @param index Network interface index. * @param index Network interface index.
* @return Network interface identifier. * @return Network interface identifier.
*/ */
static std::string indexToIid(unsigned int index) noexcept; static std::string index_to_iid(unsigned int index) noexcept;
/** /**
* @brief Override the use of some standard librarys functions. * @brief Override the use of some standard librarys functions.
@ -715,19 +536,19 @@ struct Utilities {
* changed while no memory was allocated with the previous allocator, or * changed while no memory was allocated with the previous allocator, or
* that they are compatible. * that they are compatible.
* *
* @param mallocFunc Replacement function for _malloc_. * @param malloc_func Replacement function for _malloc_.
* @param reallocFunc Replacement function for _realloc_. * @param realloc_func Replacement function for _realloc_.
* @param callocFunc Replacement function for _calloc_. * @param calloc_func Replacement function for _calloc_.
* @param freeFunc Replacement function for _free_. * @param free_func Replacement function for _free_.
* @return True in case of success, false otherwise. * @return True in case of success, false otherwise.
*/ */
static bool replaceAllocator(MallocFuncType mallocFunc, ReallocFuncType reallocFunc, CallocFuncType callocFunc, FreeFuncType freeFunc) noexcept; static bool replace_allocator(malloc_func_type malloc_func, realloc_func_type realloc_func, calloc_func_type calloc_func, free_func_type free_func) noexcept;
/** /**
* @brief Gets the load average. * @brief Gets the load average.
* @return `[0,0,0]` on Windows (not available), the load average otherwise. * @return `[0,0,0]` on Windows (not available), the load average otherwise.
*/ */
static std::array<double, 3> loadAverage() noexcept; static std::array<double, 3> load_average() noexcept;
/** /**
* @brief Store the program arguments. * @brief Store the program arguments.
@ -736,26 +557,26 @@ struct Utilities {
* *
* @return Arguments that haven't been consumed internally. * @return Arguments that haven't been consumed internally.
*/ */
static char **setupArgs(int argc, char **argv); static char **setup_args(int argc, char **argv);
/** /**
* @brief Gets the title of the current process. * @brief Gets the title of the current process.
* @return The process title. * @return The process title.
*/ */
static std::string processTitle(); static std::string process_title();
/** /**
* @brief Sets the current process title. * @brief Sets the current process title.
* @param title The process title to be set. * @param title The process title to be set.
* @return True in case of success, false otherwise. * @return True in case of success, false otherwise.
*/ */
static bool processTitle(const std::string &title); static bool process_title(const std::string &title);
/** /**
* @brief Gets memory information (in bytes). * @brief Gets memory information (in bytes).
* @return Memory information. * @return Memory information.
*/ */
static uint64_t totalMemory() noexcept; static uint64_t total_memory() noexcept;
/** /**
* @brief Gets the amount of memory available to the process (in bytes). * @brief Gets the amount of memory available to the process (in bytes).
@ -768,7 +589,7 @@ struct Utilities {
* *
* @return Amount of memory available to the process. * @return Amount of memory available to the process.
*/ */
static uint64_t constrainedMemory() noexcept; static uint64_t constrained_memory() noexcept;
/** /**
* @brief Gets the current system uptime. * @brief Gets the current system uptime.
@ -780,7 +601,7 @@ struct Utilities {
* @brief Gets the resource usage measures for the current process. * @brief Gets the resource usage measures for the current process.
* @return Resource usage measures, zeroes-filled object in case of errors. * @return Resource usage measures, zeroes-filled object in case of errors.
*/ */
static RUsage rusage() noexcept; static resource_usage rusage() noexcept;
/** /**
* @brief Gets the current high-resolution real time. * @brief Gets the current high-resolution real time.
@ -818,7 +639,7 @@ struct Utilities {
* [`gettimeofday`](https://linux.die.net/man/2/gettimeofday) * [`gettimeofday`](https://linux.die.net/man/2/gettimeofday)
* @return The current time. * @return The current time.
*/ */
static TimeVal64 timeOfDay() noexcept; static timeval64 time_of_day() noexcept;
/** /**
* @brief Causes the calling thread to sleep for a while. * @brief Causes the calling thread to sleep for a while.
@ -831,7 +652,7 @@ struct Utilities {
* use (always a non-zero value). * use (always a non-zero value).
* @return Estimate of the amount of parallelism a program should use. * @return Estimate of the amount of parallelism a program should use.
*/ */
static unsigned int availableParallelism() noexcept; static unsigned int available_parallelism() noexcept;
}; };
/** /**
@ -839,7 +660,7 @@ struct Utilities {
* @tparam Func Types of function objects. * @tparam Func Types of function objects.
*/ */
template<class... Func> template<class... Func>
struct Overloaded: Func... { struct overloaded: Func... {
using Func::operator()...; using Func::operator()...;
}; };
@ -848,7 +669,7 @@ struct Overloaded: Func... {
* @tparam Func Types of function objects. * @tparam Func Types of function objects.
*/ */
template<class... Func> template<class... Func>
Overloaded(Func...) -> Overloaded<Func...>; overloaded(Func...) -> overloaded<Func...>;
} // namespace uvw } // namespace uvw

89
src/uvw/uv_type.hpp Normal file
View File

@ -0,0 +1,89 @@
#ifndef UVW_UV_TYPE_INCLUDE_H
#define UVW_UV_TYPE_INCLUDE_H
#include <memory>
#include <type_traits>
#include <utility>
#include "config.h"
#include "loop.h"
namespace uvw {
/**
* @brief Wrapper class for underlying types.
*
* It acts mainly as a wrapper around data structures of the underlying library.
*/
template<typename U>
struct uv_type {
explicit uv_type(loop::token token, std::shared_ptr<loop> ref) noexcept
: owner{std::move(ref)}, resource{} {}
uv_type(const uv_type &) = delete;
uv_type(uv_type &&) = delete;
uv_type &operator=(const uv_type &) = delete;
uv_type &operator=(uv_type &&) = delete;
/**
* @brief Initializes the handle.
* @return Underlying return value.
*/
virtual int init() {
return 0;
}
/**
* @brief Gets the loop from which the resource was originated.
* @return A reference to a loop instance.
*/
loop &parent() const noexcept {
return *owner;
}
/**
* @brief Gets the underlying raw data structure.
*
* This function should not be used, unless you know exactly what you are
* doing and what are the risks.<br/>
* Going raw is dangerous, mainly because the lifetime management of a loop,
* a handle or a request is in charge to the library itself and users should
* not work around it.
*
* @warning
* Use this function at your own risk, but do not expect any support in case
* of bugs.
*
* @return The underlying raw data structure.
*/
const U *raw() const noexcept {
return &resource;
}
/**
* @brief Gets the underlying raw data structure.
*
* This function should not be used, unless you know exactly what you are
* doing and what are the risks.<br/>
* Going raw is dangerous, mainly because the lifetime management of a loop,
* a handle or a request is in charge to the library itself and users should
* not work around it.
*
* @warning
* Use this function at your own risk, but do not expect any support in case
* of bugs.
*
* @return The underlying raw data structure.
*/
U *raw() noexcept {
return &resource;
}
private:
std::shared_ptr<loop> owner;
U resource;
};
} // namespace uvw
#endif // UVW_UV_TYPE_INCLUDE_H

View File

@ -8,15 +8,23 @@
namespace uvw { namespace uvw {
UVW_INLINE WorkReq::WorkReq(ConstructorAccess ca, std::shared_ptr<Loop> ref, InternalTask t) UVW_INLINE work_req::work_req(loop::token token, std::shared_ptr<loop> ref, task t)
: Request{ca, std::move(ref)}, task{t} {} : request{token, std::move(ref)}, func{t} {}
UVW_INLINE void WorkReq::workCallback(uv_work_t *req) { UVW_INLINE void work_req::work_callback(uv_work_t *req) {
static_cast<WorkReq *>(req->data)->task(); static_cast<work_req *>(req->data)->func();
} }
UVW_INLINE void WorkReq::queue() { UVW_INLINE void work_req::after_work_callback(uv_work_t* req, int status) {
invoke(&uv_queue_work, parent(), get(), &workCallback, &defaultCallback<WorkEvent>); if(auto ptr = reserve(req); status) {
ptr->publish(error_event{status});
} else {
ptr->publish(work_event{});
}
}
UVW_INLINE int work_req::queue() {
return this->leak_if(uv_queue_work(parent().raw(), raw(), &work_callback, &after_work_callback));
} }
} // namespace uvw } // namespace uvw

View File

@ -9,20 +9,16 @@
namespace uvw { namespace uvw {
/** /*! @brief Work event. */
* @brief WorkEvent event. struct work_event {};
*
* It will be emitted by WorkReq according with its functionalities.
*/
struct WorkEvent {};
/** /**
* @brief The WorkReq request. * @brief The work request.
* *
* It runs user code using a thread from the threadpool and gets notified in the * It runs user code using a thread from the threadpool and gets notified in the
* loop thread by means of an event. * loop thread by means of an event.
* *
* To create a `WorkReq` through a `Loop`, arguments follow: * To create a `work_req` through a `loop`, arguments follow:
* *
* * A valid instance of a `Task`, that is of type `std::function<void(void)>`. * * A valid instance of a `Task`, that is of type `std::function<void(void)>`.
* *
@ -30,27 +26,28 @@ struct WorkEvent {};
* [documentation](http://docs.libuv.org/en/v1.x/threadpool.html) * [documentation](http://docs.libuv.org/en/v1.x/threadpool.html)
* for further details. * for further details.
*/ */
class WorkReq final: public Request<WorkReq, uv_work_t> { class work_req final: public request<work_req, uv_work_t, work_event> {
using InternalTask = std::function<void(void)>; static void work_callback(uv_work_t *req);
static void after_work_callback(uv_work_t *req, int status);
static void workCallback(uv_work_t *req);
public: public:
using Task = InternalTask; using task = std::function<void(void)>;
explicit WorkReq(ConstructorAccess ca, std::shared_ptr<Loop> ref, InternalTask t); explicit work_req(loop::token token, std::shared_ptr<loop> ref, task t);
/** /**
* @brief Runs the given task in a separate thread. * @brief Runs the given task in a separate thread.
* *
* A WorkEvent event will be emitted on the loop thread when the task is * A work event will be emitted on the loop thread when the task is
* finished.<br/> * finished.<br/>
* This request can be cancelled with `cancel()`. * This request can be cancelled with `cancel()`.
*
* @return Underlying return value.
*/ */
void queue(); int queue();
private: private:
Task task{}; task func{};
}; };
} // namespace uvw } // namespace uvw

View File

@ -95,7 +95,6 @@ ADD_UVW_TEST(check uvw/check.cpp)
ADD_UVW_TEST(emitter uvw/emitter.cpp) ADD_UVW_TEST(emitter uvw/emitter.cpp)
ADD_UVW_DIR_TEST(file_req uvw/file_req.cpp) ADD_UVW_DIR_TEST(file_req uvw/file_req.cpp)
ADD_UVW_DIR_TEST(fs_event uvw/fs_event.cpp) ADD_UVW_DIR_TEST(fs_event uvw/fs_event.cpp)
ADD_UVW_DIR_TEST(fs_poll uvw/fs_poll.cpp)
ADD_UVW_DIR_TEST(fs_req uvw/fs_req.cpp) ADD_UVW_DIR_TEST(fs_req uvw/fs_req.cpp)
ADD_UVW_TEST(handle uvw/handle.cpp) ADD_UVW_TEST(handle uvw/handle.cpp)
ADD_UVW_TEST(idle uvw/idle.cpp) ADD_UVW_TEST(idle uvw/idle.cpp)
@ -113,7 +112,7 @@ ADD_UVW_TEST(thread uvw/thread.cpp)
ADD_UVW_TEST(timer uvw/timer.cpp) ADD_UVW_TEST(timer uvw/timer.cpp)
ADD_UVW_TEST(tty uvw/tty.cpp) ADD_UVW_TEST(tty uvw/tty.cpp)
ADD_UVW_TEST(udp uvw/udp.cpp) ADD_UVW_TEST(udp uvw/udp.cpp)
ADD_UVW_TEST(underlying_type uvw/underlying_type.cpp) ADD_UVW_TEST(uv_type uvw/uv_type.cpp)
ADD_UVW_TEST(util uvw/util.cpp) ADD_UVW_TEST(util uvw/util.cpp)
ADD_UVW_TEST(work uvw/work.cpp) ADD_UVW_TEST(work uvw/work.cpp)

View File

@ -4,38 +4,38 @@
#include <memory> #include <memory>
#include <uvw.hpp> #include <uvw.hpp>
void listen(uvw::Loop &loop) { void listen(uvw::loop &loop) {
std::shared_ptr<uvw::TCPHandle> tcp = loop.resource<uvw::TCPHandle>(); std::shared_ptr<uvw::tcp_handle> tcp = loop.resource<uvw::tcp_handle>();
tcp->on<uvw::ErrorEvent>([](const uvw::ErrorEvent &, uvw::TCPHandle &) { assert(false); }); tcp->on<uvw::error_event>([](const uvw::error_event &, uvw::tcp_handle &) { assert(false); });
tcp->once<uvw::ListenEvent>([](const uvw::ListenEvent &, uvw::TCPHandle &srv) { tcp->on<uvw::listen_event>([](const uvw::listen_event &, uvw::tcp_handle &srv) {
std::cout << "listen" << std::endl; std::cout << "listen" << std::endl;
std::shared_ptr<uvw::TCPHandle> client = srv.loop().resource<uvw::TCPHandle>(); std::shared_ptr<uvw::tcp_handle> client = srv.parent().resource<uvw::tcp_handle>();
client->on<uvw::ErrorEvent>([](const uvw::ErrorEvent &, uvw::TCPHandle &) { assert(false); }); client->on<uvw::error_event>([](const uvw::error_event &, uvw::tcp_handle &) { assert(false); });
client->on<uvw::CloseEvent>([ptr = srv.shared_from_this()](const uvw::CloseEvent &, uvw::TCPHandle &) { client->on<uvw::close_event>([ptr = srv.shared_from_this()](const uvw::close_event &, uvw::tcp_handle &) {
std::cout << "close" << std::endl; std::cout << "close" << std::endl;
ptr->close(); ptr->close();
}); });
srv.accept(*client); srv.accept(*client);
uvw::Addr local = srv.sock(); uvw::socket_address local = srv.sock();
std::cout << "local: " << local.ip << " " << local.port << std::endl; std::cout << "local: " << local.ip << " " << local.port << std::endl;
uvw::Addr remote = client->peer(); uvw::socket_address remote = client->peer();
std::cout << "remote: " << remote.ip << " " << remote.port << std::endl; std::cout << "remote: " << remote.ip << " " << remote.port << std::endl;
client->on<uvw::DataEvent>([](const uvw::DataEvent &event, uvw::TCPHandle &) { client->on<uvw::data_event>([](const uvw::data_event &event, uvw::tcp_handle &) {
std::cout.write(event.data.get(), event.length) << std::endl; std::cout.write(event.data.get(), event.length) << std::endl;
std::cout << "data length: " << event.length << std::endl; std::cout << "data length: " << event.length << std::endl;
}); });
client->on<uvw::EndEvent>([](const uvw::EndEvent &, uvw::TCPHandle &handle) { client->on<uvw::end_event>([](const uvw::end_event &, uvw::tcp_handle &handle) {
std::cout << "end" << std::endl; std::cout << "end" << std::endl;
int count = 0; int count = 0;
handle.loop().walk([&count](auto &) { ++count; }); handle.parent().walk([&count](auto &) { ++count; });
std::cout << "still alive: " << count << " handles" << std::endl; std::cout << "still alive: " << count << " handles" << std::endl;
handle.close(); handle.close();
}); });
@ -43,7 +43,7 @@ void listen(uvw::Loop &loop) {
client->read(); client->read();
}); });
tcp->once<uvw::CloseEvent>([](const uvw::CloseEvent &, uvw::TCPHandle &) { tcp->on<uvw::close_event>([](const uvw::close_event &, uvw::tcp_handle &) {
std::cout << "close" << std::endl; std::cout << "close" << std::endl;
}); });
@ -51,27 +51,27 @@ void listen(uvw::Loop &loop) {
tcp->listen(); tcp->listen();
} }
void conn(uvw::Loop &loop) { void conn(uvw::loop &loop) {
auto tcp = loop.resource<uvw::TCPHandle>(); auto tcp = loop.resource<uvw::tcp_handle>();
tcp->on<uvw::ErrorEvent>([](const uvw::ErrorEvent &, uvw::TCPHandle &) { assert(false); }); tcp->on<uvw::error_event>([](const uvw::error_event &, uvw::tcp_handle &) { assert(false); });
tcp->once<uvw::WriteEvent>([](const uvw::WriteEvent &, uvw::TCPHandle &handle) { tcp->on<uvw::write_event>([](const uvw::write_event &, uvw::tcp_handle &handle) {
std::cout << "write" << std::endl; std::cout << "write" << std::endl;
handle.close(); handle.close();
}); });
tcp->once<uvw::ConnectEvent>([](const uvw::ConnectEvent &, uvw::TCPHandle &handle) { tcp->on<uvw::connect_event>([](const uvw::connect_event &, uvw::tcp_handle &handle) {
std::cout << "connect" << std::endl; std::cout << "connect" << std::endl;
auto dataTryWrite = std::unique_ptr<char[]>(new char[1]{'a'}); auto dataTryWrite = std::unique_ptr<char[]>(new char[1]{'a'});
int bw = handle.tryWrite(std::move(dataTryWrite), 1); int bw = handle.try_write(std::move(dataTryWrite), 1);
std::cout << "written: " << ((int)bw) << std::endl; std::cout << "written: " << ((int)bw) << std::endl;
auto dataWrite = std::unique_ptr<char[]>(new char[2]{'b', 'c'}); auto dataWrite = std::unique_ptr<char[]>(new char[2]{'b', 'c'});
handle.write(std::move(dataWrite), 2); handle.write(std::move(dataWrite), 2);
}); });
tcp->once<uvw::CloseEvent>([](const uvw::CloseEvent &, uvw::TCPHandle &) { tcp->on<uvw::close_event>([](const uvw::close_event &, uvw::tcp_handle &) {
std::cout << "close" << std::endl; std::cout << "close" << std::endl;
}); });
@ -79,7 +79,7 @@ void conn(uvw::Loop &loop) {
} }
void g() { void g() {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
listen(*loop); listen(*loop);
conn(*loop); conn(*loop);
loop->run(); loop->run();

View File

@ -2,22 +2,21 @@
#include <uvw/async.h> #include <uvw/async.h>
TEST(Async, Send) { TEST(Async, Send) {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto handle = loop->resource<uvw::AsyncHandle>(); auto handle = loop->resource<uvw::async_handle>();
bool checkAsyncEvent = false; bool checkAsyncEvent = false;
handle->on<uvw::ErrorEvent>([](auto &&...) { FAIL(); }); handle->on<uvw::error_event>([](auto &&...) { FAIL(); });
handle->on<uvw::AsyncEvent>([&checkAsyncEvent](const auto &, auto &hndl) { handle->on<uvw::async_event>([&checkAsyncEvent](const auto &, auto &hndl) {
ASSERT_FALSE(checkAsyncEvent); ASSERT_FALSE(checkAsyncEvent);
checkAsyncEvent = true; checkAsyncEvent = true;
hndl.close(); hndl.close();
ASSERT_TRUE(hndl.closing()); ASSERT_TRUE(hndl.closing());
}); });
handle->send(); ASSERT_EQ(0, handle->send());
ASSERT_TRUE(handle->active()); ASSERT_TRUE(handle->active());
ASSERT_FALSE(handle->closing()); ASSERT_FALSE(handle->closing());
@ -27,11 +26,11 @@ TEST(Async, Send) {
} }
TEST(Async, Fake) { TEST(Async, Fake) {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto handle = loop->resource<uvw::AsyncHandle>(); auto handle = loop->resource<uvw::async_handle>();
handle->on<uvw::ErrorEvent>([](auto &&...) { FAIL(); }); handle->on<uvw::error_event>([](auto &&...) { FAIL(); });
handle->on<uvw::AsyncEvent>([](auto &&...) { FAIL(); }); handle->on<uvw::async_event>([](auto &&...) { FAIL(); });
handle->send(); handle->send();
handle->close(); handle->close();

View File

@ -2,37 +2,40 @@
#include <uvw/check.h> #include <uvw/check.h>
TEST(Check, StartAndStop) { TEST(Check, StartAndStop) {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto handle = loop->resource<uvw::CheckHandle>(); auto handle = loop->resource<uvw::check_handle>();
bool checkCheckEvent = false; bool checkCheckEvent = false;
handle->on<uvw::ErrorEvent>([](auto &&...) { FAIL(); }); handle->on<uvw::error_event>([](auto &&...) { FAIL(); });
handle->on<uvw::CheckEvent>([&checkCheckEvent](const auto &, auto &hndl) { handle->on<uvw::check_event>([&checkCheckEvent](const auto &, auto &hndl) {
ASSERT_FALSE(checkCheckEvent); ASSERT_FALSE(checkCheckEvent);
checkCheckEvent = true; checkCheckEvent = true;
hndl.stop();
ASSERT_EQ(0, hndl.stop());
hndl.close(); hndl.close();
ASSERT_TRUE(hndl.closing()); ASSERT_TRUE(hndl.closing());
}); });
handle->start(); ASSERT_EQ(0, handle->start());
ASSERT_TRUE(handle->active()); ASSERT_TRUE(handle->active());
ASSERT_FALSE(handle->closing()); ASSERT_FALSE(handle->closing());
loop->run<uvw::Loop::Mode::NOWAIT>(); loop->run(uvw::loop::run_mode::NOWAIT);
ASSERT_TRUE(checkCheckEvent); ASSERT_TRUE(checkCheckEvent);
} }
TEST(Check, Fake) { TEST(Check, Fake) {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto handle = loop->resource<uvw::CheckHandle>(); auto handle = loop->resource<uvw::check_handle>();
handle->on<uvw::ErrorEvent>([](auto &&...) { FAIL(); }); handle->on<uvw::error_event>([](auto &&...) { FAIL(); });
handle->on<uvw::CheckEvent>([](auto &&...) { FAIL(); }); handle->on<uvw::check_event>([](auto &&...) { FAIL(); });
handle->start(); handle->start();
handle->close(); handle->close();

View File

@ -2,19 +2,19 @@
#include <uvw/dns.h> #include <uvw/dns.h>
TEST(GetAddrInfo, GetNodeAddrInfo) { TEST(GetAddrInfo, GetNodeAddrInfo) {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto request = loop->resource<uvw::GetAddrInfoReq>(); auto request = loop->resource<uvw::get_addr_info_req>();
bool checkAddrInfoEvent = false; bool checkAddrInfoEvent = false;
request->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); }); request->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
request->on<uvw::AddrInfoEvent>([&checkAddrInfoEvent](const auto &, auto &) { request->on<uvw::addr_info_event>([&checkAddrInfoEvent](const auto &, auto &) {
ASSERT_FALSE(checkAddrInfoEvent); ASSERT_FALSE(checkAddrInfoEvent);
checkAddrInfoEvent = true; checkAddrInfoEvent = true;
}); });
request->nodeAddrInfo("irc.freenode.net"); request->node_addr_info("irc.freenode.net");
loop->run(); loop->run();
@ -22,27 +22,27 @@ TEST(GetAddrInfo, GetNodeAddrInfo) {
} }
TEST(GetAddrInfo, GetNodeAddrInfoSync) { TEST(GetAddrInfo, GetNodeAddrInfoSync) {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto request = loop->resource<uvw::GetAddrInfoReq>(); auto request = loop->resource<uvw::get_addr_info_req>();
ASSERT_TRUE(request->nodeAddrInfoSync("irc.freenode.net").first); ASSERT_TRUE(request->node_addr_info_sync("irc.freenode.net").first);
ASSERT_FALSE(request->nodeAddrInfoSync("").first); ASSERT_FALSE(request->node_addr_info_sync("").first);
loop->run(); loop->run();
} }
TEST(GetAddrInfo, GetServiceAddrInfo) { TEST(GetAddrInfo, GetServiceAddrInfo) {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto request = loop->resource<uvw::GetAddrInfoReq>(); auto request = loop->resource<uvw::get_addr_info_req>();
bool checkErrorEvent = false; bool checkErrorEvent = false;
request->on<uvw::ErrorEvent>([&checkErrorEvent](const auto &, auto &) { request->on<uvw::error_event>([&checkErrorEvent](const auto &, auto &) {
ASSERT_FALSE(checkErrorEvent); ASSERT_FALSE(checkErrorEvent);
checkErrorEvent = true; checkErrorEvent = true;
}); });
request->serviceAddrInfo("foobar"); request->service_addr_info("foobar");
loop->run(); loop->run();
@ -50,28 +50,28 @@ TEST(GetAddrInfo, GetServiceAddrInfo) {
} }
TEST(GetAddrInfo, GetServiceAddrInfoSync) { TEST(GetAddrInfo, GetServiceAddrInfoSync) {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto request = loop->resource<uvw::GetAddrInfoReq>(); auto request = loop->resource<uvw::get_addr_info_req>();
ASSERT_FALSE(request->serviceAddrInfoSync("foobar").first); ASSERT_FALSE(request->service_addr_info_sync("foobar").first);
loop->run(); loop->run();
} }
TEST(GetAddrInfo, GetAddrInfo) { TEST(GetAddrInfo, GetAddrInfo) {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto request = loop->resource<uvw::GetAddrInfoReq>(); auto request = loop->resource<uvw::get_addr_info_req>();
bool checkAddrInfoEvent = false; bool checkAddrInfoEvent = false;
request->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); }); request->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
request->on<uvw::AddrInfoEvent>([&checkAddrInfoEvent](const auto &, auto &) { request->on<uvw::addr_info_event>([&checkAddrInfoEvent](const auto &, auto &) {
ASSERT_FALSE(checkAddrInfoEvent); ASSERT_FALSE(checkAddrInfoEvent);
checkAddrInfoEvent = true; checkAddrInfoEvent = true;
}); });
request->addrInfo("irc.freenode.net", "6667"); request->addr_info("irc.freenode.net", "6667");
loop->run(); loop->run();
@ -79,35 +79,35 @@ TEST(GetAddrInfo, GetAddrInfo) {
} }
TEST(GetAddrInfo, GetAddrInfoSync) { TEST(GetAddrInfo, GetAddrInfoSync) {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto request = loop->resource<uvw::GetAddrInfoReq>(); auto request = loop->resource<uvw::get_addr_info_req>();
ASSERT_TRUE(request->addrInfoSync("irc.freenode.net", "6667").first); ASSERT_TRUE(request->addr_info_sync("irc.freenode.net", "6667").first);
ASSERT_FALSE(request->addrInfoSync("", "").first); ASSERT_FALSE(request->addr_info_sync("", "").first);
loop->run(); loop->run();
} }
TEST(GetNameInfo, GetNameInfo) { TEST(GetNameInfo, GetNameInfo) {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto koRequest = loop->resource<uvw::GetNameInfoReq>(); auto koRequest = loop->resource<uvw::get_name_info_req>();
auto okRequest = loop->resource<uvw::GetNameInfoReq>(); auto okRequest = loop->resource<uvw::get_name_info_req>();
bool checkErrorEvent = false; bool checkErrorEvent = false;
bool checkNameInfoEvent = false; bool checkNameInfoEvent = false;
koRequest->on<uvw::ErrorEvent>([&checkErrorEvent](const auto &, auto &) { koRequest->on<uvw::error_event>([&checkErrorEvent](const auto &, auto &) {
ASSERT_FALSE(checkErrorEvent); ASSERT_FALSE(checkErrorEvent);
checkErrorEvent = true; checkErrorEvent = true;
}); });
okRequest->on<uvw::NameInfoEvent>([&checkNameInfoEvent](const auto &, auto &) { okRequest->on<uvw::name_info_event>([&checkNameInfoEvent](const auto &, auto &) {
ASSERT_FALSE(checkNameInfoEvent); ASSERT_FALSE(checkNameInfoEvent);
checkNameInfoEvent = true; checkNameInfoEvent = true;
}); });
koRequest->nameInfo(uvw::Addr{"", 0}, -1); koRequest->name_info(uvw::socket_address{"", 0}, -1);
okRequest->nameInfo("irc.freenode.net", 6667); okRequest->name_info("irc.freenode.net", 6667);
loop->run(); loop->run();
@ -116,11 +116,11 @@ TEST(GetNameInfo, GetNameInfo) {
} }
TEST(GetNameInfo, GetNameInfoSync) { TEST(GetNameInfo, GetNameInfoSync) {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto request = loop->resource<uvw::GetNameInfoReq>(); auto request = loop->resource<uvw::get_name_info_req>();
ASSERT_FALSE(request->nameInfoSync(uvw::Addr{"", 0}, -1).first); ASSERT_FALSE(request->name_info_sync(uvw::socket_address{"", 0}, -1).first);
ASSERT_TRUE(request->nameInfoSync("irc.freenode.net", 6667).first); ASSERT_TRUE(request->name_info_sync("irc.freenode.net", 6667).first);
loop->run(); loop->run();
} }

View File

@ -4,7 +4,7 @@
struct FakeEvent {}; struct FakeEvent {};
struct TestEmitter: uvw::Emitter<TestEmitter> { struct TestEmitter: uvw::emitter<TestEmitter, FakeEvent> {
void emit() { void emit() {
publish(FakeEvent{}); publish(FakeEvent{});
} }
@ -13,136 +13,51 @@ struct TestEmitter: uvw::Emitter<TestEmitter> {
TEST(ErrorEvent, Functionalities) { TEST(ErrorEvent, Functionalities) {
auto ecode = static_cast<std::underlying_type_t<uv_errno_t>>(UV_EADDRINUSE); auto ecode = static_cast<std::underlying_type_t<uv_errno_t>>(UV_EADDRINUSE);
uvw::ErrorEvent event{ecode}; uvw::error_event event{ecode};
ASSERT_EQ(ecode, uvw::ErrorEvent::translate(ecode)); ASSERT_EQ(ecode, uvw::error_event::translate(ecode));
ASSERT_NE(event.what(), nullptr); ASSERT_NE(event.what(), nullptr);
ASSERT_NE(event.name(), nullptr); ASSERT_NE(event.name(), nullptr);
ASSERT_EQ(event.code(), ecode); ASSERT_EQ(event.code(), ecode);
ASSERT_FALSE(static_cast<bool>(uvw::ErrorEvent{0})); ASSERT_FALSE(static_cast<bool>(uvw::error_event{0}));
ASSERT_TRUE(static_cast<bool>(uvw::ErrorEvent{ecode})); ASSERT_TRUE(static_cast<bool>(uvw::error_event{ecode}));
} }
TEST(Emitter, EmptyAndClear) { TEST(Emitter, Functionalities) {
TestEmitter emitter{}; TestEmitter emitter{};
ASSERT_TRUE(emitter.empty()); emitter.on<uvw::error_event>([](const auto &, auto &) {});
emitter.on<uvw::ErrorEvent>([](const auto &, auto &) {}); ASSERT_TRUE(emitter.has<uvw::error_event>());
ASSERT_FALSE(emitter.has<FakeEvent>());
ASSERT_FALSE(emitter.empty()); emitter.reset<FakeEvent>();
ASSERT_FALSE(emitter.empty<uvw::ErrorEvent>());
ASSERT_TRUE(emitter.empty<FakeEvent>());
emitter.clear<FakeEvent>(); ASSERT_TRUE(emitter.has<uvw::error_event>());
ASSERT_FALSE(emitter.has<FakeEvent>());
ASSERT_FALSE(emitter.empty()); emitter.reset<uvw::error_event>();
ASSERT_FALSE(emitter.empty<uvw::ErrorEvent>());
ASSERT_TRUE(emitter.empty<FakeEvent>());
emitter.clear<uvw::ErrorEvent>(); ASSERT_FALSE(emitter.has<uvw::error_event>());
ASSERT_FALSE(emitter.has<FakeEvent>());
ASSERT_TRUE(emitter.empty()); bool sentinel = false;
ASSERT_TRUE(emitter.empty<uvw::ErrorEvent>()); emitter.on<uvw::error_event>([](const auto &, auto &) {});
ASSERT_TRUE(emitter.empty<FakeEvent>()); emitter.on<FakeEvent>([&](const auto &, auto &) { sentinel = true; });
emitter.on<uvw::ErrorEvent>([](const auto &, auto &) {}); ASSERT_FALSE(sentinel);
emitter.on<FakeEvent>([](const auto &, auto &) {}); ASSERT_TRUE(emitter.has<uvw::error_event>());
ASSERT_TRUE(emitter.has<FakeEvent>());
ASSERT_FALSE(emitter.empty());
ASSERT_FALSE(emitter.empty<uvw::ErrorEvent>());
ASSERT_FALSE(emitter.empty<FakeEvent>());
emitter.clear();
ASSERT_TRUE(emitter.empty());
ASSERT_TRUE(emitter.empty<uvw::ErrorEvent>());
ASSERT_TRUE(emitter.empty<FakeEvent>());
}
TEST(Emitter, On) {
TestEmitter emitter{};
emitter.on<FakeEvent>([](const auto &, auto &) {});
ASSERT_FALSE(emitter.empty());
ASSERT_FALSE(emitter.empty<FakeEvent>());
emitter.emit(); emitter.emit();
ASSERT_FALSE(emitter.empty()); ASSERT_TRUE(sentinel);
ASSERT_FALSE(emitter.empty<FakeEvent>()); ASSERT_TRUE(emitter.has<uvw::error_event>());
} ASSERT_TRUE(emitter.has<FakeEvent>());
TEST(Emitter, Once) { emitter.reset();
TestEmitter emitter{};
ASSERT_FALSE(emitter.has<uvw::error_event>());
emitter.once<FakeEvent>([](const auto &, auto &) {}); ASSERT_FALSE(emitter.has<FakeEvent>());
ASSERT_FALSE(emitter.empty());
ASSERT_FALSE(emitter.empty<FakeEvent>());
emitter.emit();
ASSERT_TRUE(emitter.empty());
ASSERT_TRUE(emitter.empty<FakeEvent>());
}
TEST(Emitter, OnceAndErase) {
TestEmitter emitter{};
auto conn = emitter.once<FakeEvent>([](const auto &, auto &) {});
ASSERT_FALSE(emitter.empty());
ASSERT_FALSE(emitter.empty<FakeEvent>());
emitter.erase(conn);
ASSERT_TRUE(emitter.empty());
ASSERT_TRUE(emitter.empty<FakeEvent>());
}
TEST(Emitter, OnAndErase) {
TestEmitter emitter{};
auto conn = emitter.on<FakeEvent>([](const auto &, auto &) {});
ASSERT_FALSE(emitter.empty());
ASSERT_FALSE(emitter.empty<FakeEvent>());
emitter.erase(conn);
ASSERT_TRUE(emitter.empty());
ASSERT_TRUE(emitter.empty<FakeEvent>());
}
TEST(Emitter, CallbackClear) {
TestEmitter emitter{};
emitter.on<FakeEvent>([](const auto &, auto &ref) {
ref.template on<FakeEvent>([](const auto &, auto &) {});
ref.clear();
});
ASSERT_FALSE(emitter.empty());
ASSERT_FALSE(emitter.empty<FakeEvent>());
emitter.emit();
ASSERT_TRUE(emitter.empty());
ASSERT_TRUE(emitter.empty<FakeEvent>());
emitter.on<FakeEvent>([](const auto &, auto &ref) {
ref.clear();
ref.template on<FakeEvent>([](const auto &, auto &) {});
});
ASSERT_FALSE(emitter.empty());
ASSERT_FALSE(emitter.empty<FakeEvent>());
emitter.emit();
ASSERT_FALSE(emitter.empty());
ASSERT_FALSE(emitter.empty<FakeEvent>());
} }

View File

@ -10,24 +10,24 @@
TEST(FileReq, OpenAndCloseErr) { TEST(FileReq, OpenAndCloseErr) {
const std::string filename = std::string{TARGET_FILE_REQ_DIR} + std::string{"/err.file"}; const std::string filename = std::string{TARGET_FILE_REQ_DIR} + std::string{"/err.file"};
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto openReq = loop->resource<uvw::FileReq>(); auto openReq = loop->resource<uvw::file_req>();
auto closeReq = loop->resource<uvw::FileReq>(); auto closeReq = loop->resource<uvw::file_req>();
bool checkFileOpenErrorEvent = false; bool checkFileOpenErrorEvent = false;
bool checkFileCloseErrorEvent = false; bool checkFileCloseErrorEvent = false;
openReq->on<uvw::ErrorEvent>([&checkFileOpenErrorEvent](const auto &, auto &) { openReq->on<uvw::error_event>([&checkFileOpenErrorEvent](const auto &, auto &) {
ASSERT_FALSE(checkFileOpenErrorEvent); ASSERT_FALSE(checkFileOpenErrorEvent);
checkFileOpenErrorEvent = true; checkFileOpenErrorEvent = true;
}); });
closeReq->on<uvw::ErrorEvent>([&checkFileCloseErrorEvent](const auto &, auto &) { closeReq->on<uvw::error_event>([&checkFileCloseErrorEvent](const auto &, auto &) {
ASSERT_FALSE(checkFileCloseErrorEvent); ASSERT_FALSE(checkFileCloseErrorEvent);
checkFileCloseErrorEvent = true; checkFileCloseErrorEvent = true;
}); });
auto flags = uvw::Flags<uvw::FileReq::FileOpen>::from<uvw::FileReq::FileOpen::RDONLY>(); auto flags = uvw::file_req::file_open_flags::RDONLY;
openReq->open(filename, flags, 0644); openReq->open(filename, flags, 0644);
closeReq->close(); closeReq->close();
@ -40,11 +40,12 @@ TEST(FileReq, OpenAndCloseErr) {
TEST(FileReq, OpenAndCloseErrSync) { TEST(FileReq, OpenAndCloseErrSync) {
const std::string filename = std::string{TARGET_FILE_REQ_DIR} + std::string{"/err.file"}; const std::string filename = std::string{TARGET_FILE_REQ_DIR} + std::string{"/err.file"};
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto request = loop->resource<uvw::FileReq>(); auto request = loop->resource<uvw::file_req>();
auto flags = uvw::file_req::file_open_flags::RDONLY;
ASSERT_FALSE(request->openSync(filename, O_RDONLY, 0644)); ASSERT_FALSE(request->open_sync(filename, flags, 0644));
ASSERT_FALSE(request->closeSync()); ASSERT_FALSE(request->close_sync());
loop->run(); loop->run();
} }
@ -52,26 +53,26 @@ TEST(FileReq, OpenAndCloseErrSync) {
TEST(FileReq, OpenAndClose) { TEST(FileReq, OpenAndClose) {
const std::string filename = std::string{TARGET_FILE_REQ_DIR} + std::string{"/test.file"}; const std::string filename = std::string{TARGET_FILE_REQ_DIR} + std::string{"/test.file"};
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto request = loop->resource<uvw::FileReq>(); auto request = loop->resource<uvw::file_req>();
bool checkFileOpenEvent = false; bool checkFileOpenEvent = false;
bool checkFileCloseEvent = false; bool checkFileCloseEvent = false;
request->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); }); request->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
request->on<uvw::FsEvent<uvw::FileReq::Type::CLOSE>>([&checkFileCloseEvent](const auto &, auto &) { request->on<uvw::fs_event>([&](const auto &event, auto &req) {
ASSERT_FALSE(checkFileCloseEvent); if(event.type == uvw::fs_req::fs_type::CLOSE) {
checkFileCloseEvent = true; ASSERT_FALSE(checkFileCloseEvent);
checkFileCloseEvent = true;
} else if(event.type == uvw::fs_req::fs_type::OPEN) {
ASSERT_FALSE(checkFileOpenEvent);
checkFileOpenEvent = true;
req.close();
};
}); });
request->on<uvw::FsEvent<uvw::FileReq::Type::OPEN>>([&checkFileOpenEvent](const auto &, auto &req) { auto flags = uvw::file_req::file_open_flags::CREAT | uvw::file_req::file_open_flags::WRONLY;
ASSERT_FALSE(checkFileOpenEvent);
checkFileOpenEvent = true;
req.close();
});
auto flags = uvw::Flags<uvw::FileReq::FileOpen>::from<uvw::FileReq::FileOpen::CREAT, uvw::FileReq::FileOpen::WRONLY>();
request->open(filename, flags, 0644); request->open(filename, flags, 0644);
loop->run(); loop->run();
@ -83,11 +84,12 @@ TEST(FileReq, OpenAndClose) {
TEST(FileReq, OpenAndCloseSync) { TEST(FileReq, OpenAndCloseSync) {
const std::string filename = std::string{TARGET_FILE_REQ_DIR} + std::string{"/test.file"}; const std::string filename = std::string{TARGET_FILE_REQ_DIR} + std::string{"/test.file"};
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto request = loop->resource<uvw::FileReq>(); auto request = loop->resource<uvw::file_req>();
auto flags = uvw::file_req::file_open_flags::CREAT | uvw::file_req::file_open_flags::WRONLY;
ASSERT_TRUE(request->openSync(filename, O_CREAT | O_WRONLY, 0644)); ASSERT_TRUE(request->open_sync(filename, flags, 0644));
ASSERT_TRUE(request->closeSync()); ASSERT_TRUE(request->close_sync());
loop->run(); loop->run();
} }
@ -95,32 +97,30 @@ TEST(FileReq, OpenAndCloseSync) {
TEST(FileReq, RWChecked) { TEST(FileReq, RWChecked) {
const std::string filename = std::string{TARGET_FILE_REQ_DIR} + std::string{"/test.file"}; const std::string filename = std::string{TARGET_FILE_REQ_DIR} + std::string{"/test.file"};
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto request = loop->resource<uvw::FileReq>(); auto request = loop->resource<uvw::file_req>();
bool checkFileWriteEvent = false; bool checkFileWriteEvent = false;
bool checkFileReadEvent = false; bool checkFileReadEvent = false;
request->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); }); request->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
request->on<uvw::FsEvent<uvw::FileReq::Type::READ>>([&checkFileReadEvent](const auto &event, auto &req) { request->on<uvw::fs_event>([&](const auto &event, auto &req) {
ASSERT_FALSE(checkFileReadEvent); if(event.type == uvw::fs_req::fs_type::OPEN) {
ASSERT_EQ(event.data[0], 42); req.write(std::unique_ptr<char[]>{new char[1]{42}}, 1, 0);
checkFileReadEvent = true; } else if(event.type == uvw::fs_req::fs_type::READ) {
req.close(); ASSERT_FALSE(checkFileReadEvent);
ASSERT_EQ(event.read.data[0], 42);
checkFileReadEvent = true;
req.close();
} else if(event.type == uvw::fs_req::fs_type::WRITE) {
ASSERT_FALSE(checkFileWriteEvent);
checkFileWriteEvent = true;
req.read(0, 1);
};
}); });
request->on<uvw::FsEvent<uvw::FileReq::Type::WRITE>>([&checkFileWriteEvent](const auto &, auto &req) { auto flags = uvw::file_req::file_open_flags::CREAT | uvw::file_req::file_open_flags::RDWR | uvw::file_req::file_open_flags::TRUNC;
ASSERT_FALSE(checkFileWriteEvent);
checkFileWriteEvent = true;
req.read(0, 1);
});
request->on<uvw::FsEvent<uvw::FileReq::Type::OPEN>>([](const auto &, auto &req) {
req.write(std::unique_ptr<char[]>{new char[1]{42}}, 1, 0);
});
auto flags = uvw::Flags<uvw::FileReq::FileOpen>::from<uvw::FileReq::FileOpen::CREAT, uvw::FileReq::FileOpen::RDWR, uvw::FileReq::FileOpen::TRUNC>();
request->open(filename, flags, 0644); request->open(filename, flags, 0644);
loop->run(); loop->run();
@ -133,32 +133,30 @@ TEST(FileReq, RWUnchecked) {
const std::string filename = std::string{TARGET_FILE_REQ_DIR} + std::string{"/test.file"}; const std::string filename = std::string{TARGET_FILE_REQ_DIR} + std::string{"/test.file"};
std::unique_ptr<char[]> data{new char[1]{42}}; std::unique_ptr<char[]> data{new char[1]{42}};
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto request = loop->resource<uvw::FileReq>(); auto request = loop->resource<uvw::file_req>();
bool checkFileWriteEvent = false; bool checkFileWriteEvent = false;
bool checkFileReadEvent = false; bool checkFileReadEvent = false;
request->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); }); request->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
request->on<uvw::FsEvent<uvw::FileReq::Type::READ>>([&checkFileReadEvent](const auto &event, auto &req) { request->on<uvw::fs_event>([&](const auto &event, auto &req) {
ASSERT_FALSE(checkFileReadEvent); if(event.type == uvw::fs_req::fs_type::OPEN) {
ASSERT_EQ(event.data[0], 42); req.write(data.get(), 1, 0);
checkFileReadEvent = true; } else if(event.type == uvw::fs_req::fs_type::READ) {
req.close(); ASSERT_FALSE(checkFileReadEvent);
ASSERT_EQ(event.read.data[0], 42);
checkFileReadEvent = true;
req.close();
} else if(event.type == uvw::fs_req::fs_type::WRITE) {
ASSERT_FALSE(checkFileWriteEvent);
checkFileWriteEvent = true;
req.read(0, 1);
};
}); });
request->on<uvw::FsEvent<uvw::FileReq::Type::WRITE>>([&checkFileWriteEvent](const auto &, auto &req) { auto flags = uvw::file_req::file_open_flags::CREAT | uvw::file_req::file_open_flags::RDWR | uvw::file_req::file_open_flags::TRUNC;
ASSERT_FALSE(checkFileWriteEvent);
checkFileWriteEvent = true;
req.read(0, 1);
});
request->on<uvw::FsEvent<uvw::FileReq::Type::OPEN>>([&data](const auto &, auto &req) {
req.write(data.get(), 1, 0);
});
auto flags = uvw::Flags<uvw::FileReq::FileOpen>::from<uvw::FileReq::FileOpen::CREAT, uvw::FileReq::FileOpen::RDWR, uvw::FileReq::FileOpen::TRUNC>();
request->open(filename, flags, 0644); request->open(filename, flags, 0644);
loop->run(); loop->run();
@ -170,22 +168,23 @@ TEST(FileReq, RWUnchecked) {
TEST(FileReq, RWSync) { TEST(FileReq, RWSync) {
const std::string filename = std::string{TARGET_FILE_REQ_DIR} + std::string{"/test.file"}; const std::string filename = std::string{TARGET_FILE_REQ_DIR} + std::string{"/test.file"};
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto request = loop->resource<uvw::FileReq>(); auto request = loop->resource<uvw::file_req>();
auto flags = uvw::file_req::file_open_flags::CREAT | uvw::file_req::file_open_flags::RDWR | uvw::file_req::file_open_flags::TRUNC;
ASSERT_TRUE(request->openSync(filename, O_CREAT | O_RDWR | O_TRUNC, 0644)); ASSERT_TRUE(request->open_sync(filename, flags, 0644));
auto writeR = request->writeSync(std::unique_ptr<char[]>{new char[1]{42}}, 1, 0); auto writeR = request->write_sync(std::unique_ptr<char[]>{new char[1]{42}}, 1, 0);
ASSERT_TRUE(writeR.first); ASSERT_TRUE(writeR.first);
ASSERT_EQ(writeR.second, std::size_t{1}); ASSERT_EQ(writeR.second, std::size_t{1});
auto readR = request->readSync(0, 1); auto readR = request->read_sync(0, 1);
ASSERT_TRUE(readR.first); ASSERT_TRUE(readR.first);
ASSERT_EQ(readR.second.first[0], 42); ASSERT_EQ(readR.second.first[0], 42);
ASSERT_EQ(readR.second.second, std::size_t{1}); ASSERT_EQ(readR.second.second, std::size_t{1});
ASSERT_TRUE(request->closeSync()); ASSERT_TRUE(request->close_sync());
loop->run(); loop->run();
} }
@ -193,24 +192,24 @@ TEST(FileReq, RWSync) {
TEST(FileReq, Stat) { TEST(FileReq, Stat) {
const std::string filename = std::string{TARGET_FILE_REQ_DIR} + std::string{"/test.file"}; const std::string filename = std::string{TARGET_FILE_REQ_DIR} + std::string{"/test.file"};
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto request = loop->resource<uvw::FileReq>(); auto request = loop->resource<uvw::file_req>();
bool checkFileStatEvent = false; bool checkFileStatEvent = false;
request->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); }); request->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
request->on<uvw::FsEvent<uvw::FileReq::Type::FSTAT>>([&checkFileStatEvent](const auto &, auto &req) { request->on<uvw::fs_event>([&](const auto &event, auto &req) {
ASSERT_FALSE(checkFileStatEvent); if(event.type == uvw::fs_req::fs_type::OPEN) {
checkFileStatEvent = true; req.stat();
req.close(); } else if(event.type == uvw::fs_req::fs_type::FSTAT) {
ASSERT_FALSE(checkFileStatEvent);
checkFileStatEvent = true;
req.close();
};
}); });
request->on<uvw::FsEvent<uvw::FileReq::Type::OPEN>>([](const auto &, auto &req) { auto flags = uvw::file_req::file_open_flags::CREAT | uvw::file_req::file_open_flags::RDWR | uvw::file_req::file_open_flags::TRUNC;
req.stat();
});
auto flags = uvw::Flags<uvw::FileReq::FileOpen>::from<uvw::FileReq::FileOpen::CREAT, uvw::FileReq::FileOpen::RDWR, uvw::FileReq::FileOpen::TRUNC>();
request->open(filename, flags, 0644); request->open(filename, flags, 0644);
loop->run(); loop->run();
@ -221,15 +220,16 @@ TEST(FileReq, Stat) {
TEST(FileReq, StatSync) { TEST(FileReq, StatSync) {
const std::string filename = std::string{TARGET_FILE_REQ_DIR} + std::string{"/test.file"}; const std::string filename = std::string{TARGET_FILE_REQ_DIR} + std::string{"/test.file"};
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto request = loop->resource<uvw::FileReq>(); auto request = loop->resource<uvw::file_req>();
auto flags = uvw::file_req::file_open_flags::CREAT | uvw::file_req::file_open_flags::RDWR | uvw::file_req::file_open_flags::TRUNC;
ASSERT_TRUE(request->openSync(filename, O_CREAT | O_RDWR | O_TRUNC, 0644)); ASSERT_TRUE(request->open_sync(filename, flags, 0644));
auto statR = request->statSync(); auto statR = request->stat_sync();
ASSERT_TRUE(statR.first); ASSERT_TRUE(statR.first);
ASSERT_TRUE(request->closeSync()); ASSERT_TRUE(request->close_sync());
loop->run(); loop->run();
} }
@ -237,24 +237,24 @@ TEST(FileReq, StatSync) {
TEST(FileReq, Sync) { TEST(FileReq, Sync) {
const std::string filename = std::string{TARGET_FILE_REQ_DIR} + std::string{"/test.file"}; const std::string filename = std::string{TARGET_FILE_REQ_DIR} + std::string{"/test.file"};
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto request = loop->resource<uvw::FileReq>(); auto request = loop->resource<uvw::file_req>();
bool checkFileSyncEvent = false; bool checkFileSyncEvent = false;
request->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); }); request->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
request->on<uvw::FsEvent<uvw::FileReq::Type::FSYNC>>([&checkFileSyncEvent](const auto &, auto &req) { request->on<uvw::fs_event>([&](const auto &event, auto &req) {
ASSERT_FALSE(checkFileSyncEvent); if(event.type == uvw::fs_req::fs_type::FSYNC) {
checkFileSyncEvent = true; ASSERT_FALSE(checkFileSyncEvent);
req.close(); checkFileSyncEvent = true;
req.close();
} else if(event.type == uvw::fs_req::fs_type::OPEN) {
req.sync();
};
}); });
request->on<uvw::FsEvent<uvw::FileReq::Type::OPEN>>([](const auto &, auto &req) { auto flags = uvw::file_req::file_open_flags::CREAT | uvw::file_req::file_open_flags::RDWR | uvw::file_req::file_open_flags::TRUNC;
req.sync();
});
auto flags = uvw::Flags<uvw::FileReq::FileOpen>::from<uvw::FileReq::FileOpen::CREAT, uvw::FileReq::FileOpen::RDWR, uvw::FileReq::FileOpen::TRUNC>();
request->open(filename, flags, 0644); request->open(filename, flags, 0644);
loop->run(); loop->run();
@ -265,12 +265,13 @@ TEST(FileReq, Sync) {
TEST(FileReq, SyncSync) { TEST(FileReq, SyncSync) {
const std::string filename = std::string{TARGET_FILE_REQ_DIR} + std::string{"/test.file"}; const std::string filename = std::string{TARGET_FILE_REQ_DIR} + std::string{"/test.file"};
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto request = loop->resource<uvw::FileReq>(); auto request = loop->resource<uvw::file_req>();
auto flags = uvw::file_req::file_open_flags::CREAT | uvw::file_req::file_open_flags::RDWR | uvw::file_req::file_open_flags::TRUNC;
ASSERT_TRUE(request->openSync(filename, O_CREAT | O_RDWR | O_TRUNC, 0644)); ASSERT_TRUE(request->open_sync(filename, flags, 0644));
ASSERT_TRUE(request->syncSync()); ASSERT_TRUE(request->sync_sync());
ASSERT_TRUE(request->closeSync()); ASSERT_TRUE(request->close_sync());
loop->run(); loop->run();
} }
@ -278,24 +279,24 @@ TEST(FileReq, SyncSync) {
TEST(FileReq, Datasync) { TEST(FileReq, Datasync) {
const std::string filename = std::string{TARGET_FILE_REQ_DIR} + std::string{"/test.file"}; const std::string filename = std::string{TARGET_FILE_REQ_DIR} + std::string{"/test.file"};
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto request = loop->resource<uvw::FileReq>(); auto request = loop->resource<uvw::file_req>();
bool checkFileDatasyncEvent = false; bool checkFileDatasyncEvent = false;
request->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); }); request->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
request->on<uvw::FsEvent<uvw::FileReq::Type::FDATASYNC>>([&checkFileDatasyncEvent](const auto &, auto &req) { request->on<uvw::fs_event>([&](const auto &event, auto &req) {
ASSERT_FALSE(checkFileDatasyncEvent); if(event.type == uvw::fs_req::fs_type::FDATASYNC) {
checkFileDatasyncEvent = true; ASSERT_FALSE(checkFileDatasyncEvent);
req.close(); checkFileDatasyncEvent = true;
req.close();
} else if(event.type == uvw::fs_req::fs_type::OPEN) {
req.datasync();
};
}); });
request->on<uvw::FsEvent<uvw::FileReq::Type::OPEN>>([](const auto &, auto &req) { auto flags = uvw::file_req::file_open_flags::CREAT | uvw::file_req::file_open_flags::RDWR | uvw::file_req::file_open_flags::TRUNC;
req.datasync();
});
auto flags = uvw::Flags<uvw::FileReq::FileOpen>::from<uvw::FileReq::FileOpen::CREAT, uvw::FileReq::FileOpen::RDWR, uvw::FileReq::FileOpen::TRUNC>();
request->open(filename, flags, 0644); request->open(filename, flags, 0644);
loop->run(); loop->run();
@ -306,12 +307,13 @@ TEST(FileReq, Datasync) {
TEST(FileReq, DatasyncSync) { TEST(FileReq, DatasyncSync) {
const std::string filename = std::string{TARGET_FILE_REQ_DIR} + std::string{"/test.file"}; const std::string filename = std::string{TARGET_FILE_REQ_DIR} + std::string{"/test.file"};
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto request = loop->resource<uvw::FileReq>(); auto request = loop->resource<uvw::file_req>();
auto flags = uvw::file_req::file_open_flags::CREAT | uvw::file_req::file_open_flags::RDWR | uvw::file_req::file_open_flags::TRUNC;
ASSERT_TRUE(request->openSync(filename, O_CREAT | O_RDWR | O_TRUNC, 0644)); ASSERT_TRUE(request->open_sync(filename, flags, 0644));
ASSERT_TRUE(request->datasyncSync()); ASSERT_TRUE(request->datasync_sync());
ASSERT_TRUE(request->closeSync()); ASSERT_TRUE(request->close_sync());
loop->run(); loop->run();
} }
@ -319,24 +321,24 @@ TEST(FileReq, DatasyncSync) {
TEST(FileReq, Truncate) { TEST(FileReq, Truncate) {
const std::string filename = std::string{TARGET_FILE_REQ_DIR} + std::string{"/test.file"}; const std::string filename = std::string{TARGET_FILE_REQ_DIR} + std::string{"/test.file"};
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto request = loop->resource<uvw::FileReq>(); auto request = loop->resource<uvw::file_req>();
bool checkFileTruncateEvent = false; bool checkFileTruncateEvent = false;
request->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); }); request->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
request->on<uvw::FsEvent<uvw::FileReq::Type::FTRUNCATE>>([&checkFileTruncateEvent](const auto &, auto &req) { request->on<uvw::fs_event>([&](const auto &event, auto &req) {
ASSERT_FALSE(checkFileTruncateEvent); if(event.type == uvw::fs_req::fs_type::FTRUNCATE) {
checkFileTruncateEvent = true; ASSERT_FALSE(checkFileTruncateEvent);
req.close(); checkFileTruncateEvent = true;
req.close();
} else if(event.type == uvw::fs_req::fs_type::OPEN) {
req.truncate(0);
};
}); });
request->on<uvw::FsEvent<uvw::FileReq::Type::OPEN>>([](const auto &, auto &req) { auto flags = uvw::file_req::file_open_flags::CREAT | uvw::file_req::file_open_flags::RDWR | uvw::file_req::file_open_flags::TRUNC;
req.truncate(0);
});
auto flags = uvw::Flags<uvw::FileReq::FileOpen>::from<uvw::FileReq::FileOpen::CREAT, uvw::FileReq::FileOpen::RDWR, uvw::FileReq::FileOpen::TRUNC>();
request->open(filename, flags, 0644); request->open(filename, flags, 0644);
loop->run(); loop->run();
@ -347,12 +349,13 @@ TEST(FileReq, Truncate) {
TEST(FileReq, TruncateSync) { TEST(FileReq, TruncateSync) {
const std::string filename = std::string{TARGET_FILE_REQ_DIR} + std::string{"/test.file"}; const std::string filename = std::string{TARGET_FILE_REQ_DIR} + std::string{"/test.file"};
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto request = loop->resource<uvw::FileReq>(); auto request = loop->resource<uvw::file_req>();
auto flags = uvw::file_req::file_open_flags::CREAT | uvw::file_req::file_open_flags::RDWR | uvw::file_req::file_open_flags::TRUNC;
ASSERT_TRUE(request->openSync(filename, O_CREAT | O_RDWR | O_TRUNC, 0644)); ASSERT_TRUE(request->open_sync(filename, flags, 0644));
ASSERT_TRUE(request->truncateSync(0)); ASSERT_TRUE(request->truncate_sync(0));
ASSERT_TRUE(request->closeSync()); ASSERT_TRUE(request->close_sync());
loop->run(); loop->run();
} }
@ -360,24 +363,24 @@ TEST(FileReq, TruncateSync) {
TEST(FileReq, Chmod) { TEST(FileReq, Chmod) {
const std::string filename = std::string{TARGET_FILE_REQ_DIR} + std::string{"/test.file"}; const std::string filename = std::string{TARGET_FILE_REQ_DIR} + std::string{"/test.file"};
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto request = loop->resource<uvw::FileReq>(); auto request = loop->resource<uvw::file_req>();
bool checkFileChmodEvent = false; bool checkFileChmodEvent = false;
request->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); }); request->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
request->on<uvw::FsEvent<uvw::FileReq::Type::FCHMOD>>([&checkFileChmodEvent](const auto &, auto &req) { request->on<uvw::fs_event>([&](const auto &event, auto &req) {
ASSERT_FALSE(checkFileChmodEvent); if(event.type == uvw::fs_req::fs_type::FCHMOD) {
checkFileChmodEvent = true; ASSERT_FALSE(checkFileChmodEvent);
req.close(); checkFileChmodEvent = true;
req.close();
} else if(event.type == uvw::fs_req::fs_type::OPEN) {
req.chmod(0644);
};
}); });
request->on<uvw::FsEvent<uvw::FileReq::Type::OPEN>>([](const auto &, auto &req) { auto flags = uvw::file_req::file_open_flags::CREAT | uvw::file_req::file_open_flags::RDWR | uvw::file_req::file_open_flags::TRUNC;
req.chmod(0644);
});
auto flags = uvw::Flags<uvw::FileReq::FileOpen>::from<uvw::FileReq::FileOpen::CREAT, uvw::FileReq::FileOpen::RDWR, uvw::FileReq::FileOpen::TRUNC>();
request->open(filename, flags, 0644); request->open(filename, flags, 0644);
loop->run(); loop->run();
@ -388,12 +391,13 @@ TEST(FileReq, Chmod) {
TEST(FileReq, ChmodSync) { TEST(FileReq, ChmodSync) {
const std::string filename = std::string{TARGET_FILE_REQ_DIR} + std::string{"/test.file"}; const std::string filename = std::string{TARGET_FILE_REQ_DIR} + std::string{"/test.file"};
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto request = loop->resource<uvw::FileReq>(); auto request = loop->resource<uvw::file_req>();
auto flags = uvw::file_req::file_open_flags::CREAT | uvw::file_req::file_open_flags::RDWR | uvw::file_req::file_open_flags::TRUNC;
ASSERT_TRUE(request->openSync(filename, O_CREAT | O_RDWR | O_TRUNC, 0644)); ASSERT_TRUE(request->open_sync(filename, flags, 0644));
ASSERT_TRUE(request->chmodSync(0644)); ASSERT_TRUE(request->chmod_sync(0644));
ASSERT_TRUE(request->closeSync()); ASSERT_TRUE(request->close_sync());
loop->run(); loop->run();
} }
@ -401,27 +405,26 @@ TEST(FileReq, ChmodSync) {
TEST(FileReq, Futime) { TEST(FileReq, Futime) {
const std::string filename = std::string{TARGET_FILE_REQ_DIR} + std::string{"/test.file"}; const std::string filename = std::string{TARGET_FILE_REQ_DIR} + std::string{"/test.file"};
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto request = loop->resource<uvw::FileReq>(); auto request = loop->resource<uvw::file_req>();
bool checkFileUtimeEvent = false; bool checkFileUtimeEvent = false;
request->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); }); request->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
request->on<uvw::FsEvent<uvw::FileReq::Type::FUTIME>>([&checkFileUtimeEvent](const auto &, auto &req) { request->on<uvw::fs_event>([&](const auto &event, auto &req) {
ASSERT_FALSE(checkFileUtimeEvent); const auto value = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch());
checkFileUtimeEvent = true;
req.close(); if(event.type == uvw::fs_req::fs_type::FUTIME) {
ASSERT_FALSE(checkFileUtimeEvent);
checkFileUtimeEvent = true;
req.close();
} else if(event.type == uvw::fs_req::fs_type::OPEN) {
req.futime(value, value);
};
}); });
request->on<uvw::FsEvent<uvw::FileReq::Type::OPEN>>([](const auto &, auto &req) { auto flags = uvw::file_req::file_open_flags::CREAT | uvw::file_req::file_open_flags::RDWR | uvw::file_req::file_open_flags::TRUNC;
auto now = std::chrono::system_clock::now();
auto epoch = now.time_since_epoch();
auto value = std::chrono::duration_cast<std::chrono::seconds>(epoch);
req.futime(value, value);
});
auto flags = uvw::Flags<uvw::FileReq::FileOpen>::from<uvw::FileReq::FileOpen::CREAT, uvw::FileReq::FileOpen::RDWR, uvw::FileReq::FileOpen::TRUNC>();
request->open(filename, flags, 0644); request->open(filename, flags, 0644);
loop->run(); loop->run();
@ -432,18 +435,19 @@ TEST(FileReq, Futime) {
TEST(FileReq, FutimeSync) { TEST(FileReq, FutimeSync) {
const std::string filename = std::string{TARGET_FILE_REQ_DIR} + std::string{"/test.file"}; const std::string filename = std::string{TARGET_FILE_REQ_DIR} + std::string{"/test.file"};
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto request = loop->resource<uvw::FileReq>(); auto request = loop->resource<uvw::file_req>();
auto flags = uvw::file_req::file_open_flags::CREAT | uvw::file_req::file_open_flags::RDWR | uvw::file_req::file_open_flags::TRUNC;
ASSERT_TRUE(request->openSync(filename, O_CREAT | O_RDWR | O_TRUNC, 0644)); ASSERT_TRUE(request->open_sync(filename, flags, 0644));
auto now = std::chrono::system_clock::now(); auto now = std::chrono::system_clock::now();
auto epoch = now.time_since_epoch(); auto epoch = now.time_since_epoch();
auto value = std::chrono::duration_cast<std::chrono::seconds>(epoch); auto value = std::chrono::duration_cast<std::chrono::seconds>(epoch);
ASSERT_TRUE(request->futimeSync(value, value)); ASSERT_TRUE(request->futime_sync(value, value));
ASSERT_TRUE(request->truncateSync(0)); ASSERT_TRUE(request->truncate_sync(0));
ASSERT_TRUE(request->closeSync()); ASSERT_TRUE(request->close_sync());
loop->run(); loop->run();
} }
@ -451,30 +455,26 @@ TEST(FileReq, FutimeSync) {
TEST(FileReq, Chown) { TEST(FileReq, Chown) {
const std::string filename = std::string{TARGET_FILE_REQ_DIR} + std::string{"/test.file"}; const std::string filename = std::string{TARGET_FILE_REQ_DIR} + std::string{"/test.file"};
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto request = loop->resource<uvw::FileReq>(); auto request = loop->resource<uvw::file_req>();
bool checkFileChownEvent = false; bool checkFileChownEvent = false;
request->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); }); request->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
request->on<uvw::FsEvent<uvw::FileReq::Type::FCHOWN>>([&checkFileChownEvent](const auto &, auto &req) { request->on<uvw::fs_event>([&](const auto &event, auto &req) {
ASSERT_FALSE(checkFileChownEvent); if(event.type == uvw::fs_req::fs_type::FCHOWN) {
checkFileChownEvent = true; ASSERT_FALSE(checkFileChownEvent);
req.close(); checkFileChownEvent = true;
req.close();
} else if(event.type == uvw::fs_req::fs_type::FSTAT) {
req.chown(static_cast<uvw::uid_type>(event.stat.st_uid), static_cast<uvw::uid_type>(event.stat.st_gid));
} else if(event.type == uvw::fs_req::fs_type::OPEN) {
req.stat();
};
}); });
request->on<uvw::FsEvent<uvw::FileReq::Type::FSTAT>>([](const auto &event, auto &req) { auto flags = uvw::file_req::file_open_flags::CREAT | uvw::file_req::file_open_flags::RDWR | uvw::file_req::file_open_flags::TRUNC;
auto uid = static_cast<uvw::Uid>(event.stat.st_uid);
auto gid = static_cast<uvw::Uid>(event.stat.st_gid);
req.chown(uid, gid);
});
request->on<uvw::FsEvent<uvw::FileReq::Type::OPEN>>([](const auto &, auto &req) {
req.stat();
});
auto flags = uvw::Flags<uvw::FileReq::FileOpen>::from<uvw::FileReq::FileOpen::CREAT, uvw::FileReq::FileOpen::RDWR, uvw::FileReq::FileOpen::TRUNC>();
request->open(filename, flags, 0644); request->open(filename, flags, 0644);
loop->run(); loop->run();
@ -485,18 +485,19 @@ TEST(FileReq, Chown) {
TEST(FileReq, ChownSync) { TEST(FileReq, ChownSync) {
const std::string filename = std::string{TARGET_FILE_REQ_DIR} + std::string{"/test.file"}; const std::string filename = std::string{TARGET_FILE_REQ_DIR} + std::string{"/test.file"};
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto request = loop->resource<uvw::FileReq>(); auto request = loop->resource<uvw::file_req>();
auto flags = uvw::file_req::file_open_flags::CREAT | uvw::file_req::file_open_flags::RDWR | uvw::file_req::file_open_flags::TRUNC;
ASSERT_TRUE(request->openSync(filename, O_CREAT | O_RDWR | O_TRUNC, 0644)); ASSERT_TRUE(request->open_sync(filename, flags, 0644));
auto statR = request->statSync(); auto statR = request->stat_sync();
ASSERT_TRUE(statR.first); ASSERT_TRUE(statR.first);
auto uid = static_cast<uvw::Uid>(statR.second.st_uid); auto uid = static_cast<uvw::uid_type>(statR.second.st_uid);
auto gid = static_cast<uvw::Uid>(statR.second.st_gid); auto gid = static_cast<uvw::uid_type>(statR.second.st_gid);
ASSERT_TRUE(request->chownSync(uid, gid)); ASSERT_TRUE(request->chown_sync(uid, gid));
ASSERT_TRUE(request->closeSync()); ASSERT_TRUE(request->close_sync());
loop->run(); loop->run();
} }

View File

@ -11,32 +11,33 @@ TEST(FileReq, SendFile) {
const std::string srcFilename = std::string{TARGET_FILE_REQ_SENDFILE_DIR} + std::string{"/src.file"}; const std::string srcFilename = std::string{TARGET_FILE_REQ_SENDFILE_DIR} + std::string{"/src.file"};
const std::string dstFilename = std::string{TARGET_FILE_REQ_SENDFILE_DIR} + std::string{"/dst.file"}; const std::string dstFilename = std::string{TARGET_FILE_REQ_SENDFILE_DIR} + std::string{"/dst.file"};
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto srcReq = loop->resource<uvw::FileReq>(); auto srcReq = loop->resource<uvw::file_req>();
auto dstReq = loop->resource<uvw::FileReq>(); auto dstReq = loop->resource<uvw::file_req>();
bool checkFileSendFileEvent = false; bool checkFileSendFileEvent = false;
dstReq->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); }); dstReq->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
srcReq->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); }); srcReq->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
dstReq->on<uvw::FsEvent<uvw::FileReq::Type::OPEN>>([&srcReq](const auto &, auto &req) { dstReq->on<uvw::fs_event>([&](const auto &event, auto &req) {
srcReq->sendfile(static_cast<uvw::FileHandle>(req), 0, 0); if(event.type == uvw::fs_req::fs_type::OPEN) {
srcReq->sendfile(static_cast<uvw::file_handle>(req), 0, 0);
}
}); });
srcReq->on<uvw::FsEvent<uvw::FileReq::Type::SENDFILE>>([&checkFileSendFileEvent, &dstReq](const auto &, auto &req) { srcReq->on<uvw::fs_event>([&](const auto &event, auto &req) {
ASSERT_FALSE(checkFileSendFileEvent); if(event.type == uvw::fs_req::fs_type::SENDFILE) {
checkFileSendFileEvent = true; ASSERT_FALSE(checkFileSendFileEvent);
dstReq->close(); checkFileSendFileEvent = true;
req.close(); dstReq->close();
req.close();
} else if(event.type == uvw::fs_req::fs_type::OPEN) {
dstReq->open(dstFilename, uvw::file_req::file_open_flags::CREAT | uvw::file_req::file_open_flags::WRONLY | uvw::file_req::file_open_flags::TRUNC, 0644);
}
}); });
srcReq->on<uvw::FsEvent<uvw::FileReq::Type::OPEN>>([&dstFilename, &dstReq](const auto &, auto &) { auto flags = uvw::file_req::file_open_flags::CREAT | uvw::file_req::file_open_flags::RDONLY | uvw::file_req::file_open_flags::TRUNC;
auto flags = uvw::Flags<uvw::FileReq::FileOpen>::from<uvw::FileReq::FileOpen::CREAT, uvw::FileReq::FileOpen::WRONLY, uvw::FileReq::FileOpen::TRUNC>();
dstReq->open(dstFilename, flags, 0644);
});
auto flags = uvw::Flags<uvw::FileReq::FileOpen>::from<uvw::FileReq::FileOpen::CREAT, uvw::FileReq::FileOpen::RDONLY, uvw::FileReq::FileOpen::TRUNC>();
srcReq->open(srcFilename, flags, 0644); srcReq->open(srcFilename, flags, 0644);
loop->run(); loop->run();
@ -48,18 +49,18 @@ TEST(FileReq, SendFileSync) {
const std::string srcFilename = std::string{TARGET_FILE_REQ_SENDFILE_DIR} + std::string{"/src.file"}; const std::string srcFilename = std::string{TARGET_FILE_REQ_SENDFILE_DIR} + std::string{"/src.file"};
const std::string dstFilename = std::string{TARGET_FILE_REQ_SENDFILE_DIR} + std::string{"/dst.file"}; const std::string dstFilename = std::string{TARGET_FILE_REQ_SENDFILE_DIR} + std::string{"/dst.file"};
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto srcReq = loop->resource<uvw::FileReq>(); auto srcReq = loop->resource<uvw::file_req>();
auto dstReq = loop->resource<uvw::FileReq>(); auto dstReq = loop->resource<uvw::file_req>();
ASSERT_TRUE(srcReq->openSync(srcFilename, O_CREAT | O_RDONLY | O_TRUNC, 0644)); ASSERT_TRUE(srcReq->open_sync(srcFilename, uvw::file_req::file_open_flags::CREAT | uvw::file_req::file_open_flags::RDONLY | uvw::file_req::file_open_flags::TRUNC, 0644));
ASSERT_TRUE(dstReq->openSync(dstFilename, O_CREAT | O_WRONLY | O_TRUNC, 0644)); ASSERT_TRUE(dstReq->open_sync(dstFilename, uvw::file_req::file_open_flags::CREAT | uvw::file_req::file_open_flags::WRONLY | uvw::file_req::file_open_flags::TRUNC, 0644));
auto sendfileR = srcReq->sendfileSync(static_cast<uvw::FileHandle>(*dstReq), 0, 0); auto sendfileR = srcReq->sendfile_sync(static_cast<uvw::file_handle>(*dstReq), 0, 0);
ASSERT_TRUE(sendfileR.first); ASSERT_TRUE(sendfileR.first);
ASSERT_TRUE(srcReq->closeSync()); ASSERT_TRUE(srcReq->close_sync());
ASSERT_TRUE(dstReq->closeSync()); ASSERT_TRUE(dstReq->close_sync());
loop->run(); loop->run();
} }

View File

@ -5,40 +5,49 @@
TEST(FsEvent, Functionalities) { TEST(FsEvent, Functionalities) {
const std::string filename = std::string{TARGET_FS_EVENT_DIR} + std::string{"/test.file"}; const std::string filename = std::string{TARGET_FS_EVENT_DIR} + std::string{"/test.file"};
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto handle = loop->resource<uvw::FsEventHandle>(); auto handle = loop->resource<uvw::fs_event_handle>();
auto request = loop->resource<uvw::FileReq>(); auto request = loop->resource<uvw::file_req>();
bool checkFsEventEvent = false; bool checkFsEventEvent = false;
handle->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); }); handle->on<uvw::error_event>([&](const auto &, auto &) { FAIL(); });
request->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); }); request->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
handle->on<uvw::FsEventEvent>([&checkFsEventEvent](const auto &event, auto &hndl) { handle->on<uvw::fs_event_event>([&checkFsEventEvent](const auto &event, auto &hndl) {
ASSERT_FALSE(checkFsEventEvent); ASSERT_FALSE(checkFsEventEvent);
ASSERT_EQ(std::string{event.filename}, std::string{"test.file"}); ASSERT_EQ(std::string{event.filename}, std::string{"test.file"});
checkFsEventEvent = true; checkFsEventEvent = true;
hndl.stop();
ASSERT_EQ(0, hndl.stop());
hndl.close(); hndl.close();
ASSERT_TRUE(hndl.closing()); ASSERT_TRUE(hndl.closing());
}); });
request->on<uvw::FsEvent<uvw::FileReq::Type::WRITE>>([](const auto &, auto &req) { request->on<uvw::fs_event>([&](const auto &event, auto &req) {
req.close(); if(event.type == uvw::fs_req::fs_type::WRITE) {
req.close();
} else if(event.type == uvw::fs_req::fs_type::OPEN) {
req.write(std::unique_ptr<char[]>{new char[1]{42}}, 1, 0);
}
}); });
request->on<uvw::FsEvent<uvw::FileReq::Type::OPEN>>([](const auto &, auto &req) { ASSERT_EQ(0, handle->start(std::string{TARGET_FS_EVENT_DIR}, uvw::fs_event_handle::event_flags::RECURSIVE));
req.write(std::unique_ptr<char[]>{new char[1]{42}}, 1, 0);
}); auto flags = uvw::file_req::file_open_flags::CREAT | uvw::file_req::file_open_flags::RDWR | uvw::file_req::file_open_flags::TRUNC;
handle->start(std::string{TARGET_FS_EVENT_DIR}, uvw::FsEventHandle::Event::RECURSIVE);
auto flags = uvw::Flags<uvw::FileReq::FileOpen>::from<uvw::FileReq::FileOpen::CREAT, uvw::FileReq::FileOpen::RDWR, uvw::FileReq::FileOpen::TRUNC>();
request->open(filename, flags, 0644); request->open(filename, flags, 0644);
ASSERT_EQ(handle->path(), std::string{TARGET_FS_EVENT_DIR}); ASSERT_EQ(handle->path(), std::string{TARGET_FS_EVENT_DIR});
ASSERT_TRUE(handle->active()); ASSERT_TRUE(handle->active());
ASSERT_FALSE(handle->closing()); ASSERT_FALSE(handle->closing());
ASSERT_NE(0, handle->start(std::string{TARGET_FS_EVENT_DIR}, uvw::fs_event_handle::event_flags::RECURSIVE));
ASSERT_FALSE(checkFsEventEvent);
loop->run(); loop->run();
ASSERT_TRUE(checkFsEventEvent); ASSERT_TRUE(checkFsEventEvent);

View File

@ -1,41 +0,0 @@
#include <gtest/gtest.h>
#include <uvw/fs.h>
#include <uvw/fs_event.h>
#include <uvw/fs_poll.h>
TEST(FsPoll, Functionalities) {
const std::string filename = std::string{TARGET_FS_POLL_DIR} + std::string{"/test.file"};
auto loop = uvw::Loop::getDefault();
auto handle = loop->resource<uvw::FsPollHandle>();
auto request = loop->resource<uvw::FileReq>();
bool checkFsPollEvent = false;
handle->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); });
request->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); });
handle->on<uvw::FsPollEvent>([&checkFsPollEvent](const auto &, auto &hndl) {
ASSERT_FALSE(checkFsPollEvent);
checkFsPollEvent = true;
hndl.stop();
hndl.close();
ASSERT_TRUE(hndl.closing());
});
request->on<uvw::FsEvent<uvw::FileReq::Type::WRITE>>([](const auto &, auto &req) {
req.close();
});
request->openSync(filename, O_CREAT | O_RDWR | O_TRUNC, 0755);
handle->start(filename, uvw::FsPollHandle::Time{1000});
request->write(std::unique_ptr<char[]>{new char[1]{42}}, 1, 0);
ASSERT_EQ(handle->path(), filename);
ASSERT_TRUE(handle->active());
ASSERT_FALSE(handle->closing());
loop->run();
ASSERT_TRUE(checkFsPollEvent);
}

File diff suppressed because it is too large Load Diff

View File

@ -6,21 +6,20 @@ struct fake_handle_t {
void *data; void *data;
}; };
struct FakeHandle: uvw::Handle<FakeHandle, fake_handle_t> { struct fake_handle: uvw::handle<fake_handle, fake_handle_t> {
using Handle::Handle; using handle::handle;
template<typename... Args> int init() override {
bool init(Args &&...) { return 1;
return initialize([](auto...) { return true; });
} }
}; };
TEST(Handle, Functionalities) { TEST(Handle, Functionalities) {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto handle = loop->resource<uvw::AsyncHandle>(); auto handle = loop->resource<uvw::async_handle>();
ASSERT_EQ(uvw::Utilities::guessHandle(handle->category()), uvw::HandleType::ASYNC); ASSERT_EQ(uvw::utilities::guess_handle(handle->category()), uvw::handle_type::ASYNC);
ASSERT_EQ(handle->type(), uvw::HandleType::ASYNC); ASSERT_EQ(handle->type(), uvw::handle_type::ASYNC);
ASSERT_TRUE(handle->active()); ASSERT_TRUE(handle->active());
ASSERT_FALSE(handle->closing()); ASSERT_FALSE(handle->closing());
@ -38,18 +37,18 @@ TEST(Handle, Functionalities) {
ASSERT_NE(handle->size(), static_cast<decltype(handle->size())>(0)); ASSERT_NE(handle->size(), static_cast<decltype(handle->size())>(0));
ASSERT_EQ(handle->sendBufferSize(), static_cast<decltype(handle->sendBufferSize())>(0)); ASSERT_LT(handle->send_buffer_size(), 0);
ASSERT_FALSE(handle->sendBufferSize(0)); ASSERT_NE(0, handle->send_buffer_size(0));
ASSERT_EQ(handle->recvBufferSize(), static_cast<decltype(handle->recvBufferSize())>(0)); ASSERT_LT(handle->recv_buffer_size(), 0);
ASSERT_FALSE(handle->recvBufferSize(0)); ASSERT_NE(0, handle->recv_buffer_size(0));
ASSERT_NO_THROW(handle->fd()); ASSERT_NO_THROW(handle->fd());
} }
TEST(Handle, InitializationFailure) { TEST(Handle, InitializationFailure) {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto resource = loop->resource<FakeHandle>(); auto resource = loop->resource<fake_handle>();
ASSERT_FALSE(static_cast<bool>(resource)); ASSERT_FALSE(static_cast<bool>(resource));
} }

View File

@ -2,23 +2,26 @@
#include <uvw/idle.h> #include <uvw/idle.h>
TEST(Idle, StartAndStop) { TEST(Idle, StartAndStop) {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto handle = loop->resource<uvw::IdleHandle>(); auto handle = loop->resource<uvw::idle_handle>();
bool checkIdleEvent = false; bool checkIdleEvent = false;
handle->on<uvw::ErrorEvent>([](auto &&...) { FAIL(); }); handle->on<uvw::error_event>([](auto &&...) { FAIL(); });
handle->on<uvw::IdleEvent>([&checkIdleEvent](const auto &, auto &hndl) { handle->on<uvw::idle_event>([&checkIdleEvent](const auto &, auto &hndl) {
ASSERT_FALSE(checkIdleEvent); ASSERT_FALSE(checkIdleEvent);
checkIdleEvent = true; checkIdleEvent = true;
hndl.stop();
ASSERT_EQ(0, hndl.stop());
hndl.close(); hndl.close();
ASSERT_TRUE(hndl.closing()); ASSERT_TRUE(hndl.closing());
}); });
handle->start(); ASSERT_EQ(0, handle->start());
ASSERT_TRUE(handle->active()); ASSERT_TRUE(handle->active());
ASSERT_FALSE(handle->closing()); ASSERT_FALSE(handle->closing());
@ -28,11 +31,11 @@ TEST(Idle, StartAndStop) {
} }
TEST(Idle, Fake) { TEST(Idle, Fake) {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto handle = loop->resource<uvw::IdleHandle>(); auto handle = loop->resource<uvw::idle_handle>();
handle->on<uvw::ErrorEvent>([](auto &&...) { FAIL(); }); handle->on<uvw::error_event>([](auto &&...) { FAIL(); });
handle->on<uvw::IdleEvent>([](auto &&...) { FAIL(); }); handle->on<uvw::idle_event>([](auto &&...) { FAIL(); });
handle->start(); handle->start();
handle->close(); handle->close();

View File

@ -2,23 +2,23 @@
#include <uvw/lib.h> #include <uvw/lib.h>
TEST(SharedLib, Failure) { TEST(SharedLib, Failure) {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto lib = loop->resource<uvw::SharedLib>("foobar.so"); auto lib = loop->resource<uvw::shared_lib>("foobar.so");
ASSERT_FALSE(static_cast<bool>(*lib)); ASSERT_FALSE(static_cast<bool>(*lib));
ASSERT_NE(lib->error(), nullptr); ASSERT_NE(lib->error(), nullptr);
ASSERT_EQ(&lib->loop(), loop.get()); ASSERT_EQ(&lib->parent(), loop.get());
// this forces a call to the destructor to invoke uv_dlclose // this forces a call to the destructor to invoke uv_dlclose
lib.reset(); lib.reset();
} }
TEST(SharedLib, Success) { TEST(SharedLib, Success) {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto lib = loop->resource<uvw::SharedLib>(TARGET_LIB_SO); auto lib = loop->resource<uvw::shared_lib>(TARGET_LIB_SO);
ASSERT_TRUE(static_cast<bool>(*lib)); ASSERT_TRUE(static_cast<bool>(*lib));
ASSERT_EQ(&lib->loop(), loop.get()); ASSERT_EQ(&lib->parent(), loop.get());
ASSERT_EQ(lib->sym<int(double *)>("foobar"), nullptr); ASSERT_EQ(lib->sym<int(double *)>("foobar"), nullptr);
ASSERT_NE(lib->sym<int(double *)>("fake_func"), nullptr); ASSERT_NE(lib->sym<int(double *)>("fake_func"), nullptr);
double d{1.}; double d{1.};

View File

@ -1,29 +1,28 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <uvw/loop.h> #include <uvw.hpp>
#include <uvw/prepare.h>
#include <uvw/work.h>
TEST(Loop, DefaultLoop) { TEST(Loop, DefaultLoop) {
auto def = uvw::Loop::getDefault(); auto def = uvw::loop::get_default();
ASSERT_TRUE(static_cast<bool>(def)); ASSERT_TRUE(static_cast<bool>(def));
ASSERT_FALSE(def->alive()); ASSERT_FALSE(def->alive());
ASSERT_NO_THROW(def->stop()); ASSERT_NO_THROW(def->stop());
def->walk([](auto &) { FAIL(); }); def->walk([](auto &) { FAIL(); });
auto def2 = uvw::loop::get_default();
auto def2 = uvw::Loop::getDefault();
ASSERT_EQ(def, def2); ASSERT_EQ(def, def2);
ASSERT_EQ(0, def->close());
} }
TEST(Loop, Functionalities) { TEST(Loop, Functionalities) {
auto loop = uvw::Loop::create(); auto loop = uvw::loop::create();
auto handle = loop->resource<uvw::PrepareHandle>(); auto handle = loop->resource<uvw::prepare_handle>();
auto req = loop->resource<uvw::WorkReq>([] {}); auto req = loop->resource<uvw::work_req>([] {});
loop->on<uvw::ErrorEvent>([](auto &&...) { FAIL(); }); loop->on<uvw::error_event>([](auto &&...) { FAIL(); });
req->on<uvw::ErrorEvent>([](auto &&...) { FAIL(); }); req->on<uvw::error_event>([](auto &&...) { FAIL(); });
handle->on<uvw::ErrorEvent>([](auto &&...) { FAIL(); }); handle->on<uvw::error_event>([](auto &&...) { FAIL(); });
ASSERT_TRUE(static_cast<bool>(handle)); ASSERT_TRUE(static_cast<bool>(handle));
ASSERT_TRUE(static_cast<bool>(req)); ASSERT_TRUE(static_cast<bool>(req));
@ -34,15 +33,15 @@ TEST(Loop, Functionalities) {
#ifndef _MSC_VER #ifndef _MSC_VER
// fork isn't implemented on Windows in libuv and it returns an error by default // fork isn't implemented on Windows in libuv and it returns an error by default
ASSERT_NO_THROW(loop->fork()); ASSERT_EQ(0, loop->fork());
#endif #endif
ASSERT_FALSE(loop->alive()); ASSERT_FALSE(loop->alive());
ASSERT_FALSE(loop->timeout().first); ASSERT_FALSE(loop->timeout().first);
handle->start(); handle->start();
handle->on<uvw::PrepareEvent>([](const auto &, auto &hndl) { handle->on<uvw::prepare_event>([](const auto &, auto &hndl) {
hndl.loop().walk([](auto &) { hndl.parent().walk([](auto &) {
static bool trigger = true; static bool trigger = true;
ASSERT_TRUE(trigger); ASSERT_TRUE(trigger);
trigger = false; trigger = false;
@ -52,18 +51,52 @@ TEST(Loop, Functionalities) {
}); });
ASSERT_TRUE(loop->alive()); ASSERT_TRUE(loop->alive());
ASSERT_NO_THROW(loop->run()); ASSERT_EQ(0, loop->run());
loop->walk([](auto &) { FAIL(); }); loop->walk([](auto &) { FAIL(); });
ASSERT_NO_THROW(loop->run<uvw::Loop::Mode::ONCE>()); ASSERT_EQ(0, loop->run(uvw::loop::run_mode::ONCE));
ASSERT_NO_THROW(loop->run<uvw::Loop::Mode::NOWAIT>()); ASSERT_EQ(0, loop->run(uvw::loop::run_mode::NOWAIT));
ASSERT_FALSE(loop->alive()); ASSERT_FALSE(loop->alive());
ASSERT_EQ(0, loop->close());
}
TEST(Loop, Walk) {
auto loop = uvw::loop::create();
loop->resource<uvw::async_handle>();
loop->resource<uvw::check_handle>();
loop->resource<uvw::fs_event_handle>();
loop->resource<uvw::fs_poll_handle>();
loop->resource<uvw::idle_handle>();
loop->resource<uvw::pipe_handle>();
loop->resource<uvw::prepare_handle>();
loop->resource<uvw::signal_handle>();
loop->resource<uvw::tcp_handle>();
loop->resource<uvw::timer_handle>();
loop->resource<uvw::tty_handle>(0, true);
loop->resource<uvw::udp_handle>();
std::size_t count{};
loop->walk([&count](auto &handle) {
++count;
handle.close();
});
ASSERT_EQ(count, 12u);
loop->run();
loop->walk([&count](auto &handle) { --count; });
ASSERT_EQ(count, 12u);
ASSERT_EQ(0, loop->close());
} }
TEST(Loop, UserData) { TEST(Loop, UserData) {
auto loop = uvw::Loop::create(); auto loop = uvw::loop::create();
loop->data(std::make_shared<int>(42)); loop->data(std::make_shared<int>(42));
ASSERT_EQ(*std::static_pointer_cast<int>(loop->data()), 42); ASSERT_EQ(*std::static_pointer_cast<int>(loop->data()), 42);
@ -73,26 +106,32 @@ TEST(Loop, UserData) {
ASSERT_EQ(*std::static_pointer_cast<int>(loop->data()), 42); ASSERT_EQ(*std::static_pointer_cast<int>(loop->data()), 42);
ASSERT_EQ(*loop->data<int>(), 42); ASSERT_EQ(*loop->data<int>(), 42);
ASSERT_EQ(0, loop->close());
} }
TEST(Loop, Configure) { TEST(Loop, Configure) {
auto loop = uvw::Loop::create(); auto loop = uvw::loop::create();
ASSERT_NO_THROW(loop->configure(uvw::Loop::Configure::BLOCK_SIGNAL, 9)); ASSERT_EQ(0, loop->configure(uvw::loop::option::IDLE_TIME));
ASSERT_NO_THROW(loop->run()); ASSERT_EQ(0, loop->run());
ASSERT_EQ(0, loop->close());
} }
TEST(Loop, IdleTime) { TEST(Loop, IdleTime) {
auto loop = uvw::Loop::create(); auto loop = uvw::loop::create();
loop->configure(uvw::Loop::Configure::IDLE_TIME); loop->configure(uvw::loop::option::IDLE_TIME);
ASSERT_EQ(loop->idleTime().count(), 0u); ASSERT_EQ(loop->idle_time().count(), 0u);
ASSERT_EQ(0, loop->close());
} }
TEST(Loop, Raw) { TEST(Loop, Raw) {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
const auto &cloop = uvw::Loop::getDefault(); const auto &cloop = uvw::loop::get_default();
auto *raw = loop->raw(); auto *raw = loop->raw();
auto *craw = cloop->raw(); auto *craw = cloop->raw();
ASSERT_EQ(raw, craw); ASSERT_EQ(raw, craw);
ASSERT_EQ(0, loop->close());
} }

View File

@ -8,31 +8,29 @@ TEST(Pipe, ReadWrite) {
const std::string sockname = std::string{TARGET_PIPE_DIR} + std::string{"/test.sock"}; const std::string sockname = std::string{TARGET_PIPE_DIR} + std::string{"/test.sock"};
#endif #endif
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto server = loop->resource<uvw::PipeHandle>(); auto server = loop->resource<uvw::pipe_handle>();
auto client = loop->resource<uvw::PipeHandle>(); auto client = loop->resource<uvw::pipe_handle>();
server->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); }); server->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
client->on<uvw::ErrorEvent>([](const auto &, auto &) { client->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
FAIL();
server->on<uvw::listen_event>([](const uvw::listen_event &, uvw::pipe_handle &handle) {
std::shared_ptr<uvw::pipe_handle> socket = handle.parent().resource<uvw::pipe_handle>();
socket->on<uvw::error_event>([](const uvw::error_event &, uvw::pipe_handle &) { FAIL(); });
socket->on<uvw::close_event>([&handle](const uvw::close_event &, uvw::pipe_handle &) { handle.close(); });
socket->on<uvw::end_event>([](const uvw::end_event &, uvw::pipe_handle &sock) { sock.close(); });
ASSERT_EQ(0, handle.accept(*socket));
ASSERT_EQ(0, socket->read());
}); });
server->once<uvw::ListenEvent>([](const uvw::ListenEvent &, uvw::PipeHandle &handle) { client->on<uvw::write_event>([](const uvw::write_event &, uvw::pipe_handle &handle) {
std::shared_ptr<uvw::PipeHandle> socket = handle.loop().resource<uvw::PipeHandle>();
socket->on<uvw::ErrorEvent>([](const uvw::ErrorEvent &, uvw::PipeHandle &) { FAIL(); });
socket->on<uvw::CloseEvent>([&handle](const uvw::CloseEvent &, uvw::PipeHandle &) { handle.close(); });
socket->on<uvw::EndEvent>([](const uvw::EndEvent &, uvw::PipeHandle &sock) { sock.close(); });
handle.accept(*socket);
socket->read();
});
client->once<uvw::WriteEvent>([](const uvw::WriteEvent &, uvw::PipeHandle &handle) {
handle.close(); handle.close();
}); });
client->once<uvw::ConnectEvent>([](const uvw::ConnectEvent &, uvw::PipeHandle &handle) { client->on<uvw::connect_event>([](const uvw::connect_event &, uvw::pipe_handle &handle) {
ASSERT_TRUE(handle.writable()); ASSERT_TRUE(handle.writable());
ASSERT_TRUE(handle.readable()); ASSERT_TRUE(handle.readable());
@ -41,8 +39,9 @@ TEST(Pipe, ReadWrite) {
}); });
server->bind(sockname); server->bind(sockname);
server->listen();
client->connect(sockname); ASSERT_EQ(0, server->listen());
ASSERT_EQ(0, client->connect(sockname));
loop->run(); loop->run();
} }
@ -56,35 +55,35 @@ TEST(Pipe, SockPeer) {
const auto peername = sockname; const auto peername = sockname;
#endif #endif
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto server = loop->resource<uvw::PipeHandle>(); auto server = loop->resource<uvw::pipe_handle>();
auto client = loop->resource<uvw::PipeHandle>(); auto client = loop->resource<uvw::pipe_handle>();
server->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); }); server->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
client->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); }); client->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
server->once<uvw::ListenEvent>([&peername](const uvw::ListenEvent &, uvw::PipeHandle &handle) { server->on<uvw::listen_event>([&peername](const uvw::listen_event &, uvw::pipe_handle &handle) {
std::shared_ptr<uvw::PipeHandle> socket = handle.loop().resource<uvw::PipeHandle>(); std::shared_ptr<uvw::pipe_handle> socket = handle.parent().resource<uvw::pipe_handle>();
socket->on<uvw::ErrorEvent>([](const uvw::ErrorEvent &, uvw::PipeHandle &) { FAIL(); }); socket->on<uvw::error_event>([](const uvw::error_event &, uvw::pipe_handle &) { FAIL(); });
socket->on<uvw::CloseEvent>([&handle](const uvw::CloseEvent &, uvw::PipeHandle &) { handle.close(); }); socket->on<uvw::close_event>([&handle](const uvw::close_event &, uvw::pipe_handle &) { handle.close(); });
socket->on<uvw::EndEvent>([](const uvw::EndEvent &, uvw::PipeHandle &sock) { sock.close(); }); socket->on<uvw::end_event>([](const uvw::end_event &, uvw::pipe_handle &sock) { sock.close(); });
handle.accept(*socket);
socket->read();
ASSERT_EQ(0, handle.accept(*socket));
ASSERT_EQ(0, socket->read());
ASSERT_EQ(handle.sock(), peername); ASSERT_EQ(handle.sock(), peername);
}); });
client->once<uvw::ConnectEvent>([&peername](const uvw::ConnectEvent &, uvw::PipeHandle &handle) { client->on<uvw::connect_event>([&peername](const uvw::connect_event &, uvw::pipe_handle &handle) {
ASSERT_EQ(handle.peer(), peername); ASSERT_EQ(handle.peer(), peername);
handle.close(); handle.close();
}); });
server->bind(sockname); server->bind(sockname);
server->listen();
client->connect(sockname); ASSERT_EQ(0, server->listen());
ASSERT_EQ(0, client->connect(sockname));
loop->run(); loop->run();
} }
@ -98,36 +97,38 @@ TEST(Pipe, Shutdown) {
auto data = std::unique_ptr<char[]>(new char[3]{'a', 'b', 'c'}); auto data = std::unique_ptr<char[]>(new char[3]{'a', 'b', 'c'});
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto server = loop->resource<uvw::PipeHandle>(); auto server = loop->resource<uvw::pipe_handle>();
auto client = loop->resource<uvw::PipeHandle>(); auto client = loop->resource<uvw::pipe_handle>();
server->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); }); server->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
client->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); }); client->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
server->once<uvw::ListenEvent>([](const uvw::ListenEvent &, uvw::PipeHandle &handle) { server->on<uvw::listen_event>([](const uvw::listen_event &, uvw::pipe_handle &handle) {
std::shared_ptr<uvw::PipeHandle> socket = handle.loop().resource<uvw::PipeHandle>(); std::shared_ptr<uvw::pipe_handle> socket = handle.parent().resource<uvw::pipe_handle>();
socket->on<uvw::ErrorEvent>([](const uvw::ErrorEvent &, uvw::PipeHandle &) { FAIL(); }); socket->on<uvw::error_event>([](const uvw::error_event &, uvw::pipe_handle &) { FAIL(); });
socket->on<uvw::CloseEvent>([&handle](const uvw::CloseEvent &, uvw::PipeHandle &) { handle.close(); }); socket->on<uvw::close_event>([&handle](const uvw::close_event &, uvw::pipe_handle &) { handle.close(); });
socket->on<uvw::EndEvent>([](const uvw::EndEvent &, uvw::PipeHandle &sock) { sock.close(); }); socket->on<uvw::end_event>([](const uvw::end_event &, uvw::pipe_handle &sock) { sock.close(); });
handle.accept(*socket); ASSERT_EQ(0, handle.accept(*socket));
socket->read(); ASSERT_EQ(0, socket->read());
}); });
client->once<uvw::ShutdownEvent>([](const uvw::ShutdownEvent &, uvw::PipeHandle &handle) { client->on<uvw::shutdown_event>([](const uvw::shutdown_event &, uvw::pipe_handle &handle) {
handle.close(); handle.close();
}); });
client->once<uvw::ConnectEvent>([&data](const uvw::ConnectEvent &, uvw::PipeHandle &handle) { client->on<uvw::connect_event>([&data](const uvw::connect_event &, uvw::pipe_handle &handle) {
handle.write(data.get(), 3); handle.write(data.get(), 3);
handle.shutdown();
ASSERT_EQ(0, handle.shutdown());
}); });
server->bind(sockname); server->bind(sockname);
server->listen();
client->connect(sockname); ASSERT_EQ(0, server->listen());
ASSERT_EQ(0, client->connect(sockname));
loop->run(); loop->run();
} }

View File

@ -2,23 +2,26 @@
#include <uvw/prepare.h> #include <uvw/prepare.h>
TEST(Prepare, StartAndStop) { TEST(Prepare, StartAndStop) {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto handle = loop->resource<uvw::PrepareHandle>(); auto handle = loop->resource<uvw::prepare_handle>();
bool checkPrepareEvent = false; bool checkPrepareEvent = false;
handle->on<uvw::ErrorEvent>([](auto &&...) { FAIL(); }); handle->on<uvw::error_event>([](auto &&...) { FAIL(); });
handle->on<uvw::PrepareEvent>([&checkPrepareEvent](const auto &, auto &hndl) { handle->on<uvw::prepare_event>([&checkPrepareEvent](const auto &, auto &hndl) {
ASSERT_FALSE(checkPrepareEvent); ASSERT_FALSE(checkPrepareEvent);
checkPrepareEvent = true; checkPrepareEvent = true;
hndl.stop();
ASSERT_EQ(0, hndl.stop());
hndl.close(); hndl.close();
ASSERT_TRUE(hndl.closing()); ASSERT_TRUE(hndl.closing());
}); });
handle->start(); ASSERT_EQ(0, handle->start());
ASSERT_TRUE(handle->active()); ASSERT_TRUE(handle->active());
ASSERT_FALSE(handle->closing()); ASSERT_FALSE(handle->closing());
@ -28,11 +31,11 @@ TEST(Prepare, StartAndStop) {
} }
TEST(Prepare, Fake) { TEST(Prepare, Fake) {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto handle = loop->resource<uvw::PrepareHandle>(); auto handle = loop->resource<uvw::prepare_handle>();
handle->on<uvw::ErrorEvent>([](auto &&...) { FAIL(); }); handle->on<uvw::error_event>([](auto &&...) { FAIL(); });
handle->on<uvw::PrepareEvent>([](auto &&...) { FAIL(); }); handle->on<uvw::prepare_event>([](auto &&...) { FAIL(); });
handle->start(); handle->start();
handle->close(); handle->close();

View File

@ -3,8 +3,8 @@
#include <uvw/process.h> #include <uvw/process.h>
TEST(Process, Pid) { TEST(Process, Pid) {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto handle = loop->resource<uvw::ProcessHandle>(); auto handle = loop->resource<uvw::process_handle>();
ASSERT_EQ(handle->pid(), 0); ASSERT_EQ(handle->pid(), 0);
@ -12,8 +12,8 @@ TEST(Process, Pid) {
} }
TEST(Process, Cwd) { TEST(Process, Cwd) {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto handle = loop->resource<uvw::ProcessHandle>(); auto handle = loop->resource<uvw::process_handle>();
handle->cwd("."); handle->cwd(".");
@ -21,15 +21,15 @@ TEST(Process, Cwd) {
} }
TEST(Process, StdIO) { TEST(Process, StdIO) {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto handle = loop->resource<uvw::ProcessHandle>(); auto handle = loop->resource<uvw::process_handle>();
auto pipe = loop->resource<uvw::PipeHandle>(); auto pipe = loop->resource<uvw::pipe_handle>();
uvw::ProcessHandle::disableStdIOInheritance(); uvw::process_handle::disable_stdio_inheritance();
handle->stdio(*pipe, uvw::Flags<uvw::ProcessHandle::StdIO>::from<uvw::ProcessHandle::StdIO::CREATE_PIPE, uvw::ProcessHandle::StdIO::READABLE_PIPE>()); handle->stdio(*pipe, uvw::process_handle::stdio_flags::CREATE_PIPE | uvw::process_handle::stdio_flags::READABLE_PIPE);
handle->stdio(uvw::StdIN, uvw::ProcessHandle::StdIO::IGNORE_STREAM); handle->stdio(uvw::std_in, uvw::process_handle::stdio_flags::IGNORE_STREAM);
handle->stdio(uvw::StdOUT, uvw::ProcessHandle::StdIO::IGNORE_STREAM); handle->stdio(uvw::std_out, uvw::process_handle::stdio_flags::IGNORE_STREAM);
handle->stdio(uvw::StdOUT, uvw::ProcessHandle::StdIO::INHERIT_FD); handle->stdio(uvw::std_out, uvw::process_handle::stdio_flags::INHERIT_FD);
pipe->close(); pipe->close();
loop->run(); loop->run();

View File

@ -3,11 +3,11 @@
#include <uvw/work.h> #include <uvw/work.h>
TEST(Request, Functionalities) { TEST(Request, Functionalities) {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto req = loop->resource<uvw::WorkReq>([]() {}); auto req = loop->resource<uvw::work_req>([]() {});
ASSERT_NE(req->size(), decltype(req->size()){0}); ASSERT_NE(req->size(), decltype(req->size()){0});
ASSERT_FALSE(req->cancel()); ASSERT_LT(req->cancel(), 0);
loop->run(); loop->run();
} }

View File

@ -4,19 +4,17 @@
#include <uvw/async.h> #include <uvw/async.h>
#include <uvw/request.hpp> #include <uvw/request.hpp>
struct Res: uvw::Resource<Res, int> {};
TEST(Resource, Functionalities) { TEST(Resource, Functionalities) {
ASSERT_FALSE(std::is_copy_constructible<uvw::AsyncHandle>::value); ASSERT_FALSE(std::is_copy_constructible<uvw::async_handle>::value);
ASSERT_FALSE(std::is_copy_assignable<uvw::AsyncHandle>::value); ASSERT_FALSE(std::is_copy_assignable<uvw::async_handle>::value);
ASSERT_FALSE(std::is_move_constructible<uvw::AsyncHandle>::value); ASSERT_FALSE(std::is_move_constructible<uvw::async_handle>::value);
ASSERT_FALSE(std::is_move_assignable<uvw::AsyncHandle>::value); ASSERT_FALSE(std::is_move_assignable<uvw::async_handle>::value);
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto resource = loop->resource<uvw::AsyncHandle>(); auto resource = loop->resource<uvw::async_handle>();
ASSERT_EQ(&resource->loop(), loop.get()); ASSERT_EQ(&resource->parent(), loop.get());
resource->data(std::make_shared<int>(42)); resource->data(std::make_shared<int>(42));

View File

@ -3,17 +3,15 @@
#include <uvw/signal.h> #include <uvw/signal.h>
TEST(Signal, Start) { TEST(Signal, Start) {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto handle = loop->resource<uvw::SignalHandle>(); auto handle = loop->resource<uvw::signal_handle>();
handle->on<uvw::ErrorEvent>([](auto &&...) { FAIL(); }); handle->on<uvw::error_event>([](auto &&...) { FAIL(); });
handle->on<uvw::CheckEvent>([](auto &&...) { FAIL(); });
handle->start(2);
ASSERT_EQ(0, handle->start(2));
ASSERT_EQ(2, handle->signal()); ASSERT_EQ(2, handle->signal());
ASSERT_EQ(0, handle->stop());
handle->stop();
handle->close(); handle->close();
ASSERT_FALSE(handle->active()); ASSERT_FALSE(handle->active());
@ -23,17 +21,15 @@ TEST(Signal, Start) {
} }
TEST(Signal, OneShot) { TEST(Signal, OneShot) {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto handle = loop->resource<uvw::SignalHandle>(); auto handle = loop->resource<uvw::signal_handle>();
handle->on<uvw::ErrorEvent>([](auto &&...) { FAIL(); }); handle->on<uvw::error_event>([](auto &&...) { FAIL(); });
handle->on<uvw::CheckEvent>([](auto &&...) { FAIL(); });
handle->oneShot(2);
ASSERT_EQ(0, handle->one_shot(2));
ASSERT_EQ(2, handle->signal()); ASSERT_EQ(2, handle->signal());
ASSERT_EQ(0, handle->stop());
handle->stop();
handle->close(); handle->close();
ASSERT_FALSE(handle->active()); ASSERT_FALSE(handle->active());

View File

@ -5,11 +5,11 @@ struct fake_stream_t {
void *data; void *data;
}; };
struct FakeStreamHandle: uvw::StreamHandle<FakeStreamHandle, fake_stream_t> { struct fake_stream_handle: uvw::stream_handle<fake_stream_handle, fake_stream_t> {
using StreamHandle::StreamHandle; using stream_handle::stream_handle;
template<typename... Args> template<typename... Args>
bool init(Args &&...) { int init(Args &&...) {
return true; return 0;
} }
}; };

View File

@ -2,12 +2,12 @@
#include <uvw/tcp.h> #include <uvw/tcp.h>
TEST(TCP, Functionalities) { TEST(TCP, Functionalities) {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto handle = loop->resource<uvw::TCPHandle>(); auto handle = loop->resource<uvw::tcp_handle>();
ASSERT_TRUE(handle->noDelay(true)); ASSERT_TRUE(handle->no_delay(true));
ASSERT_TRUE(handle->keepAlive(true, uvw::TCPHandle::Time{128})); ASSERT_TRUE(handle->keep_alive(true, uvw::tcp_handle::time{128}));
ASSERT_TRUE(handle->simultaneousAccepts()); ASSERT_TRUE(handle->simultaneous_accepts());
handle->close(); handle->close();
loop->run(); loop->run();
@ -17,41 +17,43 @@ TEST(TCP, ReadWrite) {
const std::string address = std::string{"127.0.0.1"}; const std::string address = std::string{"127.0.0.1"};
const unsigned int port = 4242; const unsigned int port = 4242;
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto server = loop->resource<uvw::TCPHandle>(); auto server = loop->resource<uvw::tcp_handle>();
auto client = loop->resource<uvw::TCPHandle>(); auto client = loop->resource<uvw::tcp_handle>();
server->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); }); server->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
client->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); }); client->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
server->once<uvw::ListenEvent>([](const uvw::ListenEvent &, uvw::TCPHandle &handle) { server->on<uvw::listen_event>([](const uvw::listen_event &, uvw::tcp_handle &handle) {
std::shared_ptr<uvw::TCPHandle> socket = handle.loop().resource<uvw::TCPHandle>(); std::shared_ptr<uvw::tcp_handle> socket = handle.parent().resource<uvw::tcp_handle>();
socket->on<uvw::ErrorEvent>([](const uvw::ErrorEvent &, uvw::TCPHandle &) { FAIL(); }); socket->on<uvw::error_event>([](const uvw::error_event &, uvw::tcp_handle &) { FAIL(); });
socket->on<uvw::CloseEvent>([&handle](const uvw::CloseEvent &, uvw::TCPHandle &) { handle.close(); }); socket->on<uvw::close_event>([&handle](const uvw::close_event &, uvw::tcp_handle &) { handle.close(); });
socket->on<uvw::EndEvent>([](const uvw::EndEvent &, uvw::TCPHandle &sock) { sock.close(); }); socket->on<uvw::end_event>([](const uvw::end_event &, uvw::tcp_handle &sock) { sock.close(); });
handle.accept(*socket); ASSERT_EQ(0, handle.accept(*socket));
socket->read(); ASSERT_EQ(0, socket->read());
}); });
client->once<uvw::WriteEvent>([](const uvw::WriteEvent &, uvw::TCPHandle &handle) { client->on<uvw::write_event>([](const uvw::write_event &, uvw::tcp_handle &handle) {
handle.close(); handle.close();
}); });
client->once<uvw::ConnectEvent>([](const uvw::ConnectEvent &, uvw::TCPHandle &handle) { client->on<uvw::connect_event>([](const uvw::connect_event &, uvw::tcp_handle &handle) {
ASSERT_TRUE(handle.writable()); ASSERT_TRUE(handle.writable());
ASSERT_TRUE(handle.readable()); ASSERT_TRUE(handle.readable());
auto dataTryWrite = std::unique_ptr<char[]>(new char[1]{'a'}); auto dataTryWrite = std::unique_ptr<char[]>(new char[1]{'a'});
handle.tryWrite(std::move(dataTryWrite), 1);
ASSERT_EQ(1, handle.try_write(std::move(dataTryWrite), 1));
auto dataWrite = std::unique_ptr<char[]>(new char[2]{'b', 'c'}); auto dataWrite = std::unique_ptr<char[]>(new char[2]{'b', 'c'});
handle.write(std::move(dataWrite), 2); handle.write(std::move(dataWrite), 2);
}); });
server->bind(address, port); ASSERT_EQ(0, (server->bind(address, port)));
server->listen(); ASSERT_EQ(0, server->listen());
client->connect(address, port); ASSERT_EQ(0, (client->connect(address, port)));
loop->run(); loop->run();
} }
@ -60,39 +62,39 @@ TEST(TCP, SockPeer) {
const std::string address = std::string{"127.0.0.1"}; const std::string address = std::string{"127.0.0.1"};
const unsigned int port = 4242; const unsigned int port = 4242;
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto server = loop->resource<uvw::TCPHandle>(); auto server = loop->resource<uvw::tcp_handle>();
auto client = loop->resource<uvw::TCPHandle>(); auto client = loop->resource<uvw::tcp_handle>();
server->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); }); server->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
client->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); }); client->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
server->once<uvw::ListenEvent>([&address](const uvw::ListenEvent &, uvw::TCPHandle &handle) { server->on<uvw::listen_event>([&address](const uvw::listen_event &, uvw::tcp_handle &handle) {
std::shared_ptr<uvw::TCPHandle> socket = handle.loop().resource<uvw::TCPHandle>(); std::shared_ptr<uvw::tcp_handle> socket = handle.parent().resource<uvw::tcp_handle>();
socket->on<uvw::ErrorEvent>([](const uvw::ErrorEvent &, uvw::TCPHandle &) { FAIL(); }); socket->on<uvw::error_event>([](const uvw::error_event &, uvw::tcp_handle &) { FAIL(); });
socket->on<uvw::CloseEvent>([&handle](const uvw::CloseEvent &, uvw::TCPHandle &) { handle.close(); }); socket->on<uvw::close_event>([&handle](const uvw::close_event &, uvw::tcp_handle &) { handle.close(); });
socket->on<uvw::EndEvent>([](const uvw::EndEvent &, uvw::TCPHandle &sock) { sock.close(); }); socket->on<uvw::end_event>([](const uvw::end_event &, uvw::tcp_handle &sock) { sock.close(); });
handle.accept(*socket); ASSERT_EQ(0, handle.accept(*socket));
socket->read(); ASSERT_EQ(0, socket->read());
uvw::Addr addr = handle.sock(); uvw::socket_address addr = handle.sock();
ASSERT_EQ(addr.ip, address); ASSERT_EQ(addr.ip, address);
}); });
client->once<uvw::ConnectEvent>([&address](const uvw::ConnectEvent &, uvw::TCPHandle &handle) { client->on<uvw::connect_event>([&address](const uvw::connect_event &, uvw::tcp_handle &handle) {
uvw::Addr addr = handle.peer(); uvw::socket_address addr = handle.peer();
ASSERT_EQ(addr.ip, address); ASSERT_EQ(addr.ip, address);
handle.close(); handle.close();
}); });
server->bind(uvw::Addr{address, port}); ASSERT_EQ(0, (server->bind(uvw::socket_address{address, port})));
server->listen(); ASSERT_EQ(0, server->listen());
client->connect(uvw::Addr{address, port}); ASSERT_EQ(0, (client->connect(uvw::socket_address{address, port})));
loop->run(); loop->run();
} }
@ -101,62 +103,48 @@ TEST(TCP, Shutdown) {
const std::string address = std::string{"127.0.0.1"}; const std::string address = std::string{"127.0.0.1"};
const unsigned int port = 4242; const unsigned int port = 4242;
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto server = loop->resource<uvw::TCPHandle>(); auto server = loop->resource<uvw::tcp_handle>();
auto client = loop->resource<uvw::TCPHandle>(); auto client = loop->resource<uvw::tcp_handle>();
server->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); }); server->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
client->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); }); client->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
server->once<uvw::ListenEvent>([](const uvw::ListenEvent &, uvw::TCPHandle &handle) { server->on<uvw::listen_event>([](const uvw::listen_event &, uvw::tcp_handle &handle) {
std::shared_ptr<uvw::TCPHandle> socket = handle.loop().resource<uvw::TCPHandle>(); std::shared_ptr<uvw::tcp_handle> socket = handle.parent().resource<uvw::tcp_handle>();
socket->on<uvw::ErrorEvent>([](const uvw::ErrorEvent &, uvw::TCPHandle &) { FAIL(); }); socket->on<uvw::error_event>([](const uvw::error_event &, uvw::tcp_handle &) { FAIL(); });
socket->on<uvw::CloseEvent>([&handle](const uvw::CloseEvent &, uvw::TCPHandle &) { handle.close(); }); socket->on<uvw::close_event>([&handle](const uvw::close_event &, uvw::tcp_handle &) { handle.close(); });
socket->on<uvw::EndEvent>([](const uvw::EndEvent &, uvw::TCPHandle &sock) { sock.close(); }); socket->on<uvw::end_event>([](const uvw::end_event &, uvw::tcp_handle &sock) { sock.close(); });
handle.accept(*socket); ASSERT_EQ(0, handle.accept(*socket));
socket->read(); ASSERT_EQ(0, socket->read());
}); });
client->once<uvw::ShutdownEvent>([](const uvw::ShutdownEvent &, uvw::TCPHandle &handle) { client->on<uvw::shutdown_event>([](const uvw::shutdown_event &, uvw::tcp_handle &handle) {
handle.close(); handle.close();
}); });
client->once<uvw::ConnectEvent>([](const uvw::ConnectEvent &, uvw::TCPHandle &handle) { client->on<uvw::connect_event>([](const uvw::connect_event &, uvw::tcp_handle &handle) {
handle.shutdown(); ASSERT_EQ(0, handle.shutdown());
}); });
server->bind(address, port); ASSERT_EQ(0, (server->bind(address, port)));
server->listen(); ASSERT_EQ(0, server->listen());
client->connect(address, port); ASSERT_EQ(0, (client->connect(address, port)));
loop->run(); loop->run();
} }
TEST(TCP, WriteError) { TEST(TCP, WriteError) {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto handle = loop->resource<uvw::TCPHandle>(); auto handle = loop->resource<uvw::tcp_handle>();
bool checkWriteSmartPtrErrorEvent = false;
bool checkWriteNakedPtrErrorEvent = false;
bool checkTryWriteSmartPtrErrorEvent = false;
bool checkTryWriteNakedPtrErrorEvent = false;
handle->close(); handle->close();
handle->once<uvw::ErrorEvent>([&checkWriteSmartPtrErrorEvent](const auto &, auto &) { checkWriteSmartPtrErrorEvent = true; });
handle->write(std::unique_ptr<char[]>{}, 0);
handle->once<uvw::ErrorEvent>([&checkWriteNakedPtrErrorEvent](const auto &, auto &) { checkWriteNakedPtrErrorEvent = true; });
handle->write(nullptr, 0);
handle->once<uvw::ErrorEvent>([&checkTryWriteSmartPtrErrorEvent](const auto &, auto &) { checkTryWriteSmartPtrErrorEvent = true; });
handle->tryWrite(std::unique_ptr<char[]>{}, 0);
handle->once<uvw::ErrorEvent>([&checkTryWriteNakedPtrErrorEvent](const auto &, auto &) { checkTryWriteNakedPtrErrorEvent = true; });
handle->tryWrite(nullptr, 0);
loop->run(); ASSERT_NE(0, (handle->write(std::unique_ptr<char[]>{}, 0)));
ASSERT_NE(0, (handle->write(nullptr, 0)));
ASSERT_TRUE(checkWriteSmartPtrErrorEvent); ASSERT_LT(handle->try_write(std::unique_ptr<char[]>{}, 0), 0);
ASSERT_TRUE(checkWriteNakedPtrErrorEvent); ASSERT_LT(handle->try_write(nullptr, 0), 0);
ASSERT_TRUE(checkTryWriteSmartPtrErrorEvent);
ASSERT_TRUE(checkTryWriteNakedPtrErrorEvent);
} }

View File

@ -2,7 +2,7 @@
#include <uvw/thread.h> #include <uvw/thread.h>
TEST(Thread, Run) { TEST(Thread, Run) {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto has_run = std::make_shared<bool>(); auto has_run = std::make_shared<bool>();
auto cb = [](std::shared_ptr<void> data) { auto cb = [](std::shared_ptr<void> data) {
if(auto has_run = std::static_pointer_cast<bool>(data); has_run) { if(auto has_run = std::static_pointer_cast<bool>(data); has_run) {
@ -10,7 +10,7 @@ TEST(Thread, Run) {
} }
}; };
auto handle = loop->resource<uvw::Thread>(cb, has_run); auto handle = loop->resource<uvw::thread>(cb, has_run);
ASSERT_TRUE(handle->run()); ASSERT_TRUE(handle->run());
ASSERT_TRUE(handle->join()); ASSERT_TRUE(handle->join());
@ -20,8 +20,8 @@ TEST(Thread, Run) {
} }
TEST(ThreadLocalStorage, SetGet) { TEST(ThreadLocalStorage, SetGet) {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto localStorage = loop->resource<uvw::ThreadLocalStorage>(); auto localStorage = loop->resource<uvw::thread_local_storage>();
auto flag{true}; auto flag{true};
localStorage->set<bool>(&flag); localStorage->set<bool>(&flag);
@ -31,26 +31,26 @@ TEST(ThreadLocalStorage, SetGet) {
} }
TEST(Mutex, LockUnlock) { TEST(Mutex, LockUnlock) {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto mtx = loop->resource<uvw::Mutex>(); auto mtx = loop->resource<uvw::mutex>();
mtx->lock(); mtx->lock();
#ifdef _MSC_VER #ifdef _MSC_VER
// this is allowed by libuv on Windows // this is allowed by libuv on Windows
ASSERT_TRUE(mtx->tryLock()); ASSERT_TRUE(mtx->try_lock());
#else #else
ASSERT_FALSE(mtx->tryLock()); ASSERT_FALSE(mtx->try_lock());
#endif #endif
mtx->unlock(); mtx->unlock();
ASSERT_TRUE(mtx->tryLock()); ASSERT_TRUE(mtx->try_lock());
#ifdef _MSC_VER #ifdef _MSC_VER
// this is allowed by libuv on Windows // this is allowed by libuv on Windows
ASSERT_TRUE(mtx->tryLock()); ASSERT_TRUE(mtx->try_lock());
#else #else
ASSERT_FALSE(mtx->tryLock()); ASSERT_FALSE(mtx->try_lock());
#endif #endif
mtx->unlock(); mtx->unlock();
@ -59,14 +59,14 @@ TEST(Mutex, LockUnlock) {
} }
TEST(Mutex, RecursiveLockUnlock) { TEST(Mutex, RecursiveLockUnlock) {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto recursive_mtx = loop->resource<uvw::Mutex>(true); auto recursive_mtx = loop->resource<uvw::mutex>(true);
recursive_mtx->lock(); recursive_mtx->lock();
recursive_mtx->unlock(); recursive_mtx->unlock();
recursive_mtx->lock(); recursive_mtx->lock();
ASSERT_TRUE(recursive_mtx->tryLock()); ASSERT_TRUE(recursive_mtx->try_lock());
recursive_mtx->unlock(); recursive_mtx->unlock();
recursive_mtx->unlock(); recursive_mtx->unlock();

View File

@ -2,28 +2,34 @@
#include <uvw/timer.h> #include <uvw/timer.h>
TEST(Timer, StartAndStop) { TEST(Timer, StartAndStop) {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto handleNoRepeat = loop->resource<uvw::TimerHandle>(); auto handleNoRepeat = loop->resource<uvw::timer_handle>();
auto handleRepeat = loop->resource<uvw::TimerHandle>(); auto handleRepeat = loop->resource<uvw::timer_handle>();
bool checkTimerNoRepeatEvent = false; bool checkTimerNoRepeatEvent = false;
bool checkTimerRepeatEvent = false; bool checkTimerRepeatEvent = false;
handleNoRepeat->on<uvw::ErrorEvent>([](auto &&...) { FAIL(); }); handleNoRepeat->on<uvw::error_event>([](auto &&...) { FAIL(); });
handleRepeat->on<uvw::ErrorEvent>([](auto &&...) { FAIL(); }); handleRepeat->on<uvw::error_event>([](auto &&...) { FAIL(); });
handleNoRepeat->on<uvw::TimerEvent>([&checkTimerNoRepeatEvent](const auto &, auto &handle) { handleNoRepeat->on<uvw::timer_event>([&checkTimerNoRepeatEvent](const auto &, auto &handle) {
ASSERT_FALSE(checkTimerNoRepeatEvent); ASSERT_FALSE(checkTimerNoRepeatEvent);
checkTimerNoRepeatEvent = true; checkTimerNoRepeatEvent = true;
handle.stop();
ASSERT_EQ(0, handle.stop());
handle.close(); handle.close();
ASSERT_TRUE(handle.closing()); ASSERT_TRUE(handle.closing());
}); });
handleRepeat->on<uvw::TimerEvent>([&checkTimerRepeatEvent](const auto &, auto &handle) { handleRepeat->on<uvw::timer_event>([&checkTimerRepeatEvent](const auto &, auto &handle) {
if(checkTimerRepeatEvent) { if(checkTimerRepeatEvent) {
handle.stop(); ASSERT_EQ(0, handle.stop());
handle.close(); handle.close();
ASSERT_TRUE(handle.closing()); ASSERT_TRUE(handle.closing());
} else { } else {
checkTimerRepeatEvent = true; checkTimerRepeatEvent = true;
@ -31,8 +37,8 @@ TEST(Timer, StartAndStop) {
} }
}); });
handleNoRepeat->start(uvw::TimerHandle::Time{0}, uvw::TimerHandle::Time{0}); ASSERT_EQ(0, handleNoRepeat->start(uvw::timer_handle::time{0}, uvw::timer_handle::time{0}));
handleRepeat->start(uvw::TimerHandle::Time{0}, uvw::TimerHandle::Time{1}); ASSERT_EQ(0, handleRepeat->start(uvw::timer_handle::time{0}, uvw::timer_handle::time{1}));
ASSERT_TRUE(handleNoRepeat->active()); ASSERT_TRUE(handleNoRepeat->active());
ASSERT_FALSE(handleNoRepeat->closing()); ASSERT_FALSE(handleNoRepeat->closing());
@ -47,18 +53,14 @@ TEST(Timer, StartAndStop) {
} }
TEST(Timer, Again) { TEST(Timer, Again) {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto handle = loop->resource<uvw::TimerHandle>(); auto handle = loop->resource<uvw::timer_handle>();
bool checkErrorEvent = false;
bool checkTimerEvent = false; bool checkTimerEvent = false;
handle->on<uvw::ErrorEvent>([&checkErrorEvent](const auto &, auto &) { handle->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
ASSERT_FALSE(checkErrorEvent);
checkErrorEvent = true;
});
handle->on<uvw::TimerEvent>([&checkTimerEvent](const auto &, auto &hndl) { handle->on<uvw::timer_event>([&checkTimerEvent](const auto &, auto &hndl) {
static bool guard = false; static bool guard = false;
if(guard) { if(guard) {
@ -68,34 +70,38 @@ TEST(Timer, Again) {
ASSERT_TRUE(hndl.closing()); ASSERT_TRUE(hndl.closing());
} else { } else {
guard = true; guard = true;
hndl.again(); ASSERT_EQ(0, hndl.again());
ASSERT_EQ(hndl.repeat(), uvw::TimerHandle::Time{1}); ASSERT_EQ(hndl.repeat(), uvw::timer_handle::time{1});
ASSERT_FALSE(hndl.closing()); ASSERT_FALSE(hndl.closing());
} }
}); });
ASSERT_NO_THROW(handle->again()); ASSERT_NE(0, handle->again());
ASSERT_FALSE(handle->active()); ASSERT_FALSE(handle->active());
ASSERT_TRUE(checkErrorEvent);
checkErrorEvent = false; handle->start(uvw::timer_handle::time{0}, uvw::timer_handle::time{1});
handle->start(uvw::TimerHandle::Time{0}, uvw::TimerHandle::Time{1});
ASSERT_TRUE(handle->active()); ASSERT_TRUE(handle->active());
ASSERT_FALSE(handle->closing()); ASSERT_FALSE(handle->closing());
loop->run(); loop->run();
ASSERT_FALSE(checkErrorEvent);
ASSERT_TRUE(checkTimerEvent); ASSERT_TRUE(checkTimerEvent);
handle->close();
ASSERT_FALSE(handle->active());
ASSERT_TRUE(handle->closing());
ASSERT_NE(0, handle->start(uvw::timer_handle::time{0}, uvw::timer_handle::time{1}));
} }
TEST(Timer, Repeat) { TEST(Timer, Repeat) {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto handle = loop->resource<uvw::TimerHandle>(); auto handle = loop->resource<uvw::timer_handle>();
ASSERT_NO_THROW(handle->repeat(uvw::TimerHandle::Time{42})); ASSERT_NO_THROW(handle->repeat(uvw::timer_handle::time{42}));
ASSERT_EQ(handle->repeat(), uvw::TimerHandle::Time{42}); ASSERT_EQ(handle->repeat(), uvw::timer_handle::time{42});
ASSERT_NO_THROW(handle->close()); ASSERT_NO_THROW(handle->close());
// this forces an internal call to the close callback // this forces an internal call to the close callback
@ -104,13 +110,13 @@ TEST(Timer, Repeat) {
} }
TEST(Timer, Fake) { TEST(Timer, Fake) {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto handle = loop->resource<uvw::TimerHandle>(); auto handle = loop->resource<uvw::timer_handle>();
handle->on<uvw::ErrorEvent>([](auto &&...) { FAIL(); }); handle->on<uvw::error_event>([](auto &&...) { FAIL(); });
handle->on<uvw::TimerEvent>([](auto &&...) { FAIL(); }); handle->on<uvw::timer_event>([](auto &&...) { FAIL(); });
handle->start(uvw::TimerHandle::Time{0}, uvw::TimerHandle::Time{0}); handle->start(uvw::timer_handle::time{0}, uvw::timer_handle::time{0});
handle->close(); handle->close();
ASSERT_FALSE(handle->active()); ASSERT_FALSE(handle->active());
@ -120,15 +126,13 @@ TEST(Timer, Fake) {
} }
TEST(Timer, BaseHandleWalk) { TEST(Timer, BaseHandleWalk) {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto timer = loop->resource<uvw::TimerHandle>(); auto timer = loop->resource<uvw::timer_handle>();
timer->on<uvw::TimerEvent>([](const auto &, uvw::TimerHandle &handle) { timer->on<uvw::timer_event>([](const auto &, uvw::timer_handle &handle) {
handle.loop().walk(uvw::Overloaded{ handle.parent().walk(uvw::overloaded{[](uvw::timer_handle &h) { h.close(); }, [](auto &&) {}});
[](uvw::TimerHandle &h) { h.close(); },
[](auto &&) {}});
}); });
timer->start(uvw::TimerHandle::Time{100}, uvw::TimerHandle::Time{100}); timer->start(uvw::timer_handle::time{100}, uvw::timer_handle::time{100});
loop->run(); loop->run();
} }

View File

@ -3,29 +3,31 @@
#include <uvw/tty.h> #include <uvw/tty.h>
TEST(TTY, Functionalities) { TEST(TTY, Functionalities) {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto handle = loop->resource<uvw::TTYHandle>(uvw::StdOUT, false); auto handle = loop->resource<uvw::tty_handle>(uvw::std_out, false);
auto timer = loop->resource<uvw::TimerHandle>(); auto timer = loop->resource<uvw::timer_handle>();
bool checkWriteEvent = false; bool checkWriteEvent = false;
handle->on<uvw::WriteEvent>([&checkWriteEvent](const auto &, auto &hndl) { handle->on<uvw::write_event>([&checkWriteEvent](const auto &, auto &hndl) {
ASSERT_FALSE(checkWriteEvent); ASSERT_FALSE(checkWriteEvent);
checkWriteEvent = true; checkWriteEvent = true;
hndl.close(); hndl.close();
}); });
timer->on<uvw::TimerEvent>([handle](const auto &, auto &hndl) { timer->on<uvw::timer_event>([handle](const auto &, auto &hndl) {
auto data = std::make_unique<char[]>('*'); auto data = std::make_unique<char[]>('*');
handle->write(std::move(data), 1);
ASSERT_EQ(0, (handle->write(std::move(data), 1)));
hndl.close(); hndl.close();
}); });
ASSERT_TRUE(handle->reset()); ASSERT_TRUE(handle->reset_mode());
ASSERT_TRUE(!handle->readable() || handle->mode(uvw::TTYHandle::Mode::NORMAL)); ASSERT_TRUE(!handle->readable() || handle->mode(uvw::tty_handle::tty_mode::NORMAL));
ASSERT_NO_THROW(handle->getWinSize()); ASSERT_NO_THROW(handle->get_win_size());
timer->start(uvw::TimerHandle::Time{0}, uvw::TimerHandle::Time{0}); timer->start(uvw::timer_handle::time{0}, uvw::timer_handle::time{0});
loop->run(); loop->run();
ASSERT_TRUE(checkWriteEvent); ASSERT_TRUE(checkWriteEvent);

View File

@ -2,15 +2,15 @@
#include <uvw/udp.h> #include <uvw/udp.h>
TEST(UDP, Functionalities) { TEST(UDP, Functionalities) {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto handle = loop->resource<uvw::UDPHandle>(); auto handle = loop->resource<uvw::udp_handle>();
ASSERT_FALSE(handle->multicastMembership("0.0.0.0", "127.0.0.1", uvw::UDPHandle::Membership::JOIN_GROUP)); ASSERT_FALSE(handle->multicast_membership("0.0.0.0", "127.0.0.1", uvw::udp_handle::membership::JOIN_GROUP));
ASSERT_TRUE(handle->multicastMembership("224.0.0.1", "127.0.0.1", uvw::UDPHandle::Membership::JOIN_GROUP)); ASSERT_TRUE(handle->multicast_membership("224.0.0.1", "127.0.0.1", uvw::udp_handle::membership::JOIN_GROUP));
ASSERT_TRUE(handle->multicastMembership("224.0.0.1", "127.0.0.1", uvw::UDPHandle::Membership::LEAVE_GROUP)); ASSERT_TRUE(handle->multicast_membership("224.0.0.1", "127.0.0.1", uvw::udp_handle::membership::LEAVE_GROUP));
ASSERT_TRUE(handle->multicastLoop(true)); ASSERT_TRUE(handle->multicast_loop(true));
ASSERT_TRUE(handle->multicastTtl(42)); ASSERT_TRUE(handle->multicast_ttl(42));
ASSERT_TRUE(handle->multicastInterface("127.0.0.1")); ASSERT_TRUE(handle->multicast_interface("127.0.0.1"));
ASSERT_TRUE(handle->broadcast(true)); ASSERT_TRUE(handle->broadcast(true));
ASSERT_TRUE(handle->ttl(42)); ASSERT_TRUE(handle->ttl(42));
ASSERT_FALSE(handle->ttl(0)); ASSERT_FALSE(handle->ttl(0));
@ -23,14 +23,15 @@ TEST(UDP, BindRecvStop) {
const std::string address = std::string{"127.0.0.1"}; const std::string address = std::string{"127.0.0.1"};
const unsigned int port = 4242; const unsigned int port = 4242;
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto handle = loop->resource<uvw::UDPHandle>(); auto handle = loop->resource<uvw::udp_handle>();
handle->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); }); handle->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
ASSERT_EQ(0, (handle->bind(address, port)));
ASSERT_EQ(0, handle->recv());
ASSERT_EQ(0, handle->stop());
handle->bind(address, port);
handle->recv();
handle->stop();
handle->close(); handle->close();
loop->run(); loop->run();
@ -40,28 +41,28 @@ TEST(UDP, ReadTrySend) {
const std::string address = std::string{"127.0.0.1"}; const std::string address = std::string{"127.0.0.1"};
const unsigned int port = 4242; const unsigned int port = 4242;
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto server = loop->resource<uvw::UDPHandle>(); auto server = loop->resource<uvw::udp_handle>();
auto client = loop->resource<uvw::UDPHandle>(); auto client = loop->resource<uvw::udp_handle>();
server->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); }); server->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
client->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); }); client->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
server->once<uvw::UDPDataEvent>([&client](const uvw::UDPDataEvent &, uvw::UDPHandle &handle) { server->on<uvw::udp_data_event>([&client](const uvw::udp_data_event &, uvw::udp_handle &handle) {
client->close(); client->close();
handle.close(); handle.close();
}); });
server->bind(uvw::Addr{address, port}); ASSERT_EQ(0, (server->bind(uvw::socket_address{address, port})));
server->recv(); ASSERT_EQ(0, server->recv());
auto dataTrySend = std::unique_ptr<char[]>(new char[1]{'a'}); auto dataTrySend = std::unique_ptr<char[]>(new char[1]{'a'});
client->trySend(uvw::Addr{address, port}, dataTrySend.get(), 1); ASSERT_EQ(1, client->try_send(uvw::socket_address{address, port}, dataTrySend.get(), 1));
client->trySend(address, port, nullptr, 0); ASSERT_EQ(0, client->try_send(address, port, nullptr, 0));
client->trySend(uvw::Addr{address, port}, std::move(dataTrySend), 1); ASSERT_EQ(1, client->try_send(uvw::socket_address{address, port}, std::move(dataTrySend), 1));
client->trySend(address, port, std::unique_ptr<char[]>{}, 0); ASSERT_EQ(0, client->try_send(address, port, std::unique_ptr<char[]>{}, 0));
loop->run(); loop->run();
} }
@ -70,30 +71,30 @@ TEST(UDP, ReadSend) {
const std::string address = std::string{"127.0.0.1"}; const std::string address = std::string{"127.0.0.1"};
const unsigned int port = 4242; const unsigned int port = 4242;
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto server = loop->resource<uvw::UDPHandle>(); auto server = loop->resource<uvw::udp_handle>();
auto client = loop->resource<uvw::UDPHandle>(); auto client = loop->resource<uvw::udp_handle>();
server->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); }); server->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
client->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); }); client->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
server->once<uvw::UDPDataEvent>([](const uvw::UDPDataEvent &, uvw::UDPHandle &handle) { server->on<uvw::udp_data_event>([](const uvw::udp_data_event &, uvw::udp_handle &handle) {
handle.close(); handle.close();
}); });
client->once<uvw::SendEvent>([](const uvw::SendEvent &, uvw::UDPHandle &handle) { client->on<uvw::send_event>([](const uvw::send_event &, uvw::udp_handle &handle) {
handle.close(); handle.close();
}); });
server->bind(address, port); ASSERT_EQ(0, (server->bind(address, port)));
server->recv(); ASSERT_EQ(0, server->recv());
auto dataSend = std::unique_ptr<char[]>(new char[2]{'b', 'c'}); auto dataSend = std::unique_ptr<char[]>(new char[2]{'b', 'c'});
client->send(uvw::Addr{address, port}, dataSend.get(), 2); client->send(uvw::socket_address{address, port}, dataSend.get(), 2);
client->send(address, port, nullptr, 0); client->send(address, port, nullptr, 0);
client->send(uvw::Addr{address, port}, std::move(dataSend), 2); client->send(uvw::socket_address{address, port}, std::move(dataSend), 2);
client->send(address, port, std::unique_ptr<char[]>{}, 0); client->send(address, port, std::unique_ptr<char[]>{}, 0);
loop->run(); loop->run();
@ -103,15 +104,16 @@ TEST(UDP, Sock) {
const std::string address = std::string{"127.0.0.1"}; const std::string address = std::string{"127.0.0.1"};
const unsigned int port = 4242; const unsigned int port = 4242;
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto handle = loop->resource<uvw::UDPHandle>(); auto handle = loop->resource<uvw::udp_handle>();
handle->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); }); handle->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
handle->bind(address, port); handle->bind(address, port);
handle->recv(); handle->recv();
uvw::Addr sock = handle->sock(); uvw::socket_address sock = handle->sock();
ASSERT_EQ(sock.ip, address); ASSERT_EQ(sock.ip, address);
ASSERT_EQ(sock.port, decltype(sock.port){port}); ASSERT_EQ(sock.port, decltype(sock.port){port});

View File

@ -1,22 +0,0 @@
#include <gtest/gtest.h>
#include <uvw/async.h>
#include <uvw/underlying_type.hpp>
TEST(UnderlyingType, Functionalities) {
auto loop = uvw::Loop::getDefault();
auto handle = uvw::AsyncHandle::create(loop);
ASSERT_TRUE(handle);
ASSERT_EQ(&handle->loop(), loop.get());
}
TEST(UnderlyingType, Raw) {
auto loop = uvw::Loop::getDefault();
auto handle = uvw::AsyncHandle::create(loop);
const auto &chandle = handle;
auto *raw = handle->raw();
auto *craw = chandle->raw();
ASSERT_EQ(raw, craw);
}

View File

@ -6,93 +6,21 @@
template<typename T> template<typename T>
struct tag { using type = T; }; struct tag { using type = T; };
TEST(Util, UnscopedFlags) {
enum class UnscopedEnum {
FOO = 1,
BAR = 2,
BAZ = 4,
QUUX = 8
};
uvw::Flags<UnscopedEnum> flags{};
ASSERT_NO_THROW((flags = uvw::Flags<UnscopedEnum>::from<UnscopedEnum::FOO, UnscopedEnum::BAR>()));
ASSERT_NO_THROW((flags = uvw::Flags<UnscopedEnum>{UnscopedEnum::BAZ}));
ASSERT_NO_THROW((flags = uvw::Flags<UnscopedEnum>{static_cast<uvw::Flags<UnscopedEnum>::Type>(UnscopedEnum::QUUX)}));
ASSERT_NO_THROW((flags = uvw::Flags<UnscopedEnum>{std::move(flags)}));
ASSERT_NO_THROW((flags = uvw::Flags<UnscopedEnum>{flags}));
flags = uvw::Flags<UnscopedEnum>::from<UnscopedEnum::FOO, UnscopedEnum::QUUX>();
ASSERT_TRUE(static_cast<bool>(flags));
ASSERT_EQ(static_cast<uvw::Flags<UnscopedEnum>::Type>(flags), 9);
ASSERT_TRUE(flags & uvw::Flags<UnscopedEnum>::from<UnscopedEnum::FOO>());
ASSERT_FALSE(flags & UnscopedEnum::BAR);
ASSERT_FALSE(flags & uvw::Flags<UnscopedEnum>::from<UnscopedEnum::BAZ>());
ASSERT_TRUE(flags & UnscopedEnum::QUUX);
ASSERT_NO_THROW(flags = flags | UnscopedEnum::BAR);
ASSERT_NO_THROW(flags = flags | uvw::Flags<UnscopedEnum>::from<UnscopedEnum::BAZ>());
ASSERT_TRUE(flags & UnscopedEnum::FOO);
ASSERT_TRUE(flags & uvw::Flags<UnscopedEnum>::from<UnscopedEnum::BAR>());
ASSERT_TRUE(flags & UnscopedEnum::BAZ);
ASSERT_TRUE(flags & uvw::Flags<UnscopedEnum>::from<UnscopedEnum::QUUX>());
}
TEST(Util, ScopedFlags) {
enum class ScopedEnum {
FOO = 1,
BAR = 2,
BAZ = 4,
QUUX = 8
};
uvw::Flags<ScopedEnum> flags{};
ASSERT_NO_THROW((flags = uvw::Flags<ScopedEnum>::from<ScopedEnum::FOO, ScopedEnum::BAR>()));
ASSERT_NO_THROW((flags = uvw::Flags<ScopedEnum>{ScopedEnum::BAZ}));
ASSERT_NO_THROW((flags = uvw::Flags<ScopedEnum>{static_cast<uvw::Flags<ScopedEnum>::Type>(ScopedEnum::QUUX)}));
ASSERT_NO_THROW((flags = uvw::Flags<ScopedEnum>{std::move(flags)}));
ASSERT_NO_THROW((flags = uvw::Flags<ScopedEnum>{flags}));
flags = uvw::Flags<ScopedEnum>::from<ScopedEnum::FOO, ScopedEnum::QUUX>();
ASSERT_TRUE(static_cast<bool>(flags));
ASSERT_EQ(static_cast<uvw::Flags<ScopedEnum>::Type>(flags), 9);
ASSERT_TRUE(flags & uvw::Flags<ScopedEnum>::from<ScopedEnum::FOO>());
ASSERT_FALSE(flags & ScopedEnum::BAR);
ASSERT_FALSE(flags & uvw::Flags<ScopedEnum>::from<ScopedEnum::BAZ>());
ASSERT_TRUE(flags & ScopedEnum::QUUX);
ASSERT_NO_THROW(flags = flags | ScopedEnum::BAR);
ASSERT_NO_THROW(flags = flags | uvw::Flags<ScopedEnum>::from<ScopedEnum::BAZ>());
ASSERT_TRUE(flags & ScopedEnum::FOO);
ASSERT_TRUE(flags & uvw::Flags<ScopedEnum>::from<ScopedEnum::BAR>());
ASSERT_TRUE(flags & ScopedEnum::BAZ);
ASSERT_TRUE(flags & uvw::Flags<ScopedEnum>::from<ScopedEnum::QUUX>());
}
TEST(Util, Utilities) { TEST(Util, Utilities) {
ASSERT_EQ(uvw::PidType{}, uvw::PidType{}); ASSERT_EQ(uvw::pid_type{}, uvw::pid_type{});
ASSERT_NE(uvw::Utilities::OS::pid(), uvw::PidType{}); ASSERT_NE(uvw::utilities::os::pid(), uvw::pid_type{});
ASSERT_NE(uvw::Utilities::OS::parent(), uvw::PidType{}); ASSERT_NE(uvw::utilities::os::ppid(), uvw::pid_type{});
ASSERT_FALSE(uvw::Utilities::OS::homedir().empty()); ASSERT_FALSE(uvw::utilities::os::homedir().empty());
ASSERT_FALSE(uvw::Utilities::OS::tmpdir().empty()); ASSERT_FALSE(uvw::utilities::os::tmpdir().empty());
ASSERT_NE(uvw::Utilities::OS::hostname(), ""); ASSERT_NE(uvw::utilities::os::hostname(), "");
ASSERT_TRUE(uvw::Utilities::OS::env("UVW_TEST_UTIL_UTILITIES", "TRUE")); ASSERT_TRUE(uvw::utilities::os::env("UVW_TEST_UTIL_UTILITIES", "TRUE"));
ASSERT_TRUE(uvw::Utilities::OS::env("UVW_TEST_UTIL_UTILITIES") == "TRUE"); ASSERT_TRUE(uvw::utilities::os::env("UVW_TEST_UTIL_UTILITIES") == "TRUE");
ASSERT_TRUE(uvw::Utilities::OS::env("UVW_TEST_UTIL_UTILITIES", "")); ASSERT_TRUE(uvw::utilities::os::env("UVW_TEST_UTIL_UTILITIES", ""));
ASSERT_FALSE(uvw::Utilities::OS::env("UVW_TEST_UTIL_UTILITIES") == "TRUE"); ASSERT_FALSE(uvw::utilities::os::env("UVW_TEST_UTIL_UTILITIES") == "TRUE");
auto passwd = uvw::Utilities::OS::passwd(); auto passwd = uvw::utilities::os::passwd();
ASSERT_TRUE(static_cast<bool>(passwd)); ASSERT_TRUE(static_cast<bool>(passwd));
ASSERT_FALSE(passwd.username().empty()); ASSERT_FALSE(passwd.username().empty());
@ -105,67 +33,67 @@ TEST(Util, Utilities) {
ASSERT_FALSE(passwd.shell().empty()); ASSERT_FALSE(passwd.shell().empty());
#endif #endif
ASSERT_EQ(uvw::Utilities::guessHandle(uvw::FileHandle{-1}), uvw::HandleType::UNKNOWN); ASSERT_EQ(uvw::utilities::guess_handle(uvw::file_handle{-1}), uvw::handle_type::UNKNOWN);
ASSERT_NE(uvw::Utilities::guessHandle(uvw::StdIN), uvw::HandleType::UNKNOWN); ASSERT_NE(uvw::utilities::guess_handle(uvw::std_in), uvw::handle_type::UNKNOWN);
auto guessHandle = [](auto tag, auto type) { auto guessHandle = [](auto tag, auto type) {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto handle = loop->resource<typename decltype(tag)::type>(); auto handle = loop->resource<typename decltype(tag)::type>();
ASSERT_EQ(uvw::Utilities::guessHandle(handle->category()), type); ASSERT_EQ(uvw::utilities::guess_handle(handle->category()), type);
handle->close(); handle->close();
loop->run(); loop->run();
}; };
guessHandle(tag<uvw::AsyncHandle>{}, uvw::HandleType::ASYNC); guessHandle(tag<uvw::async_handle>{}, uvw::handle_type::ASYNC);
guessHandle(tag<uvw::CheckHandle>{}, uvw::HandleType::CHECK); guessHandle(tag<uvw::check_handle>{}, uvw::handle_type::CHECK);
guessHandle(tag<uvw::FsEventHandle>{}, uvw::HandleType::FS_EVENT); guessHandle(tag<uvw::fs_event_handle>{}, uvw::handle_type::FS_EVENT);
guessHandle(tag<uvw::FsPollHandle>{}, uvw::HandleType::FS_POLL); guessHandle(tag<uvw::fs_poll_handle>{}, uvw::handle_type::FS_POLL);
guessHandle(tag<uvw::IdleHandle>{}, uvw::HandleType::IDLE); guessHandle(tag<uvw::idle_handle>{}, uvw::handle_type::IDLE);
guessHandle(tag<uvw::PipeHandle>{}, uvw::HandleType::PIPE); guessHandle(tag<uvw::pipe_handle>{}, uvw::handle_type::PIPE);
guessHandle(tag<uvw::PrepareHandle>{}, uvw::HandleType::PREPARE); guessHandle(tag<uvw::prepare_handle>{}, uvw::handle_type::PREPARE);
guessHandle(tag<uvw::TCPHandle>{}, uvw::HandleType::TCP); guessHandle(tag<uvw::tcp_handle>{}, uvw::handle_type::TCP);
guessHandle(tag<uvw::TimerHandle>{}, uvw::HandleType::TIMER); guessHandle(tag<uvw::timer_handle>{}, uvw::handle_type::TIMER);
guessHandle(tag<uvw::UDPHandle>{}, uvw::HandleType::UDP); guessHandle(tag<uvw::udp_handle>{}, uvw::handle_type::UDP);
guessHandle(tag<uvw::SignalHandle>{}, uvw::HandleType::SIGNAL); guessHandle(tag<uvw::signal_handle>{}, uvw::handle_type::SIGNAL);
auto cpuInfo = uvw::Utilities::cpuInfo(); auto cpuInfo = uvw::utilities::cpu();
ASSERT_NE(cpuInfo.size(), decltype(cpuInfo.size()){0}); ASSERT_NE(cpuInfo.size(), decltype(cpuInfo.size()){0});
ASSERT_FALSE(cpuInfo[0].model.empty()); ASSERT_FALSE(cpuInfo[0].model.empty());
ASSERT_NE(cpuInfo[0].speed, decltype(cpuInfo[0].speed){0}); ASSERT_NE(cpuInfo[0].speed, decltype(cpuInfo[0].speed){0});
auto interfaceAddresses = uvw::Utilities::interfaceAddresses(); auto interfaceAddresses = uvw::utilities::interface_addresses();
ASSERT_NE(interfaceAddresses.size(), decltype(interfaceAddresses.size()){0}); ASSERT_NE(interfaceAddresses.size(), decltype(interfaceAddresses.size()){0});
ASSERT_FALSE(interfaceAddresses[0].name.empty()); ASSERT_FALSE(interfaceAddresses[0].name.empty());
ASSERT_FALSE(interfaceAddresses[0].address.ip.empty()); ASSERT_FALSE(interfaceAddresses[0].address.ip.empty());
ASSERT_FALSE(interfaceAddresses[0].netmask.ip.empty()); ASSERT_FALSE(interfaceAddresses[0].netmask.ip.empty());
ASSERT_NO_THROW(uvw::Utilities::indexToName(0)); ASSERT_NO_THROW(uvw::utilities::index_to_name(0));
ASSERT_NO_THROW(uvw::Utilities::indexToIid(0)); ASSERT_NO_THROW(uvw::utilities::index_to_iid(0));
ASSERT_TRUE(uvw::Utilities::replaceAllocator( ASSERT_TRUE(uvw::utilities::replace_allocator(
[](size_t size) { return malloc(size); }, [](size_t size) { return malloc(size); },
[](void *ptr, size_t size) { return realloc(ptr, size); }, [](void *ptr, size_t size) { return realloc(ptr, size); },
[](size_t num, size_t size) { return calloc(num, size); }, [](size_t num, size_t size) { return calloc(num, size); },
[](void *ptr) { return free(ptr); })); [](void *ptr) { return free(ptr); }));
ASSERT_NO_THROW(uvw::Utilities::loadAverage()); ASSERT_NO_THROW(uvw::utilities::load_average());
ASSERT_NE(uvw::Utilities::totalMemory(), decltype(uvw::Utilities::totalMemory()){0}); ASSERT_NE(uvw::utilities::total_memory(), decltype(uvw::utilities::total_memory()){0});
ASSERT_NE(uvw::Utilities::uptime(), decltype(uvw::Utilities::uptime()){0}); ASSERT_NE(uvw::utilities::uptime(), decltype(uvw::utilities::uptime()){0});
ASSERT_NO_THROW(uvw::Utilities::rusage()); ASSERT_NO_THROW(uvw::utilities::rusage());
ASSERT_NE(uvw::Utilities::hrtime(), decltype(uvw::Utilities::hrtime()){0}); ASSERT_NE(uvw::utilities::hrtime(), decltype(uvw::utilities::hrtime()){0});
ASSERT_FALSE(uvw::Utilities::path().empty()); ASSERT_FALSE(uvw::utilities::path().empty());
ASSERT_FALSE(uvw::Utilities::cwd().empty()); ASSERT_FALSE(uvw::utilities::cwd().empty());
ASSERT_TRUE(uvw::Utilities::chdir(uvw::Utilities::cwd())); ASSERT_TRUE(uvw::utilities::chdir(uvw::utilities::cwd()));
std::unique_ptr<char[], void (*)(void *)> fake{new char[1], [](void *ptr) { delete[] static_cast<char *>(ptr); }}; std::unique_ptr<char[], void (*)(void *)> fake{new char[1], [](void *ptr) { delete[] static_cast<char *>(ptr); }};
char *argv = fake.get(); char *argv = fake.get();
argv[0] = '\0'; argv[0] = '\0';
ASSERT_NE(uvw::Utilities::setupArgs(1, &argv), nullptr); ASSERT_NE(uvw::utilities::setup_args(1, &argv), nullptr);
ASSERT_NE(uvw::Utilities::processTitle(), std::string{}); ASSERT_NE(uvw::utilities::process_title(), std::string{});
ASSERT_TRUE(uvw::Utilities::processTitle(uvw::Utilities::processTitle())); ASSERT_TRUE(uvw::utilities::process_title(uvw::utilities::process_title()));
ASSERT_NE(uvw::Utilities::availableParallelism(), 0u); ASSERT_NE(uvw::utilities::available_parallelism(), 0u);
} }

22
test/uvw/uv_type.cpp Normal file
View File

@ -0,0 +1,22 @@
#include <gtest/gtest.h>
#include <uvw/async.h>
#include <uvw/uv_type.hpp>
TEST(UvType, Functionalities) {
auto loop = uvw::loop::get_default();
auto handle = loop->resource<uvw::async_handle>();
ASSERT_TRUE(handle);
ASSERT_EQ(&handle->parent(), loop.get());
}
TEST(UvType, Raw) {
auto loop = uvw::loop::get_default();
auto handle = loop->resource<uvw::async_handle>();
const auto &chandle = handle;
auto *raw = handle->raw();
auto *craw = chandle->raw();
ASSERT_EQ(raw, craw);
}

View File

@ -4,51 +4,53 @@
#include <uvw/work.h> #include <uvw/work.h>
TEST(Work, RunTask) { TEST(Work, RunTask) {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto handle = loop->resource<uvw::CheckHandle>(); auto handle = loop->resource<uvw::check_handle>();
bool checkTask = false; bool checkTask = false;
auto req = loop->resource<uvw::WorkReq>([&checkTask]() { auto req = loop->resource<uvw::work_req>([&checkTask]() {
ASSERT_FALSE(checkTask); ASSERT_FALSE(checkTask);
checkTask = true; checkTask = true;
}); });
req->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); }); req->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
req->on<uvw::WorkEvent>([&handle](const auto &, auto &) { req->on<uvw::work_event>([&handle](const auto &, auto &) {
handle->close(); handle->close();
}); });
handle->start(); handle->start();
req->queue();
ASSERT_EQ(0, req->queue());
loop->run(); loop->run();
ASSERT_TRUE(checkTask); ASSERT_TRUE(checkTask);
} }
TEST(Work, Cancellation) { TEST(Work, Cancellation) {
auto loop = uvw::Loop::getDefault(); auto loop = uvw::loop::get_default();
auto handle = loop->resource<uvw::TimerHandle>(); auto handle = loop->resource<uvw::timer_handle>();
bool checkErrorEvent = false; bool checkErrorEvent = false;
handle->on<uvw::TimerEvent>([](const auto &, auto &hndl) { handle->on<uvw::timer_event>([](const auto &, auto &hndl) {
hndl.stop(); hndl.stop();
hndl.close(); hndl.close();
}); });
for(auto i = 0; i < 5 /* default uv thread pool size + 1 */; ++i) { for(auto i = 0; i < 5 /* default uv thread pool size + 1 */; ++i) {
auto req = loop->resource<uvw::WorkReq>([]() {}); auto req = loop->resource<uvw::work_req>([]() {});
req->on<uvw::WorkEvent>([](const auto &, auto &) {}); req->on<uvw::work_event>([](const auto &, auto &) {});
req->on<uvw::ErrorEvent>([&checkErrorEvent](const auto &, auto &) { checkErrorEvent = true; }); req->on<uvw::error_event>([&checkErrorEvent](const auto &, auto &) { checkErrorEvent = true; });
req->queue(); req->queue();
req->cancel(); req->cancel();
} }
handle->start(uvw::TimerHandle::Time{500}, uvw::TimerHandle::Time{500}); handle->start(uvw::timer_handle::time{500}, uvw::timer_handle::time{500});
loop->run(); loop->run();
ASSERT_TRUE(checkErrorEvent); ASSERT_TRUE(checkErrorEvent);