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 <memory>
void listen(uvw::Loop &loop) {
std::shared_ptr<uvw::TCPHandle> tcp = loop.resource<uvw::TCPHandle>();
void listen(uvw::loop &loop) {
std::shared_ptr<uvw::tcp_handle> tcp = loop.resource<uvw::tcp_handle>();
tcp->once<uvw::ListenEvent>([](const uvw::ListenEvent &, uvw::TCPHandle &srv) {
std::shared_ptr<uvw::TCPHandle> client = srv.loop().resource<uvw::TCPHandle>();
tcp->on<uvw::listen_event>([](const uvw::listen_event &, uvw::tcp_handle &srv) {
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::EndEvent>([](const uvw::EndEvent &, uvw::TCPHandle &client) { client.close(); });
client->on<uvw::close_event>([ptr = srv.shared_from_this()](const uvw::close_event &, uvw::tcp_handle &) { ptr->close(); });
client->on<uvw::end_event>([](const uvw::end_event &, uvw::tcp_handle &client) { client.close(); });
srv.accept(*client);
client->read();
@ -20,12 +20,12 @@ void listen(uvw::Loop &loop) {
tcp->listen();
}
void conn(uvw::Loop &loop) {
auto tcp = loop.resource<uvw::TCPHandle>();
void conn(uvw::loop &loop) {
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' });
tcp.write(std::move(dataWrite), 2);
tcp.close();
@ -36,7 +36,7 @@ void conn(uvw::Loop &loop) {
int main() {
std::cout << "Getting UVW loop ...\n";
auto loop = uvw::Loop::getDefault();
auto loop = uvw::loop::get_default();
std::cout << "Staring UVW listener ...\n";
listen(*loop);
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
#
set(UVW_VERSION_MAJOR 2)
set(UVW_VERSION_MINOR 12)
set(UVW_VERSION_PATCH 1)
set(UVW_VERSION_MAJOR 3)
set(UVW_VERSION_MINOR 0)
set(UVW_VERSION_PATCH 0)
project(
uvw
@ -263,4 +263,5 @@ add_custom_target(
AUTHORS
LICENSE
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/>
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
graceful C++ API. Currently, no `uv_*_t` data structure is actually exposed by
the library.<br/>
The basic idea is to wrap the *C-ish* interface of `libuv` behind a graceful C++
API.<br/>
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
rules which are used with `libuv`.<br/>
@ -43,14 +42,14 @@ closed once it is no longer in use.
#include <uvw.hpp>
#include <memory>
void listen(uvw::Loop &loop) {
std::shared_ptr<uvw::TCPHandle> tcp = loop.resource<uvw::TCPHandle>();
void listen(uvw::loop &loop) {
std::shared_ptr<uvw::tcp_handle> tcp = loop.resource<uvw::tcp_handle>();
tcp->once<uvw::ListenEvent>([](const uvw::ListenEvent &, uvw::TCPHandle &srv) {
std::shared_ptr<uvw::TCPHandle> client = srv.loop().resource<uvw::TCPHandle>();
tcp->once<uvw::listen_event>([](const uvw::listen_event &, uvw::tcp_handle &srv) {
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::EndEvent>([](const uvw::EndEvent &, uvw::TCPHandle &client) { client.close(); });
client->on<uvw::close_event>([ptr = srv.shared_from_this()](const uvw::close_event &, uvw::tcp_handle &) { ptr->close(); });
client->on<uvw::end_event>([](const uvw::end_event &, uvw::tcp_handle &client) { client.close(); });
srv.accept(*client);
client->read();
@ -60,12 +59,12 @@ void listen(uvw::Loop &loop) {
tcp->listen();
}
void conn(uvw::Loop &loop) {
auto tcp = loop.resource<uvw::TCPHandle>();
void conn(uvw::loop &loop) {
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' });
tcp.write(std::move(dataWrite), 2);
tcp.close();
@ -75,7 +74,7 @@ void conn(uvw::Loop &loop) {
}
int main() {
auto loop = uvw::Loop::getDefault();
auto loop = uvw::loop::get_default();
listen(*loop);
conn(*loop);
loop->run();
@ -229,7 +228,7 @@ For more details, please refer to the
## Handles
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
them. Because of that, memory usage will grow if users simply forget about a
handle.<br/>
@ -239,7 +238,7 @@ as calling the `close` member function on them.
## Requests
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/>
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
@ -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:
```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
@ -263,7 +262,7 @@ equivalent:
```cpp
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
@ -273,23 +272,21 @@ In order to create a resource and to bind it to the given loop, just do the
following:
```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
that resource will be returned.<br/>
The line above creates and initializes a tcp handle, then a shared pointer to
that resource is returned.<br/>
Users should check if pointers have been correctly initialized: in case of
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
auto tcp = TCPHandle::create(loop);
auto tcp = loop->uninitialized_resource<uvw::tcp_handle>();
tcp->init();
```
Pretty annoying indeed. Using a loop is the recommended approach.
The resources also accept arbitrary user-data that won't be touched in any
All resources also accept arbitrary user-data that won't be touched in any
case.<br/>
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/>
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.
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:
```cpp
handle.loop().walk(uvw::Overloaded{
[](uvw::TimerHandle &h){ /* application code for timers here */ },
handle.parent().walk(uvw::overloaded{
[](uvw::timer_handle &h){ /* application code for timers here */ },
[](auto &&){ /* ignore all other types */ }
});
```
@ -332,58 +329,52 @@ No need to keep track of them.
## The event-based approach
`uvw` offers an event-based approach, so resources are small event emitters
to which listeners can be attached.<br/>
Attaching a listener to a resource is the recommended way to be notified about
changes.<br/>
Listeners must be callable objects of type `void(EventType &, ResourceType &)`,
`uvw` offers an event-based approach where resources are small event emitters to
which listeners are attached.<br/>
Attaching listeners to resources is the recommended way to receive notifications
about their operations.<br/>
Listeners are callable objects of type `void(event_type &, resource_type &)`,
where:
* `EventType` is the type of the event for which they have been designed.
* `ResourceType` is the type of the resource that has originated the event.
* `event_type` is the type of the event for which they have been designed.
* `resource_type` is the type of the resource that has originated the event.
It means that the following function types are all valid:
* `void(EventType &, ResourceType &)`
* `void(const EventType &, ResourceType &)`
* `void(EventType &, const ResourceType &)`
* `void(const EventType &, const ResourceType &)`
* `void(event_type &, resource_type &)`
* `void(const event_type &, resource_type &)`
* `void(event_type &, const resource_type &)`
* `void(const event_type &, const resource_type &)`
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.
Please note that there is no need to keep around references to the resources,
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
removed after the first event of the given type.
* `resource.on<EventType>(listener)`: to be used for long-running listeners.
To know if a listener exists for a given type, the class offers a `has` function
template. Similarly, the `reset` function template is be used to reset and thus
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,
`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/>
Almost all the resources emit `error_event` in case of errors.<br/>
All the other events are specific for the given resource and documented in the
API reference.
The code below shows how to create a simple tcp server using `uvw`:
```cpp
auto loop = uvw::Loop::getDefault();
auto tcp = loop->resource<uvw::TCPHandle>();
auto loop = uvw::loop::get_default();
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) {
std::shared_ptr<uvw::TCPHandle> client = srv.loop().resource<uvw::TCPHandle>();
client->once<uvw::EndEvent>([](const uvw::EndEvent &, uvw::TCPHandle &client) { client.close(); });
client->on<uvw::DataEvent>([](const uvw::DataEvent &, uvw::TCPHandle &) { /* data received */ });
tcp->on<uvw::listen_event>([](const uvw::listen_event &, uvw::tcp_handle &srv) {
std::shared_ptr<uvw::tcp_handle> client = srv.parent().resource<uvw::tcp_handle>();
client->on<uvw::end_event>([](const uvw::end_event &, uvw::tcp_handle &client) { client.close(); });
client->on<uvw::data_event>([](const uvw::data_event &, uvw::tcp_handle &) { /* data received */ });
srv.accept(*client);
client->read();
});
@ -392,11 +383,7 @@ tcp->bind("127.0.0.1", 4242);
tcp->listen();
```
Note also that `uvw::TCPHandle` already supports _IPv6_ out-of-the-box. The
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.
Note also that `uvw::tcp_handle` already supports _IPv6_ out-of-the-box.<br/>
The API reference is the recommended documentation for further details about
resources and their methods.
@ -414,8 +401,8 @@ things.
That being said, _going raw_ is a matter of using the `raw` member functions:
```cpp
auto loop = uvw::Loop::getDefault();
auto tcp = loop->resource<uvw::TCPHandle>();
auto loop = uvw::loop::get_default();
auto tcp = loop->resource<uvw::tcp_handle>();
uv_loop_t *raw = loop->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/dns.h"
#include "uvw/emitter.h"
#include "uvw/enum.hpp"
#include "uvw/fs.h"
#include "uvw/fs_event.h"
#include "uvw/fs_poll.h"
@ -22,6 +23,6 @@
#include "uvw/timer.h"
#include "uvw/tty.h"
#include "uvw/udp.h"
#include "uvw/underlying_type.hpp"
#include "uvw/util.h"
#include "uvw/uv_type.hpp"
#include "uvw/work.h"

View File

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

View File

@ -7,26 +7,22 @@
namespace uvw {
/**
* @brief AsyncEvent event.
*
* It will be emitted by AsyncHandle according with its functionalities.
*/
struct AsyncEvent {};
/*! @brief Async event. */
struct async_event {};
/**
* @brief The AsyncHandle handle.
* @brief The async handle.
*
* Async handles allow the user to _wakeup_ the event loop and get an event
* 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> {
static void sendCallback(uv_async_t *handle);
class async_handle final: public handle<async_handle, uv_async_t, async_event> {
static void send_callback(uv_async_t *hndl);
public:
using Handle::Handle;
using handle::handle;
/**
* @brief Initializes the handle.
@ -34,21 +30,23 @@ public:
* Unlike other handle initialization functions, it immediately starts the
* 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/>
* An AsyncEvent event will be emitted on the loop thread.
* An async event is emitted on the loop thread.
*
* See the official
* [documentation](http://docs.libuv.org/en/v1.x/async.html#c.uv_async_send)
* for further details.
*
* @return Underlying return value.
*/
void send();
int send();
};
} // namespace uvw

View File

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

View File

@ -7,45 +7,44 @@
namespace uvw {
/**
* @brief CheckEvent event.
*
* It will be emitted by CheckHandle according with its functionalities.
*/
struct CheckEvent {};
/*! @brief Check event. */
struct check_event {};
/**
* @brief The CheckHandle handle.
* @brief The check handle.
*
* Check handles will emit a CheckEvent event once per loop iteration, right
* after polling for I/O.
* Check handles will emit a check event once per loop iteration, right after
* 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> {
static void startCallback(uv_check_t *handle);
class check_handle final: public handle<check_handle, uv_check_t, check_event> {
static void start_callback(uv_check_t *hndl);
public:
using Handle::Handle;
using handle::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.
*
* 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.
*
* @return Underlying return value.
*/
void start();
int start();
/**
* @brief Stops the handle.
* @return Underlying return value.
*/
void stop();
int stop();
};
} // namespace uvw

View File

@ -6,111 +6,88 @@
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)} {}
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} {}
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) {
ptr->publish(ErrorEvent{status});
ptr->publish(error_event{status});
} else {
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) {
invoke(&uv_getaddrinfo, parent(), get(), &addrInfoCallback, node, service, hints);
UVW_INLINE int get_addr_info_req::node_addr_info(const char *node, const char *service, addrinfo *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) {
auto req = get();
auto err = uv_getaddrinfo(parent(), req, nullptr, node, service, hints);
UVW_INLINE auto get_addr_info_req::node_addr_info_sync(const char *node, const char *service, addrinfo *hints) {
auto req = raw();
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); }};
return std::make_pair(!err, std::move(data));
}
UVW_INLINE void GetAddrInfoReq::nodeAddrInfo(const std::string &node, addrinfo *hints) {
nodeAddrInfo(node.data(), nullptr, hints);
UVW_INLINE int get_addr_info_req::node_addr_info(const std::string &node, addrinfo *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) {
return nodeAddrInfoSync(node.data(), nullptr, 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 node_addr_info_sync(node.data(), nullptr, hints);
}
UVW_INLINE void GetAddrInfoReq::serviceAddrInfo(const std::string &service, addrinfo *hints) {
nodeAddrInfo(nullptr, service.data(), hints);
UVW_INLINE int get_addr_info_req::service_addr_info(const std::string &service, addrinfo *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) {
return nodeAddrInfoSync(nullptr, service.data(), 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 node_addr_info_sync(nullptr, service.data(), hints);
}
UVW_INLINE void GetAddrInfoReq::addrInfo(const std::string &node, const std::string &service, addrinfo *hints) {
nodeAddrInfo(node.data(), service.data(), hints);
UVW_INLINE int get_addr_info_req::addr_info(const std::string &node, const std::string &service, addrinfo *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) {
return nodeAddrInfoSync(node.data(), service.data(), 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 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) {
ptr->publish(ErrorEvent{status});
ptr->publish(error_event{status});
} else {
ptr->publish(NameInfoEvent{hostname, service});
ptr->publish(name_info_event{hostname, service});
}
}
UVW_INLINE void GetNameInfoReq::nameInfo(const sockaddr &addr, int flags) {
invoke(&uv_getnameinfo, parent(), get(), &nameInfoCallback, &addr, flags);
UVW_INLINE int get_name_info_req::name_info(const sockaddr &addr, int flags) {
return this->leak_if(uv_getnameinfo(parent().raw(), raw(), &name_info_callback, &addr, flags));
}
template<typename I>
UVW_INLINE void GetNameInfoReq::nameInfo(const std::string &ip, unsigned int port, int flags) {
typename details::IpTraits<I>::Type addr;
details::IpTraits<I>::addrFunc(ip.data(), port, &addr);
nameInfo(reinterpret_cast<const sockaddr &>(addr), flags);
UVW_INLINE int get_name_info_req::name_info(const std::string &ip, unsigned int port, int flags) {
return name_info(details::ip_addr(ip.data(), port), flags);
}
template<typename I>
UVW_INLINE void GetNameInfoReq::nameInfo(Addr addr, int flags) {
nameInfo<I>(std::move(addr.ip), addr.port, flags);
UVW_INLINE int get_name_info_req::name_info(socket_address addr, int flags) {
return name_info(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) {
auto req = get();
auto err = uv_getnameinfo(parent(), req, nullptr, &addr, 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 = raw();
auto err = uv_getnameinfo(parent().raw(), req, nullptr, &addr, flags);
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 *>> GetNameInfoReq::nameInfoSync(const std::string &ip, unsigned int port, int flags) {
typename details::IpTraits<I>::Type addr;
details::IpTraits<I>::addrFunc(ip.data(), port, &addr);
return nameInfoSync(reinterpret_cast<const sockaddr &>(addr), flags);
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) {
return name_info_sync(details::ip_addr(ip.data(), port), flags);
}
template<typename I>
UVW_INLINE std::pair<bool, std::pair<const char *, const char *>> GetNameInfoReq::nameInfoSync(Addr addr, int flags) {
return nameInfoSync<I>(std::move(addr.ip), addr.port, flags);
UVW_INLINE std::pair<bool, std::pair<const char *, const char *>> get_name_info_req::name_info_sync(socket_address addr, int flags) {
return name_info_sync(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

View File

@ -11,15 +11,11 @@
namespace uvw {
/**
* @brief AddrInfoEvent event.
*
* It will be emitted by GetAddrInfoReq according with its functionalities.
*/
struct AddrInfoEvent {
using Deleter = void (*)(addrinfo *);
/*! @brief The addrinfo event. */
struct addr_info_event {
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`.
@ -27,16 +23,12 @@ struct AddrInfoEvent {
* See [getaddrinfo](http://linux.die.net/man/3/getaddrinfo) for further
* details.
*/
std::unique_ptr<addrinfo, Deleter> data;
std::unique_ptr<addrinfo, deleter> data;
};
/**
* @brief NameInfoEvent event.
*
* It will be emitted by GetNameInfoReq according with its functionalities.
*/
struct NameInfoEvent {
NameInfoEvent(const char *host, const char *serv);
/*! @brief The nameinfo event. */
struct name_info_event {
name_info_event(const char *host, const char *serv);
/**
* @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/>
* 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> {
static void addrInfoCallback(uv_getaddrinfo_t *req, int status, addrinfo *res);
void nodeAddrInfo(const char *node, const char *service, addrinfo *hints = nullptr);
auto nodeAddrInfoSync(const char *node, const char *service, addrinfo *hints = nullptr);
class get_addr_info_req final: public request<get_addr_info_req, uv_getaddrinfo_t, addr_info_event> {
static void addr_info_callback(uv_getaddrinfo_t *req, int status, addrinfo *res);
int node_addr_info(const char *node, const char *service, addrinfo *hints = nullptr);
auto node_addr_info_sync(const char *node, const char *service, addrinfo *hints = nullptr);
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).
* @param node Either a numerical network address or a network hostname.
* @param hints Optional `addrinfo` data structure with additional address
* 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).
@ -90,17 +83,18 @@ public:
*
* @return A `std::pair` composed as it follows:
* * 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).
* @param service Either a service name or a port number as a string.
* @param hints Optional `addrinfo` data structure with additional address
* 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).
@ -111,9 +105,9 @@ public:
*
* @return A `std::pair` composed as it follows:
* * 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).
@ -121,8 +115,9 @@ public:
* @param service Either a service name or a port number as a string.
* @param hints Optional `addrinfo` data structure with additional address
* 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).
@ -134,48 +129,49 @@ public:
*
* @return A `std::pair` composed as it follows:
* * 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/>
* 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> {
static void nameInfoCallback(uv_getnameinfo_t *req, int status, const char *hostname, const char *service);
class get_name_info_req final: public request<get_name_info_req, uv_getnameinfo_t, name_info_event> {
static void name_info_callback(uv_getnameinfo_t *req, int status, const char *hostname, const char *service);
public:
using Request::Request;
using request::request;
/**
* @brief Async [getnameinfo](http://linux.die.net/man/3/getnameinfo).
* @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
* @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).
* @param ip A valid IP address.
* @param port A valid port number.
* @param flags Optional flags that modify the behavior of `getnameinfo`.
* @return Underlying return value.
*/
template<typename I = IPv4>
void nameInfo(const std::string &ip, unsigned int port, int flags = 0);
int name_info(const std::string &ip, unsigned int port, int flags = 0);
/**
* @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`.
* @return Underlying return value.
*/
template<typename I = IPv4>
void nameInfo(Addr addr, int flags = 0);
int name_info(socket_address addr, int flags = 0);
/**
* @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 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).
@ -204,13 +200,12 @@ public:
* * A `const char *` containing a valid hostname.
* * A `const char *` containing a valid service name.
*/
template<typename I = IPv4>
std::pair<bool, std::pair<const char *, const char *>> nameInfoSync(const std::string &ip, unsigned int port, int flags = 0);
std::pair<bool, std::pair<const char *, const char *>> name_info_sync(const std::string &ip, unsigned int port, int flags = 0);
/**
* @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`.
*
* @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 service name.
*/
template<typename I = IPv4>
std::pair<bool, std::pair<const char *, const char *>> nameInfoSync(Addr addr, int flags = 0);
std::pair<bool, std::pair<const char *, const char *>> name_info_sync(socket_address 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
#ifndef UVW_AS_LIB

View File

@ -6,23 +6,23 @@
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);
}
UVW_INLINE const char *ErrorEvent::what() const noexcept {
UVW_INLINE const char *error_event::what() const noexcept {
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);
}
UVW_INLINE int ErrorEvent::code() const noexcept {
UVW_INLINE int error_event::code() const noexcept {
return ec;
}
UVW_INLINE ErrorEvent::operator bool() const noexcept {
UVW_INLINE error_event::operator bool() const noexcept {
return ec < 0;
}

View File

@ -1,7 +1,6 @@
#ifndef UVW_EMITTER_INCLUDE_H
#define UVW_EMITTER_INCLUDE_H
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <functional>
@ -11,18 +10,19 @@
#include <unordered_map>
#include <utility>
#include <uv.h>
#include "config.h"
#include "type_info.hpp"
namespace uvw {
/**
* @brief The ErrorEvent event.
* @brief Error event.
*
* 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>>>
explicit ErrorEvent(U val) noexcept
explicit error_event(U val) noexcept
: ec{static_cast<int>(val)} {}
/**
@ -79,215 +79,75 @@ private:
* Almost everything in `uvw` is an event emitter.<br/>
* This is the base class from which resources and loops inherit.
*/
template<typename T>
class Emitter {
struct BaseHandler {
virtual ~BaseHandler() noexcept = default;
virtual bool empty() const noexcept = 0;
virtual void clear() noexcept = 0;
};
template<typename T, typename... E>
class emitter {
public:
template<typename U>
using listener_t = std::function<void(U &, T &)>;
template<typename E>
struct Handler final: BaseHandler {
using Listener = std::function<void(E &, T &)>;
using Element = std::pair<bool, Listener>;
using ListenerList = std::list<Element>;
using Connection = typename ListenerList::iterator;
bool empty() const noexcept override {
auto pred = [](auto &&element) { return element.first; };
return std::all_of(onceL.cbegin(), onceL.cend(), pred) && std::all_of(onL.cbegin(), onL.cend(), pred);
private:
template<typename U>
const auto &handler() const noexcept {
return std::get<listener_t<U>>(handlers);
}
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));
template<typename U>
auto &handler() noexcept {
return std::get<listener_t<U>>(handlers);
}
protected:
template<typename E>
void publish(E event) {
handler<E>().publish(std::move(event), *static_cast<T *>(this));
template<typename U>
void publish(U event) {
if(auto &listener = handler<U>(); listener) {
listener(event, *static_cast<T *>(this));
}
}
public:
template<typename E>
using Listener = typename Handler<E>::Listener;
/**
* @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>);
virtual ~emitter() noexcept {
static_assert(std::is_base_of_v<emitter<T, E...>, T>);
}
/**
* @brief Registers a long-lived listener with the event emitter.
*
* This method can be used to register a listener that is meant to be
* invoked more than 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
* This method is used to register a listener with the emitter.<br/>
* A 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> on(Listener<E> f) {
return handler<E>().on(std::move(f));
template<typename U>
void on(listener_t<U> 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.
*
* 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,
* @brief Checks if there is a listener registered for the specific event.
* @return True if there is a listener registered for the specific event,
* false otherwise.
*/
template<typename E>
bool empty() const noexcept {
auto id = type<E>();
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(); });
template<typename U>
bool has() const noexcept {
return static_cast<bool>(handler<U>());
}
private:
std::unordered_map<std::uint32_t, std::unique_ptr<BaseHandler>> handlers{};
std::tuple<listener_t<error_event>, listener_t<E>...> handlers{};
};
} // 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 {
UVW_INLINE void FileReq::fsOpenCallback(uv_fs_t *req) {
auto ptr = reserve(req);
if(req->result < 0) {
ptr->publish(ErrorEvent{req->result});
UVW_INLINE void file_req::fs_open_callback(uv_fs_t *req) {
if(auto ptr = reserve(req); req->result < 0) {
ptr->publish(error_event{req->result});
} else {
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) {
auto ptr = reserve(req);
if(req->result < 0) {
ptr->publish(ErrorEvent{req->result});
UVW_INLINE void file_req::fs_close_callback(uv_fs_t *req) {
if(auto ptr = reserve(req); req->result < 0) {
ptr->publish(error_event{req->result});
} else {
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) {
auto ptr = reserve(req);
if(req->result < 0) {
ptr->publish(ErrorEvent{req->result});
UVW_INLINE void file_req::fs_read_callback(uv_fs_t *req) {
if(auto ptr = reserve(req); req->result < 0) {
ptr->publish(error_event{req->result});
} 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 {
uv_fs_req_cleanup(get());
UVW_INLINE file_req::~file_req() noexcept {
uv_fs_req_cleanup(raw());
}
UVW_INLINE void FileReq::close() {
cleanupAndInvoke(&uv_fs_close, parent(), get(), file, &fsCloseCallback);
UVW_INLINE void file_req::close() {
uv_fs_req_cleanup(this->raw());
uv_fs_close(parent().raw(), raw(), file, &fs_close_callback);
}
UVW_INLINE bool FileReq::closeSync() {
auto req = get();
UVW_INLINE bool file_req::close_sync() {
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) {
file = BAD_FD;
@ -58,14 +54,16 @@ UVW_INLINE bool FileReq::closeSync() {
return !(req->result < 0);
}
UVW_INLINE void FileReq::open(const std::string &path, Flags<FileOpen> flags, int mode) {
cleanupAndInvoke(&uv_fs_open, parent(), get(), path.data(), flags, mode, &fsOpenCallback);
UVW_INLINE void file_req::open(const std::string &path, file_open_flags flags, int mode) {
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) {
auto req = get();
UVW_INLINE bool file_req::open_sync(const std::string &path, file_open_flags flags, int mode) {
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) {
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);
}
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]};
buffer = uv_buf_init(current.get(), len);
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]};
buffer = uv_buf_init(current.get(), len);
uv_buf_t bufs[] = {buffer};
auto req = get();
cleanupAndInvokeSync(&uv_fs_read, parent(), req, file, bufs, 1, offset);
auto req = raw();
uv_fs_req_cleanup(this->raw());
uv_fs_read(parent().raw(), req, file, bufs, 1, offset, nullptr);
bool err = req->result < 0;
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);
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)};
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);
uv_buf_t bufs[] = {uv_buf_init(current.get(), len)};
auto req = get();
cleanupAndInvokeSync(&uv_fs_write, parent(), req, file, bufs, 1, offset);
auto req = raw();
uv_fs_req_cleanup(this->raw());
uv_fs_write(parent().raw(), req, file, bufs, 1, offset, nullptr);
bool err = req->result < 0;
return std::make_pair(!err, err ? 0 : std::size_t(req->result));
}
UVW_INLINE void FileReq::stat() {
cleanupAndInvoke(&uv_fs_fstat, parent(), get(), file, &fsStatCallback<Type::FSTAT>);
UVW_INLINE void file_req::stat() {
uv_fs_req_cleanup(this->raw());
uv_fs_fstat(parent().raw(), raw(), file, &fs_request_callback);
}
UVW_INLINE std::pair<bool, Stat> FileReq::statSync() {
auto req = get();
cleanupAndInvokeSync(&uv_fs_fstat, parent(), req, file);
UVW_INLINE std::pair<bool, file_info> file_req::stat_sync() {
auto req = raw();
uv_fs_req_cleanup(this->raw());
uv_fs_fstat(parent().raw(), req, file, nullptr);
return std::make_pair(!(req->result < 0), req->statbuf);
}
UVW_INLINE void FileReq::sync() {
cleanupAndInvoke(&uv_fs_fsync, parent(), get(), file, &fsGenericCallback<Type::FSYNC>);
UVW_INLINE void file_req::sync() {
uv_fs_req_cleanup(this->raw());
uv_fs_fsync(parent().raw(), raw(), file, &fs_request_callback);
}
UVW_INLINE bool FileReq::syncSync() {
auto req = get();
cleanupAndInvokeSync(&uv_fs_fsync, parent(), req, file);
UVW_INLINE bool file_req::sync_sync() {
auto req = raw();
uv_fs_req_cleanup(this->raw());
uv_fs_fsync(parent().raw(), req, file, nullptr);
return !(req->result < 0);
}
UVW_INLINE void FileReq::datasync() {
cleanupAndInvoke(&uv_fs_fdatasync, parent(), get(), file, &fsGenericCallback<Type::FDATASYNC>);
UVW_INLINE void file_req::datasync() {
uv_fs_req_cleanup(this->raw());
uv_fs_fdatasync(parent().raw(), raw(), file, &fs_request_callback);
}
UVW_INLINE bool FileReq::datasyncSync() {
auto req = get();
cleanupAndInvokeSync(&uv_fs_fdatasync, parent(), req, file);
UVW_INLINE bool file_req::datasync_sync() {
auto req = raw();
uv_fs_req_cleanup(this->raw());
uv_fs_fdatasync(parent().raw(), req, file, nullptr);
return !(req->result < 0);
}
UVW_INLINE void FileReq::truncate(int64_t offset) {
cleanupAndInvoke(&uv_fs_ftruncate, parent(), get(), file, offset, &fsGenericCallback<Type::FTRUNCATE>);
UVW_INLINE void file_req::truncate(int64_t offset) {
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) {
auto req = get();
cleanupAndInvokeSync(&uv_fs_ftruncate, parent(), req, file, offset);
UVW_INLINE bool file_req::truncate_sync(int64_t offset) {
auto req = raw();
uv_fs_req_cleanup(this->raw());
uv_fs_ftruncate(parent().raw(), req, file, offset, nullptr);
return !(req->result < 0);
}
UVW_INLINE void FileReq::sendfile(FileHandle out, int64_t offset, std::size_t length) {
cleanupAndInvoke(&uv_fs_sendfile, parent(), get(), out, file, offset, length, &fsResultCallback<Type::SENDFILE>);
UVW_INLINE void file_req::sendfile(file_handle out, int64_t offset, std::size_t length) {
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) {
auto req = get();
cleanupAndInvokeSync(&uv_fs_sendfile, parent(), req, out, file, offset, 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 = raw();
uv_fs_req_cleanup(this->raw());
uv_fs_sendfile(parent().raw(), req, out, file, offset, length, nullptr);
bool err = req->result < 0;
return std::make_pair(!err, err ? 0 : std::size_t(req->result));
}
UVW_INLINE void FileReq::chmod(int mode) {
cleanupAndInvoke(&uv_fs_fchmod, parent(), get(), file, mode, &fsGenericCallback<Type::FCHMOD>);
UVW_INLINE void file_req::chmod(int mode) {
uv_fs_req_cleanup(this->raw());
uv_fs_fchmod(parent().raw(), raw(), file, mode, &fs_request_callback);
}
UVW_INLINE bool FileReq::chmodSync(int mode) {
auto req = get();
cleanupAndInvokeSync(&uv_fs_fchmod, parent(), req, file, mode);
UVW_INLINE bool file_req::chmod_sync(int mode) {
auto req = raw();
uv_fs_req_cleanup(this->raw());
uv_fs_fchmod(parent().raw(), req, file, mode, nullptr);
return !(req->result < 0);
}
UVW_INLINE void FileReq::futime(FsRequest::Time atime, FsRequest::Time mtime) {
cleanupAndInvoke(&uv_fs_futime, parent(), get(), file, atime.count(), mtime.count(), &fsGenericCallback<Type::FUTIME>);
UVW_INLINE void file_req::futime(fs_request::time atime, fs_request::time mtime) {
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) {
auto req = get();
cleanupAndInvokeSync(&uv_fs_futime, parent(), req, file, atime.count(), mtime.count());
UVW_INLINE bool file_req::futime_sync(fs_request::time atime, fs_request::time mtime) {
auto req = raw();
uv_fs_req_cleanup(this->raw());
uv_fs_futime(parent().raw(), req, file, atime.count(), mtime.count(), nullptr);
return !(req->result < 0);
}
UVW_INLINE void FileReq::chown(Uid uid, Gid gid) {
cleanupAndInvoke(&uv_fs_fchown, parent(), get(), file, uid, gid, &fsGenericCallback<Type::FCHOWN>);
UVW_INLINE void file_req::chown(uid_type uid, gid_type gid) {
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) {
auto req = get();
cleanupAndInvokeSync(&uv_fs_fchown, parent(), req, file, uid, gid);
UVW_INLINE bool file_req::chown_sync(uid_type uid, gid_type gid) {
auto req = raw();
uv_fs_req_cleanup(this->raw());
uv_fs_fchown(parent().raw(), req, file, uid, gid, nullptr);
return !(req->result < 0);
}
UVW_INLINE FileReq::operator FileHandle() const noexcept {
UVW_INLINE file_req::operator file_handle() const noexcept {
return file;
}
UVW_INLINE void FsReq::fsReadlinkCallback(uv_fs_t *req) {
auto ptr = reserve(req);
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 fs_req::~fs_req() noexcept {
uv_fs_req_cleanup(raw());
}
UVW_INLINE void FsReq::fsReaddirCallback(uv_fs_t *req) {
auto ptr = reserve(req);
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 void fs_req::unlink(const std::string &path) {
uv_fs_req_cleanup(this->raw());
uv_fs_unlink(parent().raw(), raw(), path.data(), &fs_request_callback);
}
UVW_INLINE FsReq::~FsReq() noexcept {
uv_fs_req_cleanup(get());
}
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());
UVW_INLINE bool fs_req::unlink_sync(const std::string &path) {
auto req = raw();
uv_fs_req_cleanup(this->raw());
uv_fs_unlink(parent().raw(), req, path.data(), nullptr);
return !(req->result < 0);
}
UVW_INLINE void FsReq::mkdir(const std::string &path, int mode) {
cleanupAndInvoke(&uv_fs_mkdir, parent(), get(), path.data(), mode, &fsGenericCallback<Type::MKDIR>);
UVW_INLINE void fs_req::mkdir(const std::string &path, int mode) {
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) {
auto req = get();
cleanupAndInvokeSync(&uv_fs_mkdir, parent(), req, path.data(), mode);
UVW_INLINE bool fs_req::mkdir_sync(const std::string &path, int mode) {
auto req = raw();
uv_fs_req_cleanup(this->raw());
uv_fs_mkdir(parent().raw(), req, path.data(), mode, nullptr);
return !(req->result < 0);
}
UVW_INLINE void FsReq::mkdtemp(const std::string &tpl) {
cleanupAndInvoke(&uv_fs_mkdtemp, parent(), get(), tpl.data(), &fsGenericCallback<Type::MKDTEMP>);
UVW_INLINE void fs_req::mkdtemp(const std::string &tpl) {
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) {
auto req = get();
cleanupAndInvokeSync(&uv_fs_mkdtemp, parent(), req, tpl.data());
UVW_INLINE std::pair<bool, const char *> fs_req::mkdtemp_sync(const std::string &tpl) {
auto req = raw();
uv_fs_req_cleanup(this->raw());
uv_fs_mkdtemp(parent().raw(), req, tpl.data(), nullptr);
return std::make_pair(!(req->result < 0), req->path);
}
UVW_INLINE void FsReq::mkstemp(const std::string &tpl) {
cleanupAndInvoke(&uv_fs_mkstemp, parent(), get(), tpl.data(), &fsResultCallback<Type::MKSTEMP>);
UVW_INLINE void fs_req::mkstemp(const std::string &tpl) {
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, {}};
auto req = get();
cleanupAndInvokeSync(&uv_fs_mkdtemp, parent(), req, tpl.data());
auto req = raw();
uv_fs_req_cleanup(this->raw());
uv_fs_mkstemp(parent().raw(), req, tpl.data(), nullptr);
ret.first = !(req->result < 0);
if(ret.first) {
@ -269,46 +275,51 @@ UVW_INLINE std::pair<bool, std::pair<std::string, std::size_t>> FsReq::mkstempSy
return ret;
}
UVW_INLINE void FsReq::lutime(const std::string &path, Time atime, Time mtime) {
cleanupAndInvoke(&uv_fs_lutime, parent(), get(), path.data(), atime.count(), mtime.count(), &fsGenericCallback<Type::LUTIME>);
UVW_INLINE void fs_req::lutime(const std::string &path, time atime, time mtime) {
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) {
auto req = get();
cleanupAndInvokeSync(&uv_fs_lutime, parent(), req, path.data(), atime.count(), mtime.count());
UVW_INLINE bool fs_req::lutime_sync(const std::string &path, time atime, time mtime) {
auto req = raw();
uv_fs_req_cleanup(this->raw());
uv_fs_lutime(parent().raw(), req, path.data(), atime.count(), mtime.count(), nullptr);
return !(req->result < 0);
}
UVW_INLINE void FsReq::rmdir(const std::string &path) {
cleanupAndInvoke(&uv_fs_rmdir, parent(), get(), path.data(), &fsGenericCallback<Type::RMDIR>);
UVW_INLINE void fs_req::rmdir(const std::string &path) {
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) {
auto req = get();
cleanupAndInvokeSync(&uv_fs_rmdir, parent(), req, path.data());
UVW_INLINE bool fs_req::rmdir_sync(const std::string &path) {
auto req = raw();
uv_fs_req_cleanup(this->raw());
uv_fs_rmdir(parent().raw(), req, path.data(), nullptr);
return !(req->result < 0);
}
UVW_INLINE void FsReq::scandir(const std::string &path, int flags) {
cleanupAndInvoke(&uv_fs_scandir, parent(), get(), path.data(), flags, &fsResultCallback<Type::SCANDIR>);
UVW_INLINE void fs_req::scandir(const std::string &path, int flags) {
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) {
auto req = get();
cleanupAndInvokeSync(&uv_fs_scandir, parent(), req, path.data(), flags);
UVW_INLINE std::pair<bool, std::size_t> fs_req::scandir_sync(const std::string &path, int flags) {
auto req = raw();
uv_fs_req_cleanup(this->raw());
uv_fs_scandir(parent().raw(), req, path.data(), flags, nullptr);
bool err = req->result < 0;
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() {
std::pair<bool, std::pair<EntryType, const char *>> ret{false, {EntryType::UNKNOWN, nullptr}};
UVW_INLINE std::pair<bool, std::pair<fs_req::entry_type, const char *>> fs_req::scandir_next() {
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(get());
auto res = uv_fs_scandir_next(get(), dirents);
uv_fs_req_cleanup(raw());
auto res = uv_fs_scandir_next(raw(), dirents);
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.first = true;
}
@ -316,192 +327,226 @@ UVW_INLINE std::pair<bool, std::pair<FsReq::EntryType, const char *>> FsReq::sca
return ret;
}
UVW_INLINE void FsReq::stat(const std::string &path) {
cleanupAndInvoke(&uv_fs_stat, parent(), get(), path.data(), &fsStatCallback<Type::STAT>);
UVW_INLINE void fs_req::stat(const std::string &path) {
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) {
auto req = get();
cleanupAndInvokeSync(&uv_fs_stat, parent(), req, path.data());
UVW_INLINE std::pair<bool, file_info> fs_req::stat_sync(const std::string &path) {
auto req = raw();
uv_fs_req_cleanup(this->raw());
uv_fs_stat(parent().raw(), req, path.data(), nullptr);
return std::make_pair(!(req->result < 0), req->statbuf);
}
UVW_INLINE void FsReq::lstat(const std::string &path) {
cleanupAndInvoke(&uv_fs_lstat, parent(), get(), path.data(), &fsStatCallback<Type::LSTAT>);
UVW_INLINE void fs_req::lstat(const std::string &path) {
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) {
auto req = get();
cleanupAndInvokeSync(&uv_fs_lstat, parent(), req, path.data());
UVW_INLINE std::pair<bool, file_info> fs_req::lstat_sync(const std::string &path) {
auto req = raw();
uv_fs_req_cleanup(this->raw());
uv_fs_lstat(parent().raw(), req, path.data(), nullptr);
return std::make_pair(!(req->result < 0), req->statbuf);
}
UVW_INLINE void FsReq::statfs(const std::string &path) {
cleanupAndInvoke(&uv_fs_statfs, parent(), get(), path.data(), &fsStatfsCallback);
UVW_INLINE void fs_req::statfs(const std::string &path) {
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) {
auto req = get();
cleanupAndInvokeSync(&uv_fs_statfs, parent(), req, path.data());
UVW_INLINE std::pair<bool, fs_info> fs_req::statfs_sync(const std::string &path) {
auto req = raw();
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));
}
UVW_INLINE void FsReq::rename(const std::string &old, const std::string &path) {
cleanupAndInvoke(&uv_fs_rename, parent(), get(), old.data(), path.data(), &fsGenericCallback<Type::RENAME>);
UVW_INLINE void fs_req::rename(const std::string &old, const std::string &path) {
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) {
auto req = get();
cleanupAndInvokeSync(&uv_fs_rename, parent(), req, old.data(), path.data());
UVW_INLINE bool fs_req::rename_sync(const std::string &old, const std::string &path) {
auto req = raw();
uv_fs_req_cleanup(this->raw());
uv_fs_rename(parent().raw(), req, old.data(), path.data(), nullptr);
return !(req->result < 0);
}
UVW_INLINE void FsReq::copyfile(const std::string &old, const std::string &path, Flags<CopyFile> flags) {
cleanupAndInvoke(&uv_fs_copyfile, parent(), get(), old.data(), path.data(), flags, &fsGenericCallback<Type::COPYFILE>);
UVW_INLINE void fs_req::copyfile(const std::string &old, const std::string &path, copy_file_flags flags) {
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) {
auto req = get();
cleanupAndInvokeSync(&uv_fs_copyfile, parent(), get(), old.data(), path.data(), flags);
UVW_INLINE bool fs_req::copyfile_sync(const std::string &old, const std::string &path, copy_file_flags flags) {
auto req = raw();
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);
}
UVW_INLINE void FsReq::access(const std::string &path, int mode) {
cleanupAndInvoke(&uv_fs_access, parent(), get(), path.data(), mode, &fsGenericCallback<Type::ACCESS>);
UVW_INLINE void fs_req::access(const std::string &path, int mode) {
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) {
auto req = get();
cleanupAndInvokeSync(&uv_fs_access, parent(), req, path.data(), mode);
UVW_INLINE bool fs_req::access_sync(const std::string &path, int mode) {
auto req = raw();
uv_fs_req_cleanup(this->raw());
uv_fs_access(parent().raw(), req, path.data(), mode, nullptr);
return !(req->result < 0);
}
UVW_INLINE void FsReq::chmod(const std::string &path, int mode) {
cleanupAndInvoke(&uv_fs_chmod, parent(), get(), path.data(), mode, &fsGenericCallback<Type::CHMOD>);
UVW_INLINE void fs_req::chmod(const std::string &path, int mode) {
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) {
auto req = get();
cleanupAndInvokeSync(&uv_fs_chmod, parent(), req, path.data(), mode);
UVW_INLINE bool fs_req::chmod_sync(const std::string &path, int mode) {
auto req = raw();
uv_fs_req_cleanup(this->raw());
uv_fs_chmod(parent().raw(), req, path.data(), mode, nullptr);
return !(req->result < 0);
}
UVW_INLINE void FsReq::utime(const std::string &path, FsRequest::Time atime, FsRequest::Time mtime) {
cleanupAndInvoke(&uv_fs_utime, parent(), get(), path.data(), atime.count(), mtime.count(), &fsGenericCallback<Type::UTIME>);
UVW_INLINE void fs_req::utime(const std::string &path, fs_request::time atime, fs_request::time mtime) {
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) {
auto req = get();
cleanupAndInvokeSync(&uv_fs_utime, parent(), req, path.data(), atime.count(), mtime.count());
UVW_INLINE bool fs_req::utime_sync(const std::string &path, fs_request::time atime, fs_request::time mtime) {
auto req = raw();
uv_fs_req_cleanup(this->raw());
uv_fs_utime(parent().raw(), req, path.data(), atime.count(), mtime.count(), nullptr);
return !(req->result < 0);
}
UVW_INLINE void FsReq::link(const std::string &old, const std::string &path) {
cleanupAndInvoke(&uv_fs_link, parent(), get(), old.data(), path.data(), &fsGenericCallback<Type::LINK>);
UVW_INLINE void fs_req::link(const std::string &old, const std::string &path) {
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) {
auto req = get();
cleanupAndInvokeSync(&uv_fs_link, parent(), req, old.data(), path.data());
UVW_INLINE bool fs_req::link_sync(const std::string &old, const std::string &path) {
auto req = raw();
uv_fs_req_cleanup(this->raw());
uv_fs_link(parent().raw(), req, old.data(), path.data(), nullptr);
return !(req->result < 0);
}
UVW_INLINE void FsReq::symlink(const std::string &old, const std::string &path, Flags<SymLink> flags) {
cleanupAndInvoke(&uv_fs_symlink, parent(), get(), old.data(), path.data(), flags, &fsGenericCallback<Type::SYMLINK>);
UVW_INLINE void fs_req::symlink(const std::string &old, const std::string &path, symlink_flags flags) {
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) {
auto req = get();
cleanupAndInvokeSync(&uv_fs_symlink, parent(), req, old.data(), path.data(), flags);
UVW_INLINE bool fs_req::symlink_sync(const std::string &old, const std::string &path, symlink_flags flags) {
auto req = raw();
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);
}
UVW_INLINE void FsReq::readlink(const std::string &path) {
cleanupAndInvoke(&uv_fs_readlink, parent(), get(), path.data(), &fsReadlinkCallback);
UVW_INLINE void fs_req::readlink(const std::string &path) {
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) {
auto req = get();
cleanupAndInvokeSync(&uv_fs_readlink, parent(), req, path.data());
UVW_INLINE std::pair<bool, std::pair<const char *, std::size_t>> fs_req::readlink_sync(const std::string &path) {
auto req = raw();
uv_fs_req_cleanup(this->raw());
uv_fs_readlink(parent().raw(), req, path.data(), nullptr);
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)));
}
UVW_INLINE void FsReq::realpath(const std::string &path) {
cleanupAndInvoke(&uv_fs_realpath, parent(), get(), path.data(), &fsGenericCallback<Type::REALPATH>);
UVW_INLINE void fs_req::realpath(const std::string &path) {
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) {
auto req = get();
cleanupAndInvokeSync(&uv_fs_realpath, parent(), req, path.data());
UVW_INLINE std::pair<bool, const char *> fs_req::realpath_sync(const std::string &path) {
auto req = raw();
uv_fs_req_cleanup(this->raw());
uv_fs_realpath(parent().raw(), req, path.data(), nullptr);
return std::make_pair(!(req->result < 0), req->path);
}
UVW_INLINE void FsReq::chown(const std::string &path, Uid uid, Gid gid) {
cleanupAndInvoke(&uv_fs_chown, parent(), get(), path.data(), uid, gid, &fsGenericCallback<Type::CHOWN>);
UVW_INLINE void fs_req::chown(const std::string &path, uid_type uid, gid_type gid) {
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) {
auto req = get();
cleanupAndInvokeSync(&uv_fs_chown, parent(), req, path.data(), uid, gid);
UVW_INLINE bool fs_req::chown_sync(const std::string &path, uid_type uid, gid_type gid) {
auto req = raw();
uv_fs_req_cleanup(this->raw());
uv_fs_chown(parent().raw(), req, path.data(), uid, gid, nullptr);
return !(req->result < 0);
}
UVW_INLINE void FsReq::lchown(const std::string &path, Uid uid, Gid gid) {
cleanupAndInvoke(&uv_fs_lchown, parent(), get(), path.data(), uid, gid, &fsGenericCallback<Type::LCHOWN>);
UVW_INLINE void fs_req::lchown(const std::string &path, uid_type uid, gid_type gid) {
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) {
auto req = get();
cleanupAndInvokeSync(&uv_fs_lchown, parent(), req, path.data(), uid, gid);
UVW_INLINE bool fs_req::lchown_sync(const std::string &path, uid_type uid, gid_type gid) {
auto req = raw();
uv_fs_req_cleanup(this->raw());
uv_fs_lchown(parent().raw(), req, path.data(), uid, gid, nullptr);
return !(req->result < 0);
}
UVW_INLINE void FsReq::opendir(const std::string &path) {
cleanupAndInvoke(&uv_fs_opendir, parent(), get(), path.data(), &fsGenericCallback<Type::OPENDIR>);
UVW_INLINE void fs_req::opendir(const std::string &path) {
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) {
auto req = get();
cleanupAndInvokeSync(&uv_fs_opendir, parent(), req, path.data());
UVW_INLINE bool fs_req::opendir_sync(const std::string &path) {
auto req = raw();
uv_fs_req_cleanup(this->raw());
uv_fs_opendir(parent().raw(), req, path.data(), nullptr);
return !(req->result < 0);
}
UVW_INLINE void FsReq::closedir() {
auto req = get();
UVW_INLINE void fs_req::closedir() {
auto req = raw();
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() {
auto req = get();
UVW_INLINE bool fs_req::closedir_sync() {
auto req = raw();
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);
}
UVW_INLINE void FsReq::readdir() {
auto req = get();
UVW_INLINE void fs_req::readdir() {
auto req = raw();
auto *dir = static_cast<uv_dir_t *>(req->ptr);
dir->dirents = dirents;
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() {
auto req = get();
UVW_INLINE std::pair<bool, std::pair<fs_req::entry_type, const char *>> fs_req::readdir_sync() {
auto req = raw();
auto *dir = static_cast<uv_dir_t *>(req->ptr);
dir->dirents = dirents;
dir->nentries = 1;
cleanupAndInvokeSync(&uv_fs_readdir, parent(), req, dir);
return {req->result != 0, {static_cast<EntryType>(dirents[0].type), dirents[0].name}};
uv_fs_req_cleanup(this->raw());
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);
}
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);
}

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -4,6 +4,8 @@
#include <string>
#include <type_traits>
#include <uv.h>
#include "config.h"
#include "enum.hpp"
#include "handle.hpp"
#include "loop.h"
#include "util.h"
@ -12,26 +14,23 @@ namespace uvw {
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,
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,
CHANGE = UV_CHANGE
};
} // namespace details
/**
* @brief FsEventEvent event.
*
* It will be emitted by FsEventHandle according with its functionalities.
*/
struct FsEventEvent {
FsEventEvent(const char *pathname, Flags<details::UVFsEvent> events);
/*! @brief Fs event event. */
struct fs_event_event {
fs_event_event(const char *pathname, details::uvw_fs_event events);
/**
* @brief The path to the file being monitored.
@ -46,82 +45,64 @@ struct FsEventEvent {
*
* Available flags are:
*
* * `FsEventHandle::Watch::RENAME`
* * `FsEventHandle::Watch::CHANGE`
* * `fs_event_handle::watch::RENAME`
* * `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
* 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.
*
* 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
* [documentation](http://docs.libuv.org/en/v1.x/fs_event.html)
* for further details.
*/
class FsEventHandle final: public Handle<FsEventHandle, uv_fs_event_t> {
static void startCallback(uv_fs_event_t *handle, const char *filename, int events, int status);
class fs_event_handle final: public handle<fs_event_handle, uv_fs_event_t, fs_event_event> {
static void start_callback(uv_fs_event_t *hndl, const char *filename, int events, int status);
public:
using Watch = details::UVFsEvent;
using Event = details::UVFsEventFlags;
using watch = details::uvw_fs_event;
using event_flags = details::uvw_fs_event_flags;
using Handle::Handle;
using handle::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.
*
* 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.
* As soon as a change is observed, a fs_event_event is emitted by the
* handle.
*
* Available flags are:
*
* * `FsEventHandle::Event::WATCH_ENTRY`
* * `FsEventHandle::Event::STAT`
* * `FsEventHandle::Event::RECURSIVE`
* * `fs_event_handle::event_flags::WATCH_ENTRY`
* * `fs_event_handle::event_flags::STAT`
* * `fs_event_handle::event_flags::RECURSIVE`
*
* @param path The file or directory to be monitored.
* @param flags Additional flags to control the behavior.
* @return Underlying return value.
*/
void start(const std::string &path, Flags<Event> flags = Flags<Event>{});
/**
* @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);
int start(const std::string &path, event_flags flags = event_flags::_UVW_ENUM);
/**
* @brief Stops polling the file descriptor.
* @return Underlying return value.
*/
void stop();
int stop();
/**
* @brief Gets the path being monitored.

View File

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

View File

@ -4,61 +4,60 @@
#include <chrono>
#include <string>
#include <uv.h>
#include "config.h"
#include "handle.hpp"
#include "loop.h"
#include "util.h"
namespace uvw {
/**
* @brief FsPollEvent event.
*
* It will be emitted by FsPollHandle according with its functionalities.
*/
struct FsPollEvent {
explicit FsPollEvent(Stat previous, Stat current) noexcept;
/*! @brief Fs pos event. */
struct fs_poll_event {
explicit fs_poll_event(file_info previous, file_info current) noexcept;
Stat prev; /*!< The old Stat struct. */
Stat curr; /*!< The new Stat struct. */
file_info prev; /*!< The old file_info 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
* handles, FsPollHandle handles use stat to detect when a file has changed so
* they can work on file systems where FsEventHandle handles cant.
* It allows users to monitor a given path for changes. Unlike fs_event_handle,
* fs_poll_handle uses stat to detect when a file has changed so it can work on
* 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> {
static void startCallback(uv_fs_poll_t *handle, int status, const uv_stat_t *prev, const uv_stat_t *curr);
class fs_poll_handle final: public handle<fs_poll_handle, uv_fs_poll_t, fs_poll_event> {
static void start_callback(uv_fs_poll_t *hndl, int status, const uv_stat_t *prev, const uv_stat_t *curr);
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.
* @return True in case of success, false otherwise.
* @return Underlying return value.
*/
bool init();
int init() final;
/**
* @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 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.
* @return Underlying return value.
*/
void stop();
int stop();
/**
* @brief Gets the path being monitored by the handle.

View File

@ -5,59 +5,40 @@
#include <memory>
#include <utility>
#include <uv.h>
#include "config.h"
#include "resource.hpp"
#include "util.h"
namespace uvw {
/**
* @brief CloseEvent event.
*
* It will be emitted by the handles according with their functionalities.
*/
struct CloseEvent {};
/*! @brief Close event. */
struct close_event {};
/**
* @brief Handle base class.
*
* Base type for all `uvw` handle types.
*/
template<typename T, typename U>
class Handle: public Resource<T, U> {
template<typename T, typename U, typename... E>
class handle: public resource<T, U, close_event, E...> {
protected:
static void closeCallback(uv_handle_t *handle) {
Handle<T, U> &ref = *(static_cast<T *>(handle->data));
static void close_callback(uv_handle_t *hndl) {
handle<T, U, E...> &ref = *(static_cast<T *>(hndl->data));
[[maybe_unused]] auto ptr = ref.shared_from_this();
ref.reset();
ref.publish(CloseEvent{});
ref.self_reset();
ref.publish(close_event{});
}
static void allocCallback(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);
uv_handle_t *as_uv_handle() {
return reinterpret_cast<uv_handle_t *>(this->raw());
}
template<typename F, typename... Args>
bool initialize(F &&f, Args &&...args) {
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}); }
const uv_handle_t *as_uv_handle() const {
return reinterpret_cast<const uv_handle_t *>(this->raw());
}
public:
using Resource<T, U>::Resource;
using resource<T, U, close_event, E...>::resource;
/**
* @brief Gets the category of the handle.
@ -68,8 +49,8 @@ public:
*
* @return The actual category of the handle.
*/
HandleCategory category() const noexcept {
return HandleCategory{this->template get<uv_handle_t>()->type};
handle_category category() const noexcept {
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
* 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.
*/
HandleType type() const noexcept {
return Utilities::guessHandle(category());
handle_type type() const noexcept {
return utilities::guess_handle(category());
}
/**
@ -90,22 +71,22 @@ public:
*
* 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().
* * A PipeHandle, TCPHandle, UDPHandle, etc. handle - basically any handle
* that deals with I/O - is active when it is doing something that involves
* I/O, like reading, writing, connecting, accepting new connections, etc.
* * A CheckHandle, IdleHandle, TimerHandle, etc. handle is active when it
* has been started with a call to `start()`.
* * A pipe, tcp, udp, etc. handle - basically any handle that deals with
* I/O - is active when it is doing something that involves I/O, like
* reading, writing, connecting, accepting new connections, etc.
* * A check, idle, timer, etc. handle is active when it has been started
* 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,
* `stop()` deactivates the handle again.
*
* @return True if the handle is active, false otherwise.
*/
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.
*/
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.
*
* This **must** be called on each handle before memory is released.<br/>
* In-progress requests are cancelled and this can result in an ErrorEvent
* emitted.
* In-progress requests are cancelled and this can result in errors.
*
* The handle will emit a CloseEvent when finished.
* The handle will emit a close event when finished.
*/
void close() noexcept {
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.
*/
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.
*/
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.
*/
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.
*/
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
* socket.<br/>
* This function works for TCPHandle, PipeHandle and UDPHandle handles on
* Unix and for TCPHandle and UDPHandle handles on Windows.<br/>
* This function works for tcp, pipeand udp handles on Unix and for tcp and
* udp handles on Windows.<br/>
* 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;
auto err = uv_send_buffer_size(this->template get<uv_handle_t>(), &value);
return err ? 0 : value;
auto err = uv_send_buffer_size(as_uv_handle(), &value);
return err ? err : value;
}
/**
@ -193,14 +174,14 @@ public:
*
* Sets the size of the send buffer that the operating system uses for the
* socket.<br/>
* This function works for TCPHandle, PipeHandle and UDPHandle handles on
* Unix and for TCPHandle and UDPHandle handles on Windows.<br/>
* This function works for tcp, pipe and udp handles on Unix and for tcp and
* udp handles on Windows.<br/>
* Note that Linux will set double the size.
*
* @return True in case of success, false otherwise.
* @return Underlying return value.
*/
bool sendBufferSize(int value) {
return (0 == uv_send_buffer_size(this->template get<uv_handle_t>(), &value));
int send_buffer_size(int 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
* the socket.<br/>
* This function works for TCPHandle, PipeHandle and UDPHandle handles on
* Unix and for TCPHandle and UDPHandle handles on Windows.<br/>
* This function works for tcp, pipe and udp handles on Unix and for tcp and
* udp handles on Windows.<br/>
* 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;
auto err = uv_recv_buffer_size(this->template get<uv_handle_t>(), &value);
return err ? 0 : value;
auto err = uv_recv_buffer_size(as_uv_handle(), &value);
return err ? err : value;
}
/**
@ -225,14 +207,14 @@ public:
*
* Sets the size of the receive buffer that the operating system uses for
* the socket.<br/>
* This function works for TCPHandle, PipeHandle and UDPHandle handles on
* Unix and for TCPHandle and UDPHandle handles on Windows.<br/>
* This function works for tcp, pipe and udp handles on Unix and for tcp and
* udp handles on Windows.<br/>
* Note that Linux will set double the size.
*
* @return True in case of success, false otherwise.
* @return Underlying return value.
*/
bool recvBufferSize(int value) {
return (0 == uv_recv_buffer_size(this->template get<uv_handle_t>(), &value));
int recv_buffer_size(int value) {
return uv_recv_buffer_size(as_uv_handle(), &value);
}
/**
@ -240,15 +222,14 @@ public:
*
* Supported handles:
*
* * TCPHandle
* * PipeHandle
* * TTYHandle
* * UDPHandle
* * PollHandle
* * tcp_handle
* * pipe_handle
* * tty_handle
* * udp_handle
* * poll_handle
*
* It will emit an ErrorEvent event if invoked on any other handle.<br/>
* If a handle doesnt have an attached file descriptor yet or the handle
* itself has been closed, an ErrorEvent event will be emitted.
* If invoked on a different handle, one that doesnt have an attached file
* descriptor yet or one which was closed, an invalid value is returned.
*
* See the official
* [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
* case of errors.
*/
OSFileDescriptor fd() const {
os_file_descriptor fd() const {
uv_os_fd_t fd;
uv_fileno(this->template get<uv_handle_t>(), &fd);
uv_fileno(as_uv_handle(), &fd);
return fd;
}
};

View File

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

View File

@ -7,18 +7,14 @@
namespace uvw {
/**
* @brief IdleEvent event.
*
* It will be emitted by IdleHandle according with its functionalities.
*/
struct IdleEvent {};
/*! @brief Idle event. */
struct idle_event {};
/**
* @brief The IdleHandle handle.
* @brief The idle handle.
*
* Idle handles will emit a IdleEvent event once per loop iteration, right
* before the PrepareHandle handles.
* Idle handles will emit a idle event once per loop iteration, right before the
* prepare handles.
*
* 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
@ -28,32 +24,36 @@ struct IdleEvent {};
* Despite the name, idle handles will emit events on every loop iteration, not
* 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> {
static void startCallback(uv_idle_t *handle);
class idle_handle final: public handle<idle_handle, uv_idle_t, idle_event> {
static void start_callback(uv_idle_t *hndl);
public:
using Handle::Handle;
using handle::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.
*
* A IdleEvent event will be emitted once per loop iteration, right before
* polling the PrepareHandle handles.
* An idle event will be emitted once per loop iteration, right before
* polling the prepare handles.
*
* @return Underlying return value.
*/
void start();
int start();
/**
* @brief Stops the handle.
*
* @return Underlying return value.
*/
void stop();
int stop();
};
} // namespace uvw

View File

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

View File

@ -5,22 +5,23 @@
#include <string>
#include <type_traits>
#include <uv.h>
#include "config.h"
#include "loop.h"
#include "underlying_type.hpp"
#include "uv_type.hpp"
namespace uvw {
/**
* @brief The SharedLib class.
* @brief The shared lib class.
*
* `uvw` provides cross platform utilities for loading shared libraries and
* 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:
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.
@ -41,7 +42,7 @@ public:
F *sym(const std::string &name) {
static_assert(std::is_function_v<F>);
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; }
return func;
}

View File

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

View File

@ -11,34 +11,35 @@
#include <type_traits>
#include <utility>
#include <uv.h>
#include "config.h"
#include "emitter.h"
#include "util.h"
namespace uvw {
class AsyncHandle;
class CheckHandle;
class FsEventHandle;
class FsPollHandle;
class IdleHandle;
class PipeHandle;
class PollHandle;
class PrepareHandle;
class ProcessHandle;
class SignalHandle;
class TCPHandle;
class TimerHandle;
class TTYHandle;
class UDPHandle;
class async_handle;
class check_handle;
class fs_event_handle;
class fs_poll_handle;
class idle_handle;
class pipe_handle;
class poll_handle;
class prepare_handle;
class process_handle;
class signal_handle;
class tcp_handle;
class timer_handle;
class tty_handle;
class udp_handle;
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,
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,
ONCE = UV_RUN_ONCE,
NOWAIT = UV_RUN_NOWAIT
@ -47,55 +48,49 @@ enum class UVRunMode : std::underlying_type_t<uv_run_mode> {
} // namespace details
/**
* @brief The Loop class.
* @brief The loop class.
*
* The event loop is the central part of `uvw`'s functionalities, as well as
* `libuv`'s ones.<br/>
* It takes care of polling for I/O and scheduling callbacks to be run based on
* different sources of events.
*/
class Loop final: public Emitter<Loop>, public std::enable_shared_from_this<Loop> {
using Deleter = void (*)(uv_loop_t *);
class loop final: public emitter<loop>, public std::enable_shared_from_this<loop> {
using deleter = void (*)(uv_loop_t *);
template<typename, typename>
friend class Resource;
template<typename, typename, typename...>
friend class resource;
template<typename R, typename... Args>
auto create_resource(int, Args &&...args) -> decltype(std::declval<R>().init(), std::shared_ptr<R>{}) {
auto ptr = R::create(shared_from_this(), std::forward<Args>(args)...);
ptr = ptr->init() ? ptr : nullptr;
return ptr;
}
class uv_token {
friend class loop;
explicit uv_token(int) {}
};
template<typename R, typename... Args>
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;
loop(std::unique_ptr<uv_loop_t, deleter> ptr) noexcept;
public:
using Time = std::chrono::duration<uint64_t, std::milli>;
using Configure = details::UVLoopOption;
using Mode = details::UVRunMode;
using token = uv_token;
using time = std::chrono::duration<uint64_t, std::milli>;
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.
*/
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
* it's associated. Management of the memory associated with the resource is
* 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.
*/
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.
@ -109,15 +104,15 @@ public:
*
* @return The initialized default loop.
*/
static std::shared_ptr<Loop> getDefault();
static std::shared_ptr<loop> get_default();
Loop(const Loop &) = delete;
Loop(Loop &&other) = delete;
loop(const loop &) = delete;
loop(loop &&other) = delete;
Loop &operator=(const Loop &) = delete;
Loop &operator=(Loop &&other) = delete;
loop &operator=(const loop &) = delete;
loop &operator=(loop &&other) = delete;
~Loop() noexcept;
~loop() noexcept;
/**
* @brief Sets additional loop options.
@ -126,23 +121,21 @@ public:
* mentioned otherwise.<br/>
* 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.
* * `Loop::Configure::IDLE_TIME`: Accumulate the amount of idle time the
* event loop spends in the event provider. This option is necessary to use
* `idleTime()`.
*
* An ErrorEvent will be emitted in case of errors.
* * `loop::option::IDLE_TIME`: Accumulate the amount of idle time the event
* loop spends in the event provider. This option is necessary to use
* `idle_time()`.
*
* See the official
* [documentation](http://docs.libuv.org/en/v1.x/loop.html#c.uv_loop_configure)
* for further details.
*
* @return Underlying return value.
*/
template<typename... Args>
void configure(Configure flag, Args &&...args) {
auto option = static_cast<std::underlying_type_t<Configure>>(flag);
auto err = uv_loop_configure(loop.get(), static_cast<uv_loop_option>(option), std::forward<Args>(args)...);
if(err) { publish(ErrorEvent{err}); }
int configure(option flag, Args &&...args) {
return uv_loop_configure(uv_loop.get(), static_cast<uv_loop_option>(flag), std::forward<Args>(args)...);
}
/**
@ -151,45 +144,55 @@ public:
* This should be used as a default method to create resources.<br/>
* 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.
*/
template<typename R, typename... 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.
*
* 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.
*
* 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.
* * `Loop::Mode::ONCE`: Poll for i/o once. Note that this function blocks
* if there are no pending callbacks.
* * `Loop::Mode::NOWAIT`: Poll for i/o once but dont block if there are no
* pending callbacks.
* * `loop::run_mode::ONCE`: Poll for i/o once. Note that this function
* blocks if there are no pending callbacks.
* * `loop::run_mode::NOWAIT`: Poll for i/o once but dont block if there
* are no pending callbacks.
*
* See the official
* [documentation](http://docs.libuv.org/en/v1.x/loop.html#c.uv_run)
* for further details.
*
* @return True when done, false in all other cases.
* @return Underlying return value.
*/
template<Mode mode = Mode::DEFAULT>
bool run() noexcept;
int run(run_mode mode = run_mode::DEFAULT) noexcept;
/**
* @brief Checks if there are active resources.
@ -211,8 +214,8 @@ public:
* @brief Get backend file descriptor.
*
* Only kqueue, epoll and event ports are supported.<br/>
* This can be used in conjunction with `run<Loop::Mode::NOWAIT>()` to poll
* in one thread and run the event loops callbacks in another.
* This can be used in conjunction with `run(loop::run_mode::NOWAIT)` to
* poll in one thread and run the event loops callbacks in another.
*
* @return The backend file descriptor.
*/
@ -224,14 +227,14 @@ public:
* * A boolean value that is true in case of valid timeout, false otherwise.
* * 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
* is thread safe.
* @return The accumulated time spent idle.
*/
Time idleTime() const noexcept;
time idle_time() const noexcept;
/**
* @brief Returns the current timestamp in milliseconds.
@ -245,7 +248,7 @@ public:
* @return The current timestamp in milliseconds (actual type is
* `std::chrono::duration<uint64_t, std::milli>`).
*/
Time now() const noexcept;
time now() const noexcept;
/**
* @brief Updates the event loops concept of _now_.
@ -261,58 +264,58 @@ public:
/**
* @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>
void walk(Func callback) {
auto func = [](uv_handle_t *handle, void *func) {
if(handle->data) {
auto func = [](uv_handle_t *hndl, void *func) {
if(hndl->data) {
auto &cb = *static_cast<Func *>(func);
switch(Utilities::guessHandle(HandleCategory{handle->type})) {
case HandleType::ASYNC:
cb(*static_cast<AsyncHandle *>(handle->data));
switch(utilities::guess_handle(handle_category{hndl->type})) {
case handle_type::ASYNC:
cb(*static_cast<async_handle *>(hndl->data));
break;
case HandleType::CHECK:
cb(*static_cast<CheckHandle *>(handle->data));
case handle_type::CHECK:
cb(*static_cast<check_handle *>(hndl->data));
break;
case HandleType::FS_EVENT:
cb(*static_cast<FsEventHandle *>(handle->data));
case handle_type::FS_EVENT:
cb(*static_cast<fs_event_handle *>(hndl->data));
break;
case HandleType::FS_POLL:
cb(*static_cast<FsPollHandle *>(handle->data));
case handle_type::FS_POLL:
cb(*static_cast<fs_poll_handle *>(hndl->data));
break;
case HandleType::IDLE:
cb(*static_cast<IdleHandle *>(handle->data));
case handle_type::IDLE:
cb(*static_cast<idle_handle *>(hndl->data));
break;
case HandleType::PIPE:
cb(*static_cast<PipeHandle *>(handle->data));
case handle_type::PIPE:
cb(*static_cast<pipe_handle *>(hndl->data));
break;
case HandleType::POLL:
cb(*static_cast<PollHandle *>(handle->data));
case handle_type::POLL:
cb(*static_cast<poll_handle *>(hndl->data));
break;
case HandleType::PREPARE:
cb(*static_cast<PrepareHandle *>(handle->data));
case handle_type::PREPARE:
cb(*static_cast<prepare_handle *>(hndl->data));
break;
case HandleType::PROCESS:
cb(*static_cast<ProcessHandle *>(handle->data));
case handle_type::PROCESS:
cb(*static_cast<process_handle *>(hndl->data));
break;
case HandleType::SIGNAL:
cb(*static_cast<SignalHandle *>(handle->data));
case handle_type::SIGNAL:
cb(*static_cast<signal_handle *>(hndl->data));
break;
case HandleType::TCP:
cb(*static_cast<TCPHandle *>(handle->data));
case handle_type::TCP:
cb(*static_cast<tcp_handle *>(hndl->data));
break;
case HandleType::TIMER:
cb(*static_cast<TimerHandle *>(handle->data));
case handle_type::TIMER:
cb(*static_cast<timer_handle *>(hndl->data));
break;
case HandleType::TTY:
cb(*static_cast<TTYHandle *>(handle->data));
case handle_type::TTY:
cb(*static_cast<tty_handle *>(hndl->data));
break;
case HandleType::UDP:
cb(*static_cast<UDPHandle *>(handle->data));
case handle_type::UDP:
cb(*static_cast<udp_handle *>(hndl->data));
break;
default:
// 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
* guaranteed.
*
* An ErrorEvent will be emitted in case of errors.
*
* See the official
* [documentation](http://docs.libuv.org/en/v1.x/loop.html#c.uv_loop_fork)
* 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.
@ -362,14 +365,14 @@ public:
*/
template<typename R = void>
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.
* @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.
@ -406,17 +409,10 @@ public:
uv_loop_t *raw() noexcept;
private:
std::unique_ptr<uv_loop_t, Deleter> loop;
std::shared_ptr<void> userData{nullptr};
std::unique_ptr<uv_loop_t, deleter> uv_loop;
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
#ifndef UVW_AS_LIB

View File

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

View File

@ -5,6 +5,8 @@
#include <string>
#include <type_traits>
#include <uv.h>
#include "config.h"
#include "enum.hpp"
#include "loop.h"
#include "request.hpp"
#include "stream.h"
@ -14,68 +16,69 @@ namespace uvw {
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,
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
* 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
* 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:
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.
* @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.
*
* The passed file descriptor or HANDLE is not checked for its type, but
* its required that it represents a valid pipe.<br/>
* An ErrorEvent event is emitted in case of errors.
* its required that it represents a valid pipe.
*
* @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).
*
* Paths on Unix get truncated typically between 92 and 108 bytes.<br/>
* An ErrorEvent event is emitted in case of errors.
* Paths on Unix get truncated typically between 92 and 108 bytes.
*
* @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.
*
* Paths on Unix get truncated typically between 92 and 108 bytes.<br/>
* A ConnectEvent event is emitted when the connection has been
* established.<br/>
* An ErrorEvent event is emitted in case of errors during the connection.
* A connect event is emitted when the connection has been
* established.
*
* @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.
@ -120,12 +123,12 @@ public:
*
* @return The type of the pending handle. Possible values are:
*
* * `HandleType::PIPE`
* * `HandleType::TCP`
* * `HandleType::UDP`
* * `HandleType::UNKNOWN`
* * `handle_type::PIPE`
* * `handle_type::TCP`
* * `handle_type::UDP`
* * `handle_type::UNKNOWN`
*/
HandleType receive() noexcept;
handle_type receive() noexcept;
/**
* @brief Alters pipe permissions.
@ -134,17 +137,17 @@ public:
*
* Available flags are:
*
* * `PipeHandle::Chmod::READABLE`
* * `PipeHandle::Chmod::WRITABLE`
* * `pipe_handle::chmod_flags::READABLE`
* * `pipe_handle::chmod_flags::WRITABLE`
*
* See the official
* [documentation](http://docs.libuv.org/en/v1.x/pipe.html#c.uv_pipe_chmod)
* for further details.
*
* @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:
bool ipc;

View File

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

View File

@ -4,6 +4,8 @@
#include <memory>
#include <type_traits>
#include <uv.h>
#include "config.h"
#include "enum.hpp"
#include "handle.hpp"
#include "util.h"
@ -11,113 +13,90 @@ namespace uvw {
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,
WRITABLE = UV_WRITABLE,
DISCONNECT = UV_DISCONNECT,
PRIORITIZED = UV_PRIORITIZED
PRIORITIZED = UV_PRIORITIZED,
_UVW_ENUM = 0
};
}
/**
* @brief PollEvent event.
*
* It will be emitted by PollHandle according with its functionalities.
*/
struct PollEvent {
explicit PollEvent(Flags<details::UVPollEvent> events) noexcept;
/*! @brief Poll event. */
struct poll_event {
explicit poll_event(details::uvw_poll_event events) noexcept;
/**
* @brief Detected events all in one.
*
* Available flags are:
*
* * `PollHandle::Event::READABLE`
* * `PollHandle::Event::WRITABLE`
* * `PollHandle::Event::DISCONNECT`
* * `PollHandle::Event::PRIORITIZED`
* * `poll_handle::event::READABLE`
* * `poll_handle::event::WRITABLE`
* * `poll_handle::event::DISCONNECT`
* * `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
* 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:
* * either an `int` file descriptor
* * or a `OSSocketHandle` socket descriptor
* * or a `os_socket_handle` socket descriptor
*
* See the official
* [documentation](http://docs.libuv.org/en/v1.x/poll.html)
* for further details.
*/
class PollHandle final: public Handle<PollHandle, uv_poll_t> {
static void startCallback(uv_poll_t *handle, int status, int events);
class poll_handle final: public handle<poll_handle, uv_poll_t, details::uvw_poll_event> {
static void start_callback(uv_poll_t *hndl, int status, int events);
public:
using Event = details::UVPollEvent;
using poll_event = details::uvw_poll_event;
explicit PollHandle(ConstructorAccess ca, 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, int desc);
explicit poll_handle(loop::token token, std::shared_ptr<loop> ref, os_socket_handle sock);
/**
* @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.
*
* Available flags are:
*
* * `PollHandle::Event::READABLE`
* * `PollHandle::Event::WRITABLE`
* * `PollHandle::Event::DISCONNECT`
* * `PollHandle::Event::PRIORITIZED`
* * `poll_handle::event::READABLE`
* * `poll_handle::event::WRITABLE`
* * `poll_handle::event::DISCONNECT`
* * `poll_handle::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.
* As soon as an event is detected, a poll event is emitted by the
* handle.
*
* Calling more than once this method will update the flags 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);
/**
* @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);
int start(poll_event flags);
/**
* @brief Stops polling the file descriptor.
* @return Underlying return value.
*/
void stop();
int stop();
private:
enum {
@ -127,7 +106,7 @@ private:
union {
int file_desc;
OSSocketHandle::Type socket;
os_socket_handle socket;
};
};

View File

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

View File

@ -7,47 +7,46 @@
namespace uvw {
/**
* @brief PrepareEvent event.
*
* It will be emitted by PrepareHandle according with its functionalities.
*/
struct PrepareEvent {};
/*! @brief Prepare event. */
struct prepare_event {};
/**
* @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.
*
* 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> {
static void startCallback(uv_prepare_t *handle);
class prepare_handle final: public handle<prepare_handle, uv_prepare_t, prepare_event> {
static void start_callback(uv_prepare_t *hndl);
public:
using Handle::Handle;
using handle::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.
*
* A PrepareEvent event will be emitted once per loop iteration, right
* before polling for I/O.
* A prepare event will be emitted once per loop iteration, right before
* 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.
* @return Underlying return value.
*/
void stop();
int stop();
};
} // namespace uvw

View File

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

View File

@ -6,6 +6,8 @@
#include <utility>
#include <vector>
#include <uv.h>
#include "config.h"
#include "enum.hpp"
#include "handle.hpp"
#include "loop.h"
#include "stream.h"
@ -15,54 +17,52 @@ namespace uvw {
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,
SETGID = UV_PROCESS_SETGID,
WINDOWS_VERBATIM_ARGUMENTS = UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS,
DETACHED = UV_PROCESS_DETACHED,
WINDOWS_HIDE = UV_PROCESS_WINDOWS_HIDE,
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,
CREATE_PIPE = UV_CREATE_PIPE,
INHERIT_FD = UV_INHERIT_FD,
INHERIT_STREAM = UV_INHERIT_STREAM,
READABLE_PIPE = UV_READABLE_PIPE,
WRITABLE_PIPE = UV_WRITABLE_PIPE,
OVERLAPPED_PIPE = UV_OVERLAPPED_PIPE
OVERLAPPED_PIPE = UV_OVERLAPPED_PIPE,
_UVW_ENUM = 0
};
} // namespace details
/**
* @brief ExitEvent event.
*
* It will be emitted by ProcessHandle according with its functionalities.
*/
struct ExitEvent {
explicit ExitEvent(int64_t code, int sig) noexcept;
/*! @brief Exit event. */
struct exit_event {
explicit exit_event(int64_t code, int sig) noexcept;
int64_t status; /*!< The exit status. */
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
* establish communication channels with it using streams.
*/
class ProcessHandle final: public Handle<ProcessHandle, uv_process_t> {
static void exitCallback(uv_process_t *handle, int64_t exitStatus, int termSignal);
class process_handle final: public handle<process_handle, uv_process_t, exit_event> {
static void exit_callback(uv_process_t *hndl, int64_t exit_status, int term_signal);
public:
using Process = details::UVProcessFlags;
using StdIO = details::UVStdIOFlags;
using process_flags = details::uvw_process_flags;
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.
@ -78,7 +78,7 @@ public:
* [documentation](http://docs.libuv.org/en/v1.x/process.html#c.uv_disable_stdio_inheritance)
* for further details.
*/
static void disableStdIOInheritance() noexcept;
static void disable_stdio_inheritance() noexcept;
/**
* @brief kill Sends the specified signal to the given PID.
@ -90,16 +90,13 @@ public:
/**
* @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.
*
* If the process isn't successfully spawned, an ErrorEvent event will be
* emitted by the handle.
*
* See the official
* [documentation](http://docs.libuv.org/en/v1.x/process.html)
* for further details.
@ -107,14 +104,16 @@ public:
* @param file Path pointing to the program to be executed.
* @param args Command line arguments.
* @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.
* @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.
@ -130,20 +129,20 @@ public:
* @param path The working directory to be used when `spawn()` is invoked.
* @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.
*
* Available flags are:
*
* * `ProcessHandle::Process::SETUID`
* * `ProcessHandle::Process::SETGID`
* * `ProcessHandle::Process::WINDOWS_VERBATIM_ARGUMENTS`
* * `ProcessHandle::Process::DETACHED`
* * `ProcessHandle::Process::WINDOWS_HIDE`
* * `ProcessHandle::Process::WINDOWS_HIDE_CONSOLE`
* * `ProcessHandle::Process::WINDOWS_HIDE_GUI`
* * `process_handle::process_flags::SETUID`
* * `process_handle::process_flags::SETGID`
* * `process_handle::process_flags::WINDOWS_VERBATIM_ARGUMENTS`
* * `process_handle::process_flags::DETACHED`
* * `process_handle::process_flags::WINDOWS_HIDE`
* * `process_handle::process_flags::WINDOWS_HIDE_CONSOLE`
* * `process_handle::process_flags::WINDOWS_HIDE_GUI`
*
* See the official
* [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.
* @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.
*
* Available flags are:
*
* * `ProcessHandle::StdIO::IGNORE_STREAM`
* * `ProcessHandle::StdIO::CREATE_PIPE`
* * `ProcessHandle::StdIO::INHERIT_FD`
* * `ProcessHandle::StdIO::INHERIT_STREAM`
* * `ProcessHandle::StdIO::READABLE_PIPE`
* * `ProcessHandle::StdIO::WRITABLE_PIPE`
* * `ProcessHandle::StdIO::OVERLAPPED_PIPE`
* * `process_handle::stdio_flags::IGNORE_STREAM`
* * `process_handle::stdio_flags::CREATE_PIPE`
* * `process_handle::stdio_flags::INHERIT_FD`
* * `process_handle::stdio_flags::INHERIT_STREAM`
* * `process_handle::stdio_flags::READABLE_PIPE`
* * `process_handle::stdio_flags::WRITABLE_PIPE`
* * `process_handle::stdio_flags::OVERLAPPED_PIPE`
*
* See the official
* [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.
* @return A reference to this process handle.
*/
template<typename T, typename U>
ProcessHandle &stdio(StreamHandle<T, U> &stream, Flags<StdIO> flags) {
template<typename T, typename U, typename... E>
process_handle &stdio(stream_handle<T, U, E...> &stream, stdio_flags flags) {
uv_stdio_container_t container;
Flags<StdIO>::Type fgs = flags;
container.flags = static_cast<uv_stdio_flags>(fgs);
container.data.stream = get<uv_stream_t>(stream);
poStreamStdio.push_back(std::move(container));
container.flags = static_cast<uv_stdio_flags>(flags);
container.data.stream = reinterpret_cast<uv_stream_t *>(stream.raw());
po_stream_stdio.push_back(std::move(container));
return *this;
}
@ -190,18 +188,18 @@ public:
*
* Available flags are:
*
* * `ProcessHandle::StdIO::IGNORE_STREAM`
* * `ProcessHandle::StdIO::CREATE_PIPE`
* * `ProcessHandle::StdIO::INHERIT_FD`
* * `ProcessHandle::StdIO::INHERIT_STREAM`
* * `ProcessHandle::StdIO::READABLE_PIPE`
* * `ProcessHandle::StdIO::WRITABLE_PIPE`
* * `ProcessHandle::StdIO::OVERLAPPED_PIPE`
* * `process_handle::stdio_flags::IGNORE_STREAM`
* * `process_handle::stdio_flags::CREATE_PIPE`
* * `process_handle::stdio_flags::INHERIT_FD`
* * `process_handle::stdio_flags::INHERIT_STREAM`
* * `process_handle::stdio_flags::READABLE_PIPE`
* * `process_handle::stdio_flags::WRITABLE_PIPE`
* * `process_handle::stdio_flags::OVERLAPPED_PIPE`
*
* Default file descriptors are:
* * `uvw::StdIN` for `stdin`
* * `uvw::StdOUT` for `stdout`
* * `uvw::StdERR` for `stderr`
* * `uvw::std_in` for `stdin`
* * `uvw::std_out` for `stdout`
* * `uvw::std_err` for `stderr`
*
* See the official
* [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.
* @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.
* @param id A valid user id to be used.
* @return A reference to this process handle.
*/
ProcessHandle &uid(Uid id);
process_handle &uid(uid_type id);
/**
* @brief Sets the child process' group id.
* @param id A valid group id to be used.
* @return A reference to this process handle.
*/
ProcessHandle &gid(Gid id);
process_handle &gid(gid_type id);
private:
std::string poCwd;
Flags<Process> poFlags;
std::vector<uv_stdio_container_t> poFdStdio;
std::vector<uv_stdio_container_t> poStreamStdio;
Uid poUid;
Gid poGid;
std::string po_cwd;
process_flags po_flags;
std::vector<uv_stdio_container_t> po_fd_stdio;
std::vector<uv_stdio_container_t> po_stream_stdio;
uid_type po_uid;
gid_type po_gid;
};
} // namespace uvw

View File

@ -5,6 +5,7 @@
#include <type_traits>
#include <utility>
#include <uv.h>
#include "config.h"
#include "resource.hpp"
namespace uvw {
@ -14,56 +15,32 @@ namespace uvw {
*
* Base type for all `uvw` request types.
*/
template<typename T, typename U>
class Request: public Resource<T, U> {
template<typename T, typename U, typename... E>
class request: public resource<T, U, E...> {
protected:
static auto reserve(U *req) {
auto ptr = static_cast<T *>(req->data)->shared_from_this();
ptr->reset();
ptr->self_reset();
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:
using Resource<T, U>::Resource;
using resource<T, U, E...>::resource;
/**
* @brief Cancels a pending request.
*
* This method fails if the request is executing or has finished
* executing.<br/>
* It can emit an ErrorEvent event in case of errors.
* executing.
*
* See the official
* [documentation](http://docs.libuv.org/en/v1.x/request.html#c.uv_cancel)
* for further details.
*
* @return True in case of success, false otherwise.
* @return Underlying return value.
*/
bool cancel() {
return (0 == uv_cancel(this->template get<uv_req_t>()));
int cancel() {
return uv_cancel(reinterpret_cast<uv_req_t *>(this->raw()));
}
/**
@ -71,7 +48,7 @@ public:
* @return The size of the underlying request type.
*/
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 <utility>
#include "config.h"
#include "emitter.h"
#include "underlying_type.hpp"
#include "uv_type.hpp"
namespace uvw {
@ -13,31 +14,29 @@ namespace uvw {
*
* This is the base class for handles and requests.
*/
template<typename T, typename U>
class Resource: public UnderlyingType<T, U>, public Emitter<T>, public std::enable_shared_from_this<T> {
template<typename T, typename U, typename... E>
class resource: public uv_type<U>, public emitter<T, E...>, public std::enable_shared_from_this<T> {
protected:
using ConstructorAccess = typename UnderlyingType<T, U>::ConstructorAccess;
auto parent() const noexcept {
return this->loop().loop.get();
int leak_if(int err) noexcept {
if(err == 0) {
self_ptr = this->shared_from_this();
}
void leak() noexcept {
sPtr = this->shared_from_this();
return err;
}
void reset() noexcept {
sPtr.reset();
void self_reset() noexcept {
self_ptr.reset();
}
bool self() const noexcept {
return static_cast<bool>(sPtr);
bool has_self() const noexcept {
return static_cast<bool>(self_ptr);
}
public:
explicit Resource(ConstructorAccess ca, std::shared_ptr<Loop> ref)
: UnderlyingType<T, U>{ca, std::move(ref)} {
this->get()->data = this;
explicit resource(loop::token token, std::shared_ptr<loop> ref)
: uv_type<U>{token, std::move(ref)} {
this->raw()->data = this;
}
/**
@ -46,20 +45,20 @@ public:
*/
template<typename R = void>
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.
* @param uData User-defined arbitrary data.
* @param udata User-defined arbitrary data.
*/
void data(std::shared_ptr<void> uData) {
userData = std::move(uData);
void data(std::shared_ptr<void> udata) {
user_data = std::move(udata);
}
private:
std::shared_ptr<void> userData{nullptr};
std::shared_ptr<void> sPtr{nullptr};
std::shared_ptr<void> user_data{nullptr};
std::shared_ptr<void> self_ptr{nullptr};
};
} // namespace uvw

View File

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

View File

@ -2,70 +2,70 @@
#define UVW_SIGNAL_INCLUDE_H
#include <uv.h>
#include "config.h"
#include "handle.hpp"
#include "loop.h"
namespace uvw {
/**
* @brief SignalEvent event.
*
* It will be emitted by SignalHandle according with its functionalities.
*/
struct SignalEvent {
explicit SignalEvent(int sig) noexcept;
/*! @brief Signal event. */
struct signal_event {
explicit signal_event(int sig) noexcept;
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
* bases.<br/>
* 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
* [documentation](http://docs.libuv.org/en/v1.x/signal.html)
* for further details.
*/
class SignalHandle final: public Handle<SignalHandle, uv_signal_t> {
static void startCallback(uv_signal_t *handle, int signum);
class signal_handle final: public handle<signal_handle, uv_signal_t, signal_event> {
static void start_callback(uv_signal_t *hndl, int signum);
public:
using Handle::Handle;
using handle::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.
*
* The handle will start emitting SignalEvent when needed.
* The handle will start emitting signal events when needed.
*
* @param signum The signal to be monitored.
* @return Underlying return value.
*/
void start(int signum);
int start(int signum);
/**
* @brief Starts the handle.
*
* Same functionality as SignalHandle::start but the signal handler is reset
* the moment the signal is received.
* Same functionality as signal_handle::start but the signal handler is
* 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.
* @return Underlying return value.
*/
void stop();
int stop();
/**
* @brief Gets the signal being monitored.

View File

@ -6,11 +6,28 @@
namespace uvw {
UVW_INLINE DataEvent::DataEvent(std::unique_ptr<char[]> buf, std::size_t len) noexcept
: data{std::move(buf)}, length{len} {}
UVW_INLINE data_event::data_event(std::unique_ptr<char[]> buf, std::size_t len) noexcept
: data{std::move(buf)},
length{len} {}
UVW_INLINE void details::ShutdownReq::shutdown(uv_stream_t *handle) {
invoke(&uv_shutdown, get(), handle, &defaultCallback<ShutdownEvent>);
UVW_INLINE void details::connect_req::connect_callback(uv_connect_t *req, int status) {
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

View File

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

View File

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

View File

@ -7,6 +7,8 @@
#include <type_traits>
#include <utility>
#include <uv.h>
#include "config.h"
#include "enum.hpp"
#include "request.hpp"
#include "stream.h"
#include "util.h"
@ -15,20 +17,21 @@ namespace uvw {
namespace details {
enum class UVTCPFlags : std::underlying_type_t<uv_tcp_flags> {
IPV6ONLY = UV_TCP_IPV6ONLY
enum class uvw_tcp_flags : std::underlying_type_t<uv_tcp_flags> {
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/>
* By default, _IPv4_ is used as a template parameter. The handle already
* supports _IPv6_ out-of-the-box by using `uvw::IPv6`.
* By default, _ipv4_ is used as a template parameter. The handle already
* 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
* 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)
* 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:
using Time = std::chrono::duration<unsigned int>;
using Bind = details::UVTCPFlags;
using IPv4 = uvw::IPv4;
using IPv6 = uvw::IPv6;
using time = std::chrono::duration<unsigned int>;
using tcp_flags = details::uvw_tcp_flags;
using ipv4 = uvw::ipv4;
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.
* @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.
@ -58,25 +61,28 @@ public:
* The passed file descriptor or SOCKET is not checked for its type, but
* 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.
* @param value True to enable it, 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.
* @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>`).
* @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.
@ -92,78 +98,73 @@ public:
* @param enable True to enable it, 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.
*
* A successful call to this function does not guarantee that the call to
* `listen()` or `connect()` will work properly.<br/>
* ErrorEvent events can be emitted because of either this function or the
* ones mentioned above.
* `listen()` or `connect()` will work properly.
*
* Available flags are:
*
* * `TCPHandle::Bind::IPV6ONLY`: it disables dual-stack support and only
* IPv6 is used.
* * `tcp_handle::tcp_flags::IPV6ONLY`: it disables dual-stack support and
* only IPv6 is used.
*
* @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
* @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.
*
* A successful call to this function does not guarantee that the call to
* `listen()` or `connect()` will work properly.<br/>
* ErrorEvent events can be emitted because of either this function or the
* ones mentioned above.
* `listen()` or `connect()` will work properly.
*
* Available flags are:
*
* * `TCPHandle::Bind::IPV6ONLY`: it disables dual-stack support and only
* IPv6 is used.
* * `tcp_handle::tcp_flags::IPV6ONLY`: it disables dual-stack support and
* only IPv6 is used.
*
* @param ip The address to which to bind.
* @param port The port to which to bind.
* @param opts Optional additional flags.
* @return Underlying return value.
*/
template<typename I = IPv4>
void bind(const std::string &ip, unsigned int port, Flags<Bind> opts = Flags<Bind>{});
int bind(const std::string &ip, unsigned int port, tcp_flags opts = tcp_flags::_UVW_ENUM);
/**
* @brief Binds the handle to an address and port.
*
* A successful call to this function does not guarantee that the call to
* `listen()` or `connect()` will work properly.<br/>
* ErrorEvent events can be emitted because of either this function or the
* ones mentioned above.
* `listen()` or `connect()` will work properly.
*
* Available flags are:
*
* * `TCPHandle::Bind::IPV6ONLY`: it disables dual-stack support and only
* IPv6 is used.
* * `tcp_handle::tcp_flags::IPV6ONLY`: it disables dual-stack support and
* only IPv6 is used.
*
* @param addr A valid instance of Addr.
* @param addr A valid instance of socket_address.
* @param opts Optional additional flags.
* @return Underlying return value.
*/
template<typename I = IPv4>
void bind(Addr addr, Flags<Bind> opts = Flags<Bind>{});
int bind(socket_address addr, tcp_flags opts = tcp_flags::_UVW_ENUM);
/**
* @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>
Addr sock() const noexcept;
socket_address sock() const noexcept;
/**
* @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>
Addr peer() const noexcept;
socket_address peer() const noexcept;
/**
* @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
* done to match the behavior of Linux systems.
*
* A ConnectEvent event is emitted when the connection has been
* established.<br/>
* An ErrorEvent event is emitted in case of errors during the connection.
* A connect event is emitted when the connection has been established.
*
* @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.
*
* A ConnectEvent event is emitted when the connection has been
* established.<br/>
* An ErrorEvent event is emitted in case of errors during the connection.
* A connect event is emitted when the connection has been established.
*
* @param ip The address to which to bind.
* @param port The port to which to bind.
* @return Underlying return value.
*/
template<typename I = IPv4>
void connect(const std::string &ip, unsigned int port);
int connect(const std::string &ip, unsigned int port);
/**
* @brief Establishes an IPv4 or IPv6 TCP connection.
*
* A ConnectEvent event is emitted when the connection has been
* established.<br/>
* An ErrorEvent event is emitted in case of errors during the connection.
* A connect event is emitted when the connection has been established.
*
* @param addr A valid instance of Addr.
* @param addr A valid instance of socket_address.
* @return Underlying return value.
*/
template<typename I = IPv4>
void connect(Addr addr);
int connect(socket_address addr);
/**
* @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
* linger interval of zero and then calling `close`.<br/>
* 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/>
* An ErrorEvent event is emitted in case of errors.
* A close event is emitted when the connection has been reset.
*
* @return Underlying return value.
*/
void closeReset();
int close_reset();
private:
enum {
@ -227,37 +224,6 @@ private:
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
#ifndef UVW_AS_LIB

View File

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

View File

@ -8,55 +8,57 @@
#include <type_traits>
#include <utility>
#include <uv.h>
#include "config.h"
#include "enum.hpp"
#include "loop.h"
#include "underlying_type.hpp"
#include "uv_type.hpp"
namespace uvw {
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_HAS_STACK_SIZE = UV_THREAD_HAS_STACK_SIZE
};
}
class Thread;
class ThreadLocalStorage;
class Once;
class Mutex;
class RWLock;
class Semaphore;
class Condition;
class Barrier;
class thread;
class thread_local_storage;
class once;
class mutex;
class rwlock;
class semaphore;
class condition;
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
* 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>`.
*/
class Thread final: public UnderlyingType<Thread, uv_thread_t> {
using InternalTask = std::function<void(std::shared_ptr<void>)>;
class thread final: public uv_type<uv_thread_t> {
using internal_task = std::function<void(std::shared_ptr<void>)>;
static void createCallback(void *arg);
static void create_callback(void *arg);
public:
using Options = details::UVThreadCreateFlags;
using Task = InternalTask;
using Type = uv_thread_t;
using create_flags = details::uvw_thread_create_flags;
using task = internal_task;
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.
* @return The identifier of the calling thread.
*/
static Type self() noexcept;
static type self() noexcept;
/**
* @brief Compares thread by means of their identifiers.
@ -64,9 +66,9 @@ public:
* @param tr A valid instance of a thread.
* @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.
@ -79,15 +81,15 @@ public:
*
* Available flags are:
*
* * `Thread::Options::THREAD_NO_FLAGS`: no flags set.
* * `Thread::Options::THREAD_HAS_STACK_SIZE`: if set, `stack` specifies a
* * `thread::create_flags::THREAD_NO_FLAGS`: no flags set.
* * `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
* be used (it behaves as if the flag was not set). Other values will be
* rounded up to the nearest page boundary.
*
* @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.
@ -97,21 +99,21 @@ public:
private:
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
* seen as a global variable that is only visible to a particular thread and not
* the whole program.
*/
class ThreadLocalStorage final: public UnderlyingType<ThreadLocalStorage, uv_key_t> {
class thread_local_storage final: public uv_type<uv_key_t> {
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.
@ -120,7 +122,7 @@ public:
*/
template<typename T>
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>
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
* 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;
public:
using UnderlyingType::UnderlyingType;
using uv_type::uv_type;
/**
* @brief Runs a function once and only once.
@ -156,29 +158,29 @@ public:
* @param f A valid callback function.
*/
template<typename F>
static void once(F &&f) noexcept {
using CallbackType = void (*)(void);
static_assert(std::is_convertible_v<F, CallbackType>);
CallbackType cb = f;
static void run(F &&f) noexcept {
using callback_type = void (*)(void);
static_assert(std::is_convertible_v<F, callback_type>);
callback_type cb = f;
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
* default value is false, the mutex isn't recursive.
*/
class Mutex final: public UnderlyingType<Mutex, uv_mutex_t> {
friend class Condition;
class mutex final: public uv_type<uv_mutex_t> {
friend class condition;
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.
@ -189,7 +191,7 @@ public:
* @brief Tries to lock the mutex.
* @return True in case of success, false otherwise.
*/
bool tryLock() noexcept;
bool try_lock() noexcept;
/**
* @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:
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.
*/
void rdLock() noexcept;
void rdlock() noexcept;
/**
* @brief Tries to lock a read-write lock object for reading.
* @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.
*/
void rdUnlock() noexcept;
void rdunlock() noexcept;
/**
* @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.
* @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.
*/
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.
*/
class Semaphore final: public UnderlyingType<Semaphore, uv_sem_t> {
class semaphore final: public uv_type<uv_sem_t> {
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.
@ -266,17 +268,17 @@ public:
* @brief Tries to lock a semaphore.
* @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:
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.
@ -299,10 +301,10 @@ public:
* These function atomically releases the mutex and causes the calling
* 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.
*/
void wait(Mutex &mutex) noexcept;
void wait(mutex &mtx) noexcept;
/**
* @brief Waits on a condition.
@ -314,28 +316,28 @@ public:
* signaled or broadcasted, or if the absolute time specified has already
* 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.
* @param timeout The maximum time to wait before to return.
* @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
* `wait` before any of them successfully return from the call. The value
* 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:
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.

View File

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

View File

@ -9,61 +9,61 @@
namespace uvw {
/**
* @brief TimerEvent event.
*
* It will be emitted by TimerHandle according with its functionalities.
*/
struct TimerEvent {};
/*! @brief Timer event. */
struct timer_event {};
/**
* @brief The TimerHandle handle.
* @brief The timer handle.
*
* 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> {
static void startCallback(uv_timer_t *handle);
class timer_handle final: public handle<timer_handle, uv_timer_t, timer_event> {
static void start_callback(uv_timer_t *hndl);
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.
* @return True in case of success, false otherwise.
* @return Underlying return value.
*/
bool init();
int init() final;
/**
* @brief Starts the timer.
*
* If timeout is zero, a TimerEvent event is emitted on the next event loop
* iteration. If repeat is non-zero, a TimerEvent event is emitted first
* after timeout milliseconds and then repeatedly after repeat milliseconds.
* If timeout is zero, a timer event is emitted on the next event loop
* iteration. If repeat is non-zero, a timer event is emitted first after
* timeout milliseconds and then repeatedly after repeat milliseconds.
*
* @param timeout Milliseconds before to emit an event (use
* `std::chrono::duration<uint64_t, std::milli>`).
* @param repeat Milliseconds between successive events (use
* `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.
* @return Underlying return value.
*/
void stop();
int stop();
/**
* @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
* as the timeout.<br/>
* If the timer has never been started before it emits an ErrorEvent event.
* as the timeout.
*
* @return Underlying return value.
*/
void again();
int again();
/**
* @brief Sets the repeat interval value.
@ -83,23 +83,23 @@ public:
* @param repeat Repeat interval in milliseconds (use
* `std::chrono::duration<uint64_t, std::milli>`).
*/
void repeat(Time repeat);
void repeat(time repeat);
/**
* @brief Gets the timer repeat value.
* @return Timer repeat value in milliseconds (as a
* `std::chrono::duration<uint64_t, std::milli>`).
*/
Time repeat();
time repeat();
/**
* @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.
*/
Time dueIn();
time due_in();
};
} // namespace uvw

View File

@ -3,44 +3,43 @@
#endif
#include <utility>
#include "config.h"
namespace uvw {
UVW_INLINE details::ResetModeMemo::~ResetModeMemo() {
UVW_INLINE details::reset_mode_memo::~reset_mode_memo() {
uv_tty_reset_mode();
}
UVW_INLINE TTYHandle::TTYHandle(ConstructorAccess ca, std::shared_ptr<Loop> ref, FileHandle desc, bool readable)
: StreamHandle{ca, std::move(ref)},
memo{resetModeMemo()},
UVW_INLINE tty_handle::tty_handle(loop::token token, std::shared_ptr<loop> ref, file_handle desc, bool readable)
: stream_handle{token, std::move(ref)},
memo{mode_memo_handler()},
fd{desc},
rw{readable} {}
UVW_INLINE std::shared_ptr<details::ResetModeMemo> TTYHandle::resetModeMemo() {
static std::weak_ptr<details::ResetModeMemo> weak;
UVW_INLINE std::shared_ptr<details::reset_mode_memo> tty_handle::mode_memo_handler() {
static std::weak_ptr<details::reset_mode_memo> weak;
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;
};
UVW_INLINE bool TTYHandle::init() {
return initialize(&uv_tty_init, fd, rw);
UVW_INLINE int tty_handle::init() {
return leak_if(uv_tty_init(parent().raw(), raw(), fd, rw));
}
UVW_INLINE bool TTYHandle::mode(TTYHandle::Mode m) {
return (0 == uv_tty_set_mode(get(), static_cast<std::underlying_type_t<Mode>>(m)));
UVW_INLINE bool tty_handle::mode(tty_handle::tty_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());
}
UVW_INLINE WinSize TTYHandle::getWinSize() {
WinSize size;
UVW_INLINE win_size tty_handle::get_win_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.height = -1;
}
@ -48,21 +47,21 @@ UVW_INLINE WinSize TTYHandle::getWinSize() {
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) {
case VTermState::SUPPORTED:
case tty_vtermstate::SUPPORTED:
uv_tty_set_vterm_state(uv_tty_vtermstate_t::UV_TTY_SUPPORTED);
break;
case VTermState::UNSUPPORTED:
case tty_vtermstate::UNSUPPORTED:
uv_tty_set_vterm_state(uv_tty_vtermstate_t::UV_TTY_UNSUPPORTED);
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_get_vterm_state(&state);
return VTermState{state};
return tty_vtermstate{state};
}
} // namespace uvw

View File

@ -4,6 +4,7 @@
#include <memory>
#include <type_traits>
#include <uv.h>
#include "config.h"
#include "stream.h"
#include "util.h"
@ -11,17 +12,17 @@ namespace uvw {
namespace details {
struct ResetModeMemo {
~ResetModeMemo();
struct reset_mode_memo {
~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,
RAW = UV_TTY_MODE_RAW,
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,
UNSUPPORTED = UV_TTY_UNSUPPORTED
};
@ -29,16 +30,16 @@ enum class UVTTYVTermStateT : std::underlying_type_t<uv_tty_vtermstate_t> {
} // namespace details
/**
* @brief The TTYHandle handle.
* @brief The tty handle.
*
* 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:
* * `uvw::StdIN` or `0` for `stdin`
* * `uvw::StdOUT` or `1` for `stdout`
* * `uvw::StdERR` or `2` for `stderr`
* * A valid file_handle. Usually the file descriptor will be:
* * `uvw::std_in` or `0` for `stdin`
* * `uvw::std_out` or `1` for `stdout`
* * `uvw::std_err` or `2` for `stderr`
* * A boolean value that specifies the plan on calling `read()` with this
* 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)
* for further details.
*/
class TTYHandle final: public StreamHandle<TTYHandle, uv_tty_t> {
static std::shared_ptr<details::ResetModeMemo> resetModeMemo();
class tty_handle final: public stream_handle<tty_handle, uv_tty_t> {
static std::shared_ptr<details::reset_mode_memo> mode_memo_handler();
public:
using Mode = details::UVTTYModeT;
using VTermState = details::UVTTYVTermStateT;
using tty_mode = details::uvw_tty_mode_t;
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.
* @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.
*
* Available modes are:
*
* * `TTY::Mode::NORMAL`
* * `TTY::Mode::RAW`
* * `TTY::Mode::IO`
* * `TTY::tty_mode::NORMAL`
* * `TTY::tty_mode::RAW`
* * `TTY::tty_mode::IO`
*
* See the official
* [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.
* @return True in case of success, false otherwise.
*/
bool mode(Mode m);
bool mode(tty_mode m);
/**
* @brief Resets TTY settings to default values.
* @return True in case of success, false otherwise.
*/
bool reset() noexcept;
bool reset_mode() noexcept;
/**
* @brief Gets the current Window size.
* @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
@ -100,8 +101,8 @@ public:
*
* Available states are:
*
* * `TTY::VTermState::SUPPORTED`
* * `TTY::VTermState::UNSUPPORTED`
* * `TTY::tty_vtermstate::SUPPORTED`
* * `TTY::tty_vtermstate::UNSUPPORTED`
*
* See the official
* [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.
*/
void vtermState(VTermState s) const noexcept;
void vterm_state(tty_vtermstate s) const noexcept;
/**
* @brief Gets the current state of whether console virtual terminal
@ -119,8 +120,8 @@ public:
*
* Available states are:
*
* * `TTY::VTermState::SUPPORTED`
* * `TTY::VTermState::UNSUPPORTED`
* * `TTY::tty_vtermstate::SUPPORTED`
* * `TTY::tty_vtermstate::UNSUPPORTED`
*
* See the official
* [documentation](http://docs.libuv.org/en/v1.x/tty.html#c.uv_tty_vtermstate_t)
@ -128,11 +129,11 @@ public:
*
* @return The current state.
*/
VTermState vtermState() const noexcept;
tty_vtermstate vterm_state() const noexcept;
private:
std::shared_ptr<details::ResetModeMemo> memo;
FileHandle::Type fd;
std::shared_ptr<details::reset_mode_memo> memo;
file_handle fd;
int rw;
};

View File

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

View File

@ -6,274 +6,211 @@
namespace uvw {
UVW_INLINE UDPDataEvent::UDPDataEvent(Addr 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} {}
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} {}
UVW_INLINE details::SendReq::SendReq(ConstructorAccess ca, std::shared_ptr<Loop> loop, std::unique_ptr<char[], Deleter> dt, unsigned int len)
: Request<SendReq, uv_udp_send_t>{ca, std::move(loop)},
UVW_INLINE void details::send_req::udp_send_callback(uv_udp_send_t *req, int status) {
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)},
buf{uv_buf_init(data.get(), len)} {}
UVW_INLINE void details::SendReq::send(uv_udp_t *handle, const struct sockaddr *addr) {
invoke(&uv_udp_send, get(), handle, &buf, 1, addr, &defaultCallback<SendEvent>);
UVW_INLINE int details::send_req::send(uv_udp_t *hndl, const struct sockaddr *addr) {
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)
: Handle{ca, std::move(ref)}, tag{FLAGS}, flags{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) {
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() {
return (tag == FLAGS) ? initialize(&uv_udp_init_ex, flags) : initialize(&uv_udp_init);
if(nread > 0) {
// 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) {
invoke(&uv_udp_open, get(), socket);
UVW_INLINE udp_handle::udp_handle(loop::token token, std::shared_ptr<loop> ref, unsigned int f)
: 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) {
invoke(&uv_udp_bind, get(), &addr, opts);
UVW_INLINE int udp_handle::open(os_socket_handle socket) {
return uv_udp_open(raw(), socket);
}
UVW_INLINE void UDPHandle::connect(const sockaddr &addr) {
invoke(&uv_udp_connect, get(), &addr);
UVW_INLINE int udp_handle::connect(const sockaddr &addr) {
return uv_udp_connect(raw(), &addr);
}
template<typename I>
UVW_INLINE void UDPHandle::connect(const std::string &ip, unsigned int port) {
typename details::IpTraits<I>::Type addr;
details::IpTraits<I>::addrFunc(ip.data(), port, &addr);
connect(reinterpret_cast<const sockaddr &>(addr));
UVW_INLINE int udp_handle::connect(const std::string &ip, unsigned int port) {
return connect(details::ip_addr(ip.data(), port));
}
template<typename I>
UVW_INLINE void UDPHandle::connect(Addr addr) {
connect<I>(std::move(addr.ip), addr.port);
UVW_INLINE int udp_handle::connect(socket_address addr) {
return connect(addr.ip, addr.port);
}
UVW_INLINE void UDPHandle::disconnect() {
invoke(&uv_udp_connect, get(), nullptr);
UVW_INLINE int udp_handle::disconnect() {
return uv_udp_connect(raw(), nullptr);
}
template<typename I>
UVW_INLINE Addr UDPHandle::peer() const noexcept {
return details::address<I>(&uv_udp_getpeername, get());
UVW_INLINE socket_address udp_handle::peer() const noexcept {
sockaddr_storage storage;
int len = sizeof(sockaddr_storage);
uv_udp_getpeername(raw(), reinterpret_cast<sockaddr *>(&storage), &len);
return details::sock_addr(storage);
}
template<typename I>
UVW_INLINE void UDPHandle::bind(const std::string &ip, unsigned int port, Flags<Bind> opts) {
typename details::IpTraits<I>::Type addr;
details::IpTraits<I>::addrFunc(ip.data(), port, &addr);
bind(reinterpret_cast<const sockaddr &>(addr), std::move(opts));
UVW_INLINE int udp_handle::bind(const sockaddr &addr, udp_handle::udp_flags opts) {
return uv_udp_bind(raw(), &addr, static_cast<uv_udp_flags>(opts));
}
template<typename I>
UVW_INLINE void UDPHandle::bind(Addr addr, Flags<Bind> opts) {
bind<I>(std::move(addr.ip), addr.port, std::move(opts));
UVW_INLINE int udp_handle::bind(const std::string &ip, unsigned int port, udp_flags opts) {
return bind(details::ip_addr(ip.data(), port), opts);
}
template<typename I>
UVW_INLINE Addr UDPHandle::sock() const noexcept {
return details::address<I>(&uv_udp_getsockname, get());
UVW_INLINE int udp_handle::bind(socket_address addr, udp_flags opts) {
return bind(addr.ip, addr.port, opts);
}
template<typename I>
UVW_INLINE bool UDPHandle::multicastMembership(const std::string &multicast, const std::string &iface, Membership membership) {
return (0 == uv_udp_set_membership(get(), multicast.data(), iface.data(), static_cast<uv_membership>(membership)));
UVW_INLINE socket_address udp_handle::sock() const noexcept {
sockaddr_storage storage;
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) {
return (0 == uv_udp_set_multicast_loop(get(), enable));
UVW_INLINE bool udp_handle::multicast_membership(const std::string &multicast, const std::string &iface, membership ms) {
return (0 == uv_udp_set_membership(raw(), multicast.data(), iface.data(), static_cast<uv_membership>(ms)));
}
UVW_INLINE bool UDPHandle::multicastTtl(int val) {
return (0 == uv_udp_set_multicast_ttl(get(), val > 255 ? 255 : val));
UVW_INLINE bool udp_handle::multicast_loop(bool enable) {
return (0 == uv_udp_set_multicast_loop(raw(), enable));
}
template<typename I>
UVW_INLINE bool UDPHandle::multicastInterface(const std::string &iface) {
return (0 == uv_udp_set_multicast_interface(get(), iface.data()));
UVW_INLINE bool udp_handle::multicast_ttl(int val) {
return (0 == uv_udp_set_multicast_ttl(raw(), val > 255 ? 255 : val));
}
UVW_INLINE bool UDPHandle::broadcast(bool enable) {
return (0 == uv_udp_set_broadcast(get(), enable));
UVW_INLINE bool udp_handle::multicast_interface(const std::string &iface) {
return (0 == uv_udp_set_multicast_interface(raw(), iface.data()));
}
UVW_INLINE bool UDPHandle::ttl(int val) {
return (0 == uv_udp_set_ttl(get(), val > 255 ? 255 : val));
UVW_INLINE bool udp_handle::broadcast(bool enable) {
return (0 == uv_udp_set_broadcast(raw(), enable));
}
UVW_INLINE void UDPHandle::send(const sockaddr &addr, std::unique_ptr<char[]> data, unsigned int len) {
auto req = loop().resource<details::SendReq>(std::unique_ptr<char[], details::SendReq::Deleter>{data.release(), [](char *ptr) { delete[] ptr; }}, len);
UVW_INLINE bool udp_handle::ttl(int val) {
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 &) {
ptr->publish(event);
};
req->once<ErrorEvent>(listener);
req->once<SendEvent>(listener);
req->send(get(), &addr);
req->on<error_event>(listener);
req->on<send_event>(listener);
return req->send(raw(), &addr);
}
template<typename I>
UVW_INLINE void UDPHandle::send(const std::string &ip, unsigned int port, std::unique_ptr<char[]> data, unsigned int 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);
UVW_INLINE int udp_handle::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);
}
template<typename I>
UVW_INLINE void UDPHandle::send(Addr addr, std::unique_ptr<char[]> data, unsigned int len) {
send<I>(std::move(addr.ip), addr.port, std::move(data), len);
UVW_INLINE int udp_handle::send(socket_address addr, std::unique_ptr<char[]> data, unsigned int len) {
return send(addr.ip, addr.port, std::move(data), len);
}
UVW_INLINE void UDPHandle::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);
UVW_INLINE int udp_handle::send(const sockaddr &addr, char *data, unsigned int 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 &) {
ptr->publish(event);
};
req->once<ErrorEvent>(listener);
req->once<SendEvent>(listener);
req->send(get(), &addr);
req->on<error_event>(listener);
req->on<send_event>(listener);
return req->send(raw(), &addr);
}
template<typename I>
UVW_INLINE void UDPHandle::send(const std::string &ip, unsigned int port, char *data, unsigned int len) {
typename details::IpTraits<I>::Type addr;
details::IpTraits<I>::addrFunc(ip.data(), port, &addr);
send(reinterpret_cast<const sockaddr &>(addr), data, len);
UVW_INLINE int udp_handle::send(const std::string &ip, unsigned int port, char *data, unsigned int len) {
return send(details::ip_addr(ip.data(), port), data, len);
}
template<typename I>
UVW_INLINE void UDPHandle::send(Addr addr, char *data, unsigned int len) {
send<I>(std::move(addr.ip), addr.port, data, len);
UVW_INLINE int udp_handle::send(socket_address addr, char *data, unsigned int len) {
return send(addr.ip, addr.port, data, len);
}
template<typename I>
UVW_INLINE int UDPHandle::trySend(const sockaddr &addr, std::unique_ptr<char[]> data, unsigned int len) {
UVW_INLINE int udp_handle::try_send(const sockaddr &addr, std::unique_ptr<char[]> data, unsigned int len) {
uv_buf_t bufs[] = {uv_buf_init(data.get(), len)};
auto bw = uv_udp_try_send(get(), bufs, 1, &addr);
if(bw < 0) {
publish(ErrorEvent{bw});
bw = 0;
}
return bw;
return uv_udp_try_send(raw(), bufs, 1, &addr);
}
template<typename I>
UVW_INLINE int UDPHandle::trySend(const std::string &ip, unsigned int port, std::unique_ptr<char[]> data, unsigned int 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);
UVW_INLINE int udp_handle::try_send(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);
}
template<typename I>
UVW_INLINE int UDPHandle::trySend(Addr addr, std::unique_ptr<char[]> data, unsigned int len) {
return trySend<I>(std::move(addr.ip), addr.port, std::move(data), len);
UVW_INLINE int udp_handle::try_send(socket_address addr, std::unique_ptr<char[]> data, unsigned int len) {
return try_send(addr.ip, addr.port, std::move(data), len);
}
template<typename I>
UVW_INLINE int UDPHandle::trySend(const sockaddr &addr, char *data, unsigned int len) {
UVW_INLINE int udp_handle::try_send(const sockaddr &addr, char *data, unsigned int len) {
uv_buf_t bufs[] = {uv_buf_init(data, len)};
auto bw = uv_udp_try_send(get(), bufs, 1, &addr);
if(bw < 0) {
publish(ErrorEvent{bw});
bw = 0;
}
return bw;
return uv_udp_try_send(raw(), bufs, 1, &addr);
}
template<typename I>
UVW_INLINE int UDPHandle::trySend(const std::string &ip, unsigned int port, char *data, unsigned int len) {
typename details::IpTraits<I>::Type addr;
details::IpTraits<I>::addrFunc(ip.data(), port, &addr);
return trySend(reinterpret_cast<const sockaddr &>(addr), data, len);
UVW_INLINE int udp_handle::try_send(const std::string &ip, unsigned int port, char *data, unsigned int len) {
return try_send(details::ip_addr(ip.data(), port), data, len);
}
template<typename I>
UVW_INLINE int UDPHandle::trySend(Addr addr, char *data, unsigned int len) {
return trySend<I>(std::move(addr.ip), addr.port, data, len);
UVW_INLINE int udp_handle::try_send(socket_address addr, char *data, unsigned int len) {
return try_send(addr.ip, addr.port, data, len);
}
template<typename I>
UVW_INLINE void UDPHandle::recv() {
invoke(&uv_udp_recv_start, get(), &allocCallback, &recvCallback<I>);
UVW_INLINE int udp_handle::recv() {
return uv_udp_recv_start(raw(), &details::common_alloc_callback, &recv_callback);
}
UVW_INLINE void UDPHandle::stop() {
invoke(&uv_udp_recv_stop, get());
UVW_INLINE int udp_handle::stop() {
return uv_udp_recv_stop(raw());
}
UVW_INLINE size_t UDPHandle::sendQueueSize() const noexcept {
return uv_udp_get_send_queue_size(get());
UVW_INLINE size_t udp_handle::send_queue_size() const noexcept {
return uv_udp_get_send_queue_size(raw());
}
UVW_INLINE size_t UDPHandle::sendQueueCount() const noexcept {
return uv_udp_get_send_queue_count(get());
UVW_INLINE size_t udp_handle::send_queue_count() const noexcept {
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

View File

@ -7,73 +7,70 @@
#include <type_traits>
#include <utility>
#include <uv.h>
#include "config.h"
#include "enum.hpp"
#include "handle.hpp"
#include "request.hpp"
#include "util.h"
namespace uvw {
/**
* @brief SendEvent event.
*
* It will be emitted by UDPHandle according with its functionalities.
*/
struct SendEvent {};
/*! @brief Send event. */
struct send_event {};
/**
* @brief UDPDataEvent event.
*
* 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;
/*! @brief UDP data event. */
struct udp_data_event {
explicit udp_data_event(socket_address 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::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. */
};
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,
UDP_PARTIAL = UV_UDP_PARTIAL,
REUSEADDR = UV_UDP_REUSEADDR,
UDP_MMSG_CHUNK = UV_UDP_MMSG_CHUNK,
UDP_MMSG_FREE = UV_UDP_MMSG_FREE,
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,
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:
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:
std::unique_ptr<char[], Deleter> data;
std::unique_ptr<char[], deleter> data;
uv_buf_t buf;
};
} // namespace details
/**
* @brief The UDPHandle handle.
* @brief The UDP handle.
*
* UDP handles encapsulate UDP communication for both clients and servers.<br/>
* By default, _IPv4_ is used as a template parameter. The handle already
* supports _IPv6_ out-of-the-box by using `uvw::IPv6`.
* By default, _ipv4_ is used as a template parameter. The handle already
* 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
* the socket.
@ -82,42 +79,22 @@ private:
* [documentation](http://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_init_ex)
* for further details.
*/
class UDPHandle final: public Handle<UDPHandle, uv_udp_t> {
template<typename I>
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));
}
}
class udp_handle final: public handle<udp_handle, uv_udp_t, send_event, udp_data_event> {
static void recv_callback(uv_udp_t *hndl, ssize_t nread, const uv_buf_t *buf, const sockaddr *addr, unsigned flags);
public:
using Membership = details::UVMembership;
using Bind = details::UVUDPFlags;
using IPv4 = uvw::IPv4;
using IPv6 = uvw::IPv6;
using membership = details::uvw_membership;
using udp_flags = details::uvw_udp_flags;
using ipv4 = uvw::ipv4;
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.
* @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.
@ -129,22 +106,84 @@ public:
* [documentation](http://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_open)
* 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.
*
* Available flags are:
*
* * `UDPHandle::Bind::IPV6ONLY`
* * `UDPHandle::Bind::UDP_PARTIAL`
* * `UDPHandle::Bind::REUSEADDR`
* * `UDPHandle::Bind::UDP_MMSG_CHUNK`
* * `UDPHandle::Bind::UDP_MMSG_FREE`
* * `UDPHandle::Bind::UDP_LINUX_RECVERR`
* * `UDPHandle::Bind::UDP_RECVMMSG`
* * `udp_handle::udp_flags::IPV6ONLY`
* * `udp_handle::udp_flags::UDP_PARTIAL`
* * `udp_handle::udp_flags::REUSEADDR`
* * `udp_handle::udp_flags::UDP_MMSG_CHUNK`
* * `udp_handle::udp_flags::UDP_MMSG_FREE`
* * `udp_handle::udp_flags::UDP_LINUX_RECVERR`
* * `udp_handle::udp_flags::UDP_RECVMMSG`
*
* See the official
* [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 opts Optional additional flags.
* @return Underlying return value.
*/
void bind(const sockaddr &addr, Flags<Bind> opts = Flags<Bind>{});
/**
* @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;
int bind(const sockaddr &addr, udp_flags opts = udp_flags::_UVW_ENUM);
/**
* @brief Binds the UDP handle to an IP address and port.
*
* Available flags are:
*
* * `UDPHandle::Bind::IPV6ONLY`
* * `UDPHandle::Bind::UDP_PARTIAL`
* * `UDPHandle::Bind::REUSEADDR`
* * `UDPHandle::Bind::UDP_MMSG_CHUNK`
* * `UDPHandle::Bind::UDP_MMSG_FREE`
* * `UDPHandle::Bind::UDP_LINUX_RECVERR`
* * `UDPHandle::Bind::UDP_RECVMMSG`
* * `udp_handle::udp_flags::IPV6ONLY`
* * `udp_handle::udp_flags::UDP_PARTIAL`
* * `udp_handle::udp_flags::REUSEADDR`
* * `udp_handle::udp_flags::UDP_MMSG_CHUNK`
* * `udp_handle::udp_flags::UDP_MMSG_FREE`
* * `udp_handle::udp_flags::UDP_LINUX_RECVERR`
* * `udp_handle::udp_flags::UDP_RECVMMSG`
*
* See the official
* [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 port The port to which to bind.
* @param opts Optional additional flags.
* @return Underlying return value.
*/
template<typename I = IPv4>
void bind(const std::string &ip, unsigned int port, Flags<Bind> opts = Flags<Bind>{});
int bind(const std::string &ip, unsigned int port, udp_flags opts = udp_flags::_UVW_ENUM);
/**
* @brief Binds the UDP handle to an IP address and port.
*
* Available flags are:
*
* * `UDPHandle::Bind::IPV6ONLY`
* * `UDPHandle::Bind::UDP_PARTIAL`
* * `UDPHandle::Bind::REUSEADDR`
* * `UDPHandle::Bind::UDP_MMSG_CHUNK`
* * `UDPHandle::Bind::UDP_MMSG_FREE`
* * `UDPHandle::Bind::UDP_LINUX_RECVERR`
* * `UDPHandle::Bind::UDP_RECVMMSG`
* * `udp_handle::udp_flags::IPV6ONLY`
* * `udp_handle::udp_flags::UDP_PARTIAL`
* * `udp_handle::udp_flags::REUSEADDR`
* * `udp_handle::udp_flags::UDP_MMSG_CHUNK`
* * `udp_handle::udp_flags::UDP_MMSG_FREE`
* * `udp_handle::udp_flags::UDP_LINUX_RECVERR`
* * `udp_handle::udp_flags::UDP_RECVMMSG`
*
* See the official
* [documentation](http://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_flags)
* for further details.
*
* @param addr A valid instance of Addr.
* @param addr A valid instance of socket_address.
* @param opts Optional additional flags.
* @return Underlying return value.
*/
template<typename I = IPv4>
void bind(Addr addr, Flags<Bind> opts = Flags<Bind>{});
int bind(socket_address addr, udp_flags opts = udp_flags::_UVW_ENUM);
/**
* @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>
Addr sock() const noexcept;
socket_address sock() const noexcept;
/**
* @brief Sets membership for a multicast address.
*
* Available values for `membership` are:
* Available values for `ms` are:
*
* * `UDPHandle::Membership::LEAVE_GROUP`
* * `UDPHandle::Membership::JOIN_GROUP`
* * `udp_handle::membership::LEAVE_GROUP`
* * `udp_handle::membership::JOIN_GROUP`
*
* @param multicast Multicast address to set membership for.
* @param iface Interface address.
* @param membership Action to be performed.
* @param ms Action to be performed.
* @return True in case of success, false otherwise.
*/
template<typename I = IPv4>
bool multicastMembership(const std::string &multicast, const std::string &iface, Membership membership);
bool multicast_membership(const std::string &multicast, const std::string &iface, membership ms);
/**
* @brief Sets IP multicast loop flag.
@ -297,22 +272,21 @@ public:
* @param enable True to enable multicast loop, 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.
* @param val A value in the range `[1, 255]`.
* @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.
* @param iface Interface address.
* @return True in case of success, false otherwise.
*/
template<typename I = IPv4>
bool multicastInterface(const std::string &iface);
bool multicast_interface(const std::string &iface);
/**
* @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
* them.
*
* A SendEvent event will be emitted when the data have been sent.<br/>
* An ErrorEvent event will be emitted in case of errors.
* A send event will be emitted when the data have been sent.
*
* @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
* @param data The data to be sent.
* @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.
@ -357,16 +331,15 @@ public:
* The handle takes the ownership of the data and it is in charge of delete
* them.
*
* A SendEvent event will be emitted when the data have been sent.<br/>
* An ErrorEvent event will be emitted in case of errors.
* A send event will be emitted when the data have been sent.
*
* @param ip The address to which to send data.
* @param port The port to which to send data.
* @param data The data to be sent.
* @param len The lenght of the submitted data.
* @return Underlying return value.
*/
template<typename I = IPv4>
void send(const std::string &ip, unsigned int port, std::unique_ptr<char[]> data, unsigned int len);
int send(const std::string &ip, unsigned int port, std::unique_ptr<char[]> data, unsigned int len);
/**
* @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
* them.
*
* A SendEvent event will be emitted when the data have been sent.<br/>
* An ErrorEvent event will be emitted in case of errors.
* A send event will be emitted when the data have been sent.
*
* @param addr A valid instance of Addr.
* @param addr A valid instance of socket_address.
* @param data The data to be sent.
* @param len The lenght of the submitted data.
* @return Underlying return value.
*/
template<typename I = IPv4>
void send(Addr addr, std::unique_ptr<char[]> data, unsigned int len);
int send(socket_address addr, std::unique_ptr<char[]> data, unsigned int len);
/**
* @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
* lifetime overcome the one of the request.
*
* A SendEvent event will be emitted when the data have been sent.<br/>
* An ErrorEvent event will be emitted in case of errors.
* A send event will be emitted when the data have been sent.
*
* @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
* @param data The data to be sent.
* @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.
@ -417,16 +389,15 @@ public:
* The handle doesn't take the ownership of the data. Be sure that their
* lifetime overcome the one of the request.
*
* A SendEvent event will be emitted when the data have been sent.<br/>
* An ErrorEvent event will be emitted in case of errors.
* A send event will be emitted when the data have been sent.
*
* @param ip The address to which to send data.
* @param port The port to which to send data.
* @param data The data to be sent.
* @param len The lenght of the submitted data.
* @return Underlying return value.
*/
template<typename I = IPv4>
void send(const std::string &ip, unsigned int port, char *data, unsigned int len);
int send(const std::string &ip, unsigned int port, char *data, unsigned int len);
/**
* @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
* lifetime overcome the one of the request.
*
* A SendEvent event will be emitted when the data have been sent.<br/>
* An ErrorEvent event will be emitted in case of errors.
* A send event will be emitted when the data have been sent.
*
* @param addr A valid instance of Addr.
* @param addr A valid instance of socket_address.
* @param data The data to be sent.
* @param len The lenght of the submitted data.
* @return Underlying return value.
*/
template<typename I = IPv4>
void send(Addr addr, char *data, unsigned int len);
int send(socket_address addr, char *data, unsigned int len);
/**
* @brief Sends data over the UDP socket.
@ -457,10 +427,9 @@ public:
* @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
* @param data The data to be sent.
* @param len The lenght of the submitted data.
* @return Number of bytes written.
* @return Underlying return value.
*/
template<typename I = IPv4>
int trySend(const sockaddr &addr, std::unique_ptr<char[]> data, unsigned int len);
int try_send(const sockaddr &addr, std::unique_ptr<char[]> data, unsigned int len);
/**
* @brief Sends data over the UDP socket.
@ -472,10 +441,9 @@ public:
* @param port The port to which to send data.
* @param data The data to be sent.
* @param len The lenght of the submitted data.
* @return Number of bytes written.
* @return Underlying return value.
*/
template<typename I = IPv4>
int trySend(const std::string &ip, unsigned int port, std::unique_ptr<char[]> data, unsigned int len);
int try_send(const std::string &ip, unsigned int port, std::unique_ptr<char[]> data, unsigned int len);
/**
* @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
* 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 len The lenght of the submitted data.
* @return Number of bytes written.
* @return Underlying return value.
*/
template<typename I = IPv4>
int trySend(Addr addr, std::unique_ptr<char[]> data, unsigned int len);
int try_send(socket_address addr, std::unique_ptr<char[]> data, unsigned int len);
/**
* @brief Sends data over the UDP socket.
@ -500,10 +467,9 @@ public:
* @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
* @param data The data to be sent.
* @param len The lenght of the submitted data.
* @return Number of bytes written.
* @return Underlying return value.
*/
template<typename I = IPv4>
int trySend(const sockaddr &addr, char *data, unsigned int len);
int try_send(const sockaddr &addr, char *data, unsigned int len);
/**
* @brief Sends data over the UDP socket.
@ -515,10 +481,9 @@ public:
* @param port The port to which to send data.
* @param data The data to be sent.
* @param len The lenght of the submitted data.
* @return Number of bytes written.
* @return Underlying return value.
*/
template<typename I = IPv4>
int trySend(const std::string &ip, unsigned int port, char *data, unsigned int len);
int try_send(const std::string &ip, unsigned int port, char *data, unsigned int len);
/**
* @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
* 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 len The lenght of the submitted data.
* @return Number of bytes written.
* @return Underlying return value.
*/
template<typename I = IPv4>
int trySend(Addr addr, char *data, unsigned int len);
int try_send(socket_address addr, char *data, unsigned int len);
/**
* @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
* port number.
*
* An UDPDataEvent event will be emitted when the handle receives data.<br/>
* An ErrorEvent event will be emitted in case of errors.
* An UDP data event will be emitted when the handle receives data.
*
* @return Underlying return value.
*/
template<typename I = IPv4>
void recv();
int recv();
/**
* @brief Stops listening for incoming datagrams.
* @return Underlying return value.
*/
void stop();
int stop();
/**
* @brief Gets the number of bytes queued for sending.
@ -559,13 +524,14 @@ public:
*
* @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.
*/
size_t sendQueueCount() const noexcept;
size_t send_queue_count() const noexcept;
private:
enum {
@ -576,76 +542,6 @@ private:
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
#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"
#endif
#include <algorithm>
#include "config.h"
namespace uvw {
UVW_INLINE Passwd::Passwd(std::shared_ptr<uv_passwd_t> pwd)
: passwd{pwd} {}
UVW_INLINE passwd_info::passwd_info(std::shared_ptr<uv_passwd_t> pwd)
: value{pwd} {}
UVW_INLINE std::string Passwd::username() const noexcept {
return ((passwd && passwd->username) ? passwd->username : "");
UVW_INLINE std::string passwd_info::username() const noexcept {
return ((value && value->username) ? value->username : "");
}
UVW_INLINE decltype(uv_passwd_t::uid) Passwd::uid() const noexcept {
return (passwd ? passwd->uid : decltype(uv_passwd_t::uid){});
UVW_INLINE decltype(uv_passwd_t::uid) passwd_info::uid() const noexcept {
return (value ? value->uid : decltype(uv_passwd_t::uid){});
}
UVW_INLINE decltype(uv_passwd_t::gid) Passwd::gid() const noexcept {
return (passwd ? passwd->gid : decltype(uv_passwd_t::gid){});
UVW_INLINE decltype(uv_passwd_t::gid) passwd_info::gid() const noexcept {
return (value ? value->gid : decltype(uv_passwd_t::gid){});
}
UVW_INLINE std::string Passwd::shell() const noexcept {
return ((passwd && passwd->shell) ? passwd->shell : "");
UVW_INLINE std::string passwd_info::shell() const noexcept {
return ((value && value->shell) ? value->shell : "");
}
UVW_INLINE std::string Passwd::homedir() const noexcept {
return ((passwd && passwd->homedir) ? passwd->homedir : "");
UVW_INLINE std::string passwd_info::homedir() const noexcept {
return ((value && value->homedir) ? value->homedir : "");
}
UVW_INLINE Passwd::operator bool() const noexcept {
return static_cast<bool>(passwd);
UVW_INLINE passwd_info::operator bool() const noexcept {
return static_cast<bool>(value);
}
UVW_INLINE UtsName::UtsName(std::shared_ptr<uv_utsname_t> utsname)
: utsname{utsname} {}
UVW_INLINE uts_name::uts_name(std::shared_ptr<uv_utsname_t> init)
: uname{init} {}
UVW_INLINE std::string UtsName::sysname() const noexcept {
return utsname ? utsname->sysname : "";
UVW_INLINE std::string uts_name::sysname() const noexcept {
return uname ? uname->sysname : "";
}
UVW_INLINE std::string UtsName::release() const noexcept {
return utsname ? utsname->release : "";
UVW_INLINE std::string uts_name::release() const noexcept {
return uname ? uname->release : "";
}
UVW_INLINE std::string UtsName::version() const noexcept {
return utsname ? utsname->version : "";
UVW_INLINE std::string uts_name::version() const noexcept {
return uname ? uname->version : "";
}
UVW_INLINE std::string UtsName::machine() const noexcept {
return utsname ? utsname->machine : "";
UVW_INLINE std::string uts_name::machine() const noexcept {
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();
}
UVW_INLINE PidType Utilities::OS::parent() noexcept {
UVW_INLINE pid_type utilities::os::ppid() noexcept {
return uv_os_getppid();
}
UVW_INLINE std::string Utilities::OS::homedir() noexcept {
return details::tryRead(&uv_os_homedir);
UVW_INLINE std::string utilities::os::homedir() noexcept {
return details::try_read(&uv_os_homedir);
}
UVW_INLINE std::string Utilities::OS::tmpdir() noexcept {
return details::tryRead(&uv_os_tmpdir);
UVW_INLINE std::string utilities::os::tmpdir() noexcept {
return details::try_read(&uv_os_tmpdir);
}
UVW_INLINE std::string Utilities::OS::env(const std::string &name) noexcept {
return details::tryRead(&uv_os_getenv, name.c_str());
UVW_INLINE std::string utilities::os::env(const std::string &name) noexcept {
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())));
}
UVW_INLINE std::string Utilities::OS::hostname() noexcept {
return details::tryRead(&uv_os_gethostname);
UVW_INLINE std::string utilities::os::hostname() noexcept {
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>();
uv_os_uname(ptr.get());
return ptr;
}
UVW_INLINE Passwd Utilities::OS::passwd() noexcept {
UVW_INLINE passwd_info utilities::os::passwd() noexcept {
auto deleter = [](uv_passwd_t *passwd) {
uv_os_free_passwd(passwd);
delete passwd;
@ -99,7 +152,7 @@ UVW_INLINE Passwd Utilities::OS::passwd() noexcept {
return ptr;
}
UVW_INLINE int Utilities::OS::priority(PidType pid) {
UVW_INLINE int utilities::os::priority(pid_type pid) {
int prio = 0;
if(uv_os_getpriority(pid, &prio)) {
@ -109,66 +162,66 @@ UVW_INLINE int Utilities::OS::priority(PidType pid) {
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);
}
UVW_INLINE HandleType Utilities::guessHandle(HandleCategory category) noexcept {
UVW_INLINE handle_type utilities::guess_handle(handle_category category) noexcept {
switch(category) {
case UV_ASYNC:
return HandleType::ASYNC;
return handle_type::ASYNC;
case UV_CHECK:
return HandleType::CHECK;
return handle_type::CHECK;
case UV_FS_EVENT:
return HandleType::FS_EVENT;
return handle_type::FS_EVENT;
case UV_FS_POLL:
return HandleType::FS_POLL;
return handle_type::FS_POLL;
case UV_HANDLE:
return HandleType::HANDLE;
return handle_type::HANDLE;
case UV_IDLE:
return HandleType::IDLE;
return handle_type::IDLE;
case UV_NAMED_PIPE:
return HandleType::PIPE;
return handle_type::PIPE;
case UV_POLL:
return HandleType::POLL;
return handle_type::POLL;
case UV_PREPARE:
return HandleType::PREPARE;
return handle_type::PREPARE;
case UV_PROCESS:
return HandleType::PROCESS;
return handle_type::PROCESS;
case UV_STREAM:
return HandleType::STREAM;
return handle_type::STREAM;
case UV_TCP:
return HandleType::TCP;
return handle_type::TCP;
case UV_TIMER:
return HandleType::TIMER;
return handle_type::TIMER;
case UV_TTY:
return HandleType::TTY;
return handle_type::TTY;
case UV_UDP:
return HandleType::UDP;
return handle_type::UDP;
case UV_SIGNAL:
return HandleType::SIGNAL;
return handle_type::SIGNAL;
case UV_FILE:
return HandleType::FILE;
return handle_type::FILE;
default:
return HandleType::UNKNOWN;
return handle_type::UNKNOWN;
}
}
UVW_INLINE HandleType Utilities::guessHandle(FileHandle file) noexcept {
HandleCategory category = uv_guess_handle(file);
return guessHandle(category);
UVW_INLINE handle_type utilities::guess_handle(file_handle file) noexcept {
handle_category category = uv_guess_handle(file);
return guess_handle(category);
}
UVW_INLINE std::vector<CPUInfo> Utilities::cpuInfo() noexcept {
std::vector<CPUInfo> cpuinfos;
UVW_INLINE std::vector<cpu_info> utilities::cpu() noexcept {
std::vector<cpu_info> cpuinfos;
uv_cpu_info_t *infos;
int count;
if(0 == uv_cpu_info(&infos, &count)) {
std::for_each(infos, infos + count, [&cpuinfos](const auto &info) {
cpuinfos.push_back({info.model, info.speed, info.cpu_times});
});
for (int next = 0; next < count; ++next) {
cpuinfos.push_back({infos[next].model, infos[next].speed, infos[next].cpu_times});
}
uv_free_cpu_info(infos, count);
}
@ -176,30 +229,30 @@ UVW_INLINE std::vector<CPUInfo> Utilities::cpuInfo() noexcept {
return cpuinfos;
}
UVW_INLINE std::vector<InterfaceAddress> Utilities::interfaceAddresses() noexcept {
std::vector<InterfaceAddress> interfaces;
UVW_INLINE std::vector<interface_address> utilities::interface_addresses() noexcept {
std::vector<interface_address> interfaces;
uv_interface_address_t *ifaces{nullptr};
int count{0};
if(0 == uv_interface_addresses(&ifaces, &count)) {
std::for_each(ifaces, ifaces + count, [&interfaces](const auto &iface) {
InterfaceAddress interfaceAddress;
for(int next = 0; next < count; ++next) {
interface_address iface_addr;
interfaceAddress.name = iface.name;
std::copy(iface.phys_addr, (iface.phys_addr + 6), interfaceAddress.physical);
interfaceAddress.internal = iface.is_internal == 0 ? false : true;
iface_addr.name = ifaces[next].name;
std::copy(ifaces[next].phys_addr, (ifaces[next].phys_addr + 6), iface_addr.physical);
iface_addr.internal = ifaces[next].is_internal == 0 ? false : true;
if(iface.address.address4.sin_family == AF_INET) {
interfaceAddress.address = details::address<IPv4>(&iface.address.address4);
interfaceAddress.netmask = details::address<IPv4>(&iface.netmask.netmask4);
} else if(iface.address.address4.sin_family == AF_INET6) {
interfaceAddress.address = details::address<IPv6>(&iface.address.address6);
interfaceAddress.netmask = details::address<IPv6>(&iface.netmask.netmask6);
if(ifaces[next].address.address4.sin_family == AF_INET) {
iface_addr.address = details::sock_addr(ifaces[next].address.address4);
iface_addr.netmask = details::sock_addr(ifaces[next].netmask.netmask4);
} else if(ifaces[next].address.address4.sin_family == AF_INET6) {
iface_addr.address = details::sock_addr(ifaces[next].address.address6);
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);
}
@ -207,29 +260,29 @@ UVW_INLINE std::vector<InterfaceAddress> Utilities::interfaceAddresses() noexcep
return interfaces;
}
UVW_INLINE std::string Utilities::indexToName(unsigned int index) noexcept {
return details::tryRead(&uv_if_indextoname, index);
UVW_INLINE std::string utilities::index_to_name(unsigned int index) noexcept {
return details::try_read(&uv_if_indextoname, index);
}
UVW_INLINE std::string Utilities::indexToIid(unsigned int index) noexcept {
return details::tryRead(&uv_if_indextoiid, index);
UVW_INLINE std::string utilities::index_to_iid(unsigned int index) noexcept {
return details::try_read(&uv_if_indextoiid, index);
}
UVW_INLINE bool Utilities::replaceAllocator(MallocFuncType mallocFunc, ReallocFuncType reallocFunc, CallocFuncType callocFunc, FreeFuncType freeFunc) noexcept {
return (0 == uv_replace_allocator(mallocFunc, reallocFunc, callocFunc, freeFunc));
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(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;
uv_loadavg(avg.data());
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);
}
UVW_INLINE std::string Utilities::processTitle() {
UVW_INLINE std::string utilities::process_title() {
std::size_t size = details::DEFAULT_SIZE;
char buf[details::DEFAULT_SIZE];
std::string str{};
@ -241,19 +294,19 @@ UVW_INLINE std::string Utilities::processTitle() {
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()));
}
UVW_INLINE uint64_t Utilities::totalMemory() noexcept {
UVW_INLINE uint64_t utilities::total_memory() noexcept {
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();
}
UVW_INLINE double Utilities::uptime() noexcept {
UVW_INLINE double utilities::uptime() noexcept {
double ret;
if(0 != uv_uptime(&ret)) {
@ -263,39 +316,39 @@ UVW_INLINE double Utilities::uptime() noexcept {
return ret;
}
UVW_INLINE RUsage Utilities::rusage() noexcept {
RUsage ru;
UVW_INLINE resource_usage utilities::rusage() noexcept {
resource_usage 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();
}
UVW_INLINE std::string Utilities::path() noexcept {
return details::tryRead(&uv_exepath);
UVW_INLINE std::string utilities::path() noexcept {
return details::try_read(&uv_exepath);
}
UVW_INLINE std::string Utilities::cwd() noexcept {
return details::tryRead(&uv_cwd);
UVW_INLINE std::string utilities::cwd() noexcept {
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()));
}
UVW_INLINE TimeVal64 Utilities::timeOfDay() noexcept {
UVW_INLINE timeval64 utilities::time_of_day() noexcept {
uv_timeval64_t ret;
uv_gettimeofday(&ret);
return ret;
}
UVW_INLINE void Utilities::sleep(unsigned int msec) noexcept {
UVW_INLINE void utilities::sleep(unsigned int msec) noexcept {
uv_sleep(msec);
}
UVW_INLINE unsigned int Utilities::availableParallelism() noexcept {
UVW_INLINE unsigned int utilities::available_parallelism() noexcept {
return uv_available_parallelism();
}

View File

@ -11,12 +11,13 @@
#include <utility>
#include <vector>
#include <uv.h>
#include "config.h"
namespace uvw {
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,
ASYNC = UV_ASYNC,
CHECK = UV_CHECK,
@ -38,20 +39,20 @@ enum class UVHandleType : std::underlying_type_t<uv_handle_type> {
};
template<typename T>
struct UVTypeWrapper {
struct uv_type_wrapper {
using Type = T;
constexpr UVTypeWrapper()
constexpr uv_type_wrapper()
: value{} {}
constexpr UVTypeWrapper(Type val)
constexpr uv_type_wrapper(Type val)
: value{val} {}
constexpr operator Type() const noexcept {
return value;
}
bool operator==(UVTypeWrapper other) const noexcept {
bool operator==(uv_type_wrapper other) const noexcept {
return value == other.value;
}
@ -60,166 +61,40 @@ private:
};
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);
}
} // 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.
*/
struct WinSize {
struct win_size {
int width; /*!< The _width_ 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. */
using FileHandle = details::UVTypeWrapper<uv_file>; /*!< Utility class that wraps an internal file handle. */
using OSSocketHandle = details::UVTypeWrapper<uv_os_sock_t>; /*!< Utility class that wraps an os socket handle. */
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 file_handle std_in{0}; /*!< Placeholder for stdin descriptor. */
constexpr file_handle std_out{1}; /*!< Placeholder for stdout descriptor. */
constexpr file_handle std_err{2}; /*!< Placeholder for stderr descriptor. */
constexpr FileHandle StdIN{0}; /*!< Placeholder for stdin descriptor. */
constexpr FileHandle StdOUT{1}; /*!< Placeholder for stdout descriptor. */
constexpr FileHandle StdERR{2}; /*!< Placeholder for stderr descriptor. */
using time_spec = uv_timespec_t; /*!< Library equivalent for uv_timespec_t. */
using file_info = uv_stat_t; /*!< Library equivalent for uv_stat_t. */
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 Stat = uv_stat_t; /*!< Library equivalent for uv_stat_t. */
using Statfs = uv_statfs_t; /*!< Library equivalent for uv_statfs_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. */
using timeval = uv_timeval_t; /*!< Library equivalent for uv_timeval_t. */
using timeval64 = uv_timeval64_t; /*!< Library equivalent for uv_timeval64_t. */
using resource_usage = uv_rusage_t; /*!< Library equivalent for uv_rusage_t. */
/**
* @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
* current effective uid (not the real uid).
*
* \sa Utilities::passwd
* \sa utilities::passwd
*/
struct Passwd {
Passwd(std::shared_ptr<uv_passwd_t> pwd);
struct passwd_info {
passwd_info(std::shared_ptr<uv_passwd_t> pwd);
/**
* @brief Gets the username.
@ -269,7 +144,7 @@ struct Passwd {
operator bool() const noexcept;
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
* machine.
*
* \sa Utilities::uname
* \sa utilities::uname
*/
struct UtsName {
UtsName(std::shared_ptr<uv_utsname_t> utsname);
struct uts_name {
uts_name(std::shared_ptr<uv_utsname_t> init);
/**
* @brief Gets the operating system name (like "Linux").
@ -309,7 +184,7 @@ struct UtsName {
std::string machine() const noexcept;
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.
*/
struct IPv4 {};
struct ipv4 {};
/**
* @brief The IPv6 tag.
*
* To be used as template parameter to switch between IPv4 and IPv6.
*/
struct IPv6 {};
struct ipv6 {};
/**
* @brief Address representation.
*/
struct Addr {
struct socket_address {
std::string ip; /*!< Either an IPv4 or an IPv6. */
unsigned int port; /*!< A valid service identifier. */
};
@ -337,8 +212,8 @@ struct Addr {
/**
* \brief CPU information.
*/
struct CPUInfo {
using CPUTime = decltype(uv_cpu_info_t::cpu_times);
struct cpu_info {
using cpu_time = decltype(uv_cpu_info_t::cpu_times);
std::string model; /*!< The model 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`,
* `idle`, `irq`, all of them having type `uint64_t`.
*/
CPUTime times;
cpu_time times;
};
/**
* \brief Interface address.
*/
struct InterfaceAddress {
struct interface_address {
std::string name; /*!< The name of the interface (as an example _eth0_). */
char physical[6]; /*!< The physical address. */
bool internal; /*!< True if it is an internal interface (as an example _loopback_), false otherwise. */
Addr address; /*!< The address of the given interface. */
Addr netmask; /*!< The netmask of the given interface. */
socket_address address; /*!< The address of the given interface. */
socket_address netmask; /*!< The netmask of the given interface. */
};
namespace details {
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>
std::string tryRead(F &&f, Args &&...args) noexcept {
std::string try_read(F &&f, Args &&...args) noexcept {
std::size_t size = DEFAULT_SIZE;
char buf[DEFAULT_SIZE];
std::string str{};
@ -450,6 +263,14 @@ std::string tryRead(F &&f, Args &&...args) noexcept {
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
/**
@ -457,16 +278,16 @@ std::string tryRead(F &&f, Args &&...args) noexcept {
*
* Miscellaneous functions that dont really belong to any other class.
*/
struct Utilities {
using MallocFuncType = void *(*)(size_t);
using ReallocFuncType = void *(*)(void *, size_t);
using CallocFuncType = void *(*)(size_t, size_t);
using FreeFuncType = void (*)(void *);
struct utilities {
using malloc_func_type = void *(*)(size_t);
using realloc_func_type = void *(*)(void *, size_t);
using calloc_func_type = void *(*)(size_t, size_t);
using free_func_type = void (*)(void *);
/**
* @brief OS dedicated utilities.
*/
struct OS {
struct os {
/**
* @brief Returns the current process id.
*
@ -476,7 +297,7 @@ struct Utilities {
*
* @return The current process id.
*/
static PidType pid() noexcept;
static pid_type pid() noexcept;
/**
* @brief Returns the parent process id.
@ -487,7 +308,7 @@ struct Utilities {
*
* @return The parent process id.
*/
static PidType parent() noexcept;
static pid_type ppid() noexcept;
/**
* @brief Gets the current user's home directory.
@ -576,7 +397,7 @@ struct Utilities {
*
* @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.
@ -590,7 +411,7 @@ struct Utilities {
*
* @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.
@ -605,7 +426,7 @@ struct Utilities {
* @param pid A valid process id.
* @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.
@ -622,15 +443,15 @@ struct Utilities {
* @param prio The scheduling priority to set to the process.
* @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.
* @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.
@ -643,14 +464,14 @@ struct Utilities {
* @param file A valid descriptor.
* @return One of the following types:
*
* * `HandleType::UNKNOWN`
* * `HandleType::PIPE`
* * `HandleType::TCP`
* * `HandleType::TTY`
* * `HandleType::UDP`
* * `HandleType::FILE`
* * `handle_type::UNKNOWN`
* * `handle_type::PIPE`
* * `handle_type::TCP`
* * `handle_type::TTY`
* * `handle_type::UDP`
* * `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.
*
@ -659,7 +480,7 @@ struct Utilities {
*
* @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.
@ -669,7 +490,7 @@ struct Utilities {
*
* @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
@ -684,7 +505,7 @@ struct Utilities {
* @param index Network interface index.
* @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.
@ -696,7 +517,7 @@ struct Utilities {
* @param index Network interface index.
* @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.
@ -715,19 +536,19 @@ struct Utilities {
* changed while no memory was allocated with the previous allocator, or
* that they are compatible.
*
* @param mallocFunc Replacement function for _malloc_.
* @param reallocFunc Replacement function for _realloc_.
* @param callocFunc Replacement function for _calloc_.
* @param freeFunc Replacement function for _free_.
* @param malloc_func Replacement function for _malloc_.
* @param realloc_func Replacement function for _realloc_.
* @param calloc_func Replacement function for _calloc_.
* @param free_func Replacement function for _free_.
* @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.
* @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.
@ -736,26 +557,26 @@ struct Utilities {
*
* @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.
* @return The process title.
*/
static std::string processTitle();
static std::string process_title();
/**
* @brief Sets the current process title.
* @param title The process title to be set.
* @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).
* @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).
@ -768,7 +589,7 @@ struct Utilities {
*
* @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.
@ -780,7 +601,7 @@ struct Utilities {
* @brief Gets the resource usage measures for the current process.
* @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.
@ -818,7 +639,7 @@ struct Utilities {
* [`gettimeofday`](https://linux.die.net/man/2/gettimeofday)
* @return The current time.
*/
static TimeVal64 timeOfDay() noexcept;
static timeval64 time_of_day() noexcept;
/**
* @brief Causes the calling thread to sleep for a while.
@ -831,7 +652,7 @@ struct Utilities {
* use (always a non-zero value).
* @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.
*/
template<class... Func>
struct Overloaded: Func... {
struct overloaded: Func... {
using Func::operator()...;
};
@ -848,7 +669,7 @@ struct Overloaded: Func... {
* @tparam Func Types of function objects.
*/
template<class... Func>
Overloaded(Func...) -> Overloaded<Func...>;
overloaded(Func...) -> overloaded<Func...>;
} // 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 {
UVW_INLINE WorkReq::WorkReq(ConstructorAccess ca, std::shared_ptr<Loop> ref, InternalTask t)
: Request{ca, std::move(ref)}, task{t} {}
UVW_INLINE work_req::work_req(loop::token token, std::shared_ptr<loop> ref, task t)
: request{token, std::move(ref)}, func{t} {}
UVW_INLINE void WorkReq::workCallback(uv_work_t *req) {
static_cast<WorkReq *>(req->data)->task();
UVW_INLINE void work_req::work_callback(uv_work_t *req) {
static_cast<work_req *>(req->data)->func();
}
UVW_INLINE void WorkReq::queue() {
invoke(&uv_queue_work, parent(), get(), &workCallback, &defaultCallback<WorkEvent>);
UVW_INLINE void work_req::after_work_callback(uv_work_t* req, int status) {
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

View File

@ -9,20 +9,16 @@
namespace uvw {
/**
* @brief WorkEvent event.
*
* It will be emitted by WorkReq according with its functionalities.
*/
struct WorkEvent {};
/*! @brief Work event. */
struct work_event {};
/**
* @brief The WorkReq request.
* @brief The work request.
*
* It runs user code using a thread from the threadpool and gets notified in the
* 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)>`.
*
@ -30,27 +26,28 @@ struct WorkEvent {};
* [documentation](http://docs.libuv.org/en/v1.x/threadpool.html)
* for further details.
*/
class WorkReq final: public Request<WorkReq, uv_work_t> {
using InternalTask = std::function<void(void)>;
static void workCallback(uv_work_t *req);
class work_req final: public request<work_req, uv_work_t, work_event> {
static void work_callback(uv_work_t *req);
static void after_work_callback(uv_work_t *req, int status);
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.
*
* 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/>
* This request can be cancelled with `cancel()`.
*
* @return Underlying return value.
*/
void queue();
int queue();
private:
Task task{};
task func{};
};
} // namespace uvw

View File

@ -95,7 +95,6 @@ ADD_UVW_TEST(check uvw/check.cpp)
ADD_UVW_TEST(emitter uvw/emitter.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_poll uvw/fs_poll.cpp)
ADD_UVW_DIR_TEST(fs_req uvw/fs_req.cpp)
ADD_UVW_TEST(handle uvw/handle.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(tty uvw/tty.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(work uvw/work.cpp)

View File

@ -4,38 +4,38 @@
#include <memory>
#include <uvw.hpp>
void listen(uvw::Loop &loop) {
std::shared_ptr<uvw::TCPHandle> tcp = loop.resource<uvw::TCPHandle>();
tcp->on<uvw::ErrorEvent>([](const uvw::ErrorEvent &, uvw::TCPHandle &) { assert(false); });
void listen(uvw::loop &loop) {
std::shared_ptr<uvw::tcp_handle> tcp = loop.resource<uvw::tcp_handle>();
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::shared_ptr<uvw::TCPHandle> client = srv.loop().resource<uvw::TCPHandle>();
client->on<uvw::ErrorEvent>([](const uvw::ErrorEvent &, uvw::TCPHandle &) { assert(false); });
std::shared_ptr<uvw::tcp_handle> client = srv.parent().resource<uvw::tcp_handle>();
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;
ptr->close();
});
srv.accept(*client);
uvw::Addr local = srv.sock();
uvw::socket_address local = srv.sock();
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;
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 << "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;
int count = 0;
handle.loop().walk([&count](auto &) { ++count; });
handle.parent().walk([&count](auto &) { ++count; });
std::cout << "still alive: " << count << " handles" << std::endl;
handle.close();
});
@ -43,7 +43,7 @@ void listen(uvw::Loop &loop) {
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;
});
@ -51,27 +51,27 @@ void listen(uvw::Loop &loop) {
tcp->listen();
}
void conn(uvw::Loop &loop) {
auto tcp = loop.resource<uvw::TCPHandle>();
tcp->on<uvw::ErrorEvent>([](const uvw::ErrorEvent &, uvw::TCPHandle &) { assert(false); });
void conn(uvw::loop &loop) {
auto tcp = loop.resource<uvw::tcp_handle>();
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;
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;
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;
auto dataWrite = std::unique_ptr<char[]>(new char[2]{'b', 'c'});
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;
});
@ -79,7 +79,7 @@ void conn(uvw::Loop &loop) {
}
void g() {
auto loop = uvw::Loop::getDefault();
auto loop = uvw::loop::get_default();
listen(*loop);
conn(*loop);
loop->run();

View File

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

View File

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

View File

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

View File

@ -4,7 +4,7 @@
struct FakeEvent {};
struct TestEmitter: uvw::Emitter<TestEmitter> {
struct TestEmitter: uvw::emitter<TestEmitter, FakeEvent> {
void emit() {
publish(FakeEvent{});
}
@ -13,136 +13,51 @@ struct TestEmitter: uvw::Emitter<TestEmitter> {
TEST(ErrorEvent, Functionalities) {
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.name(), nullptr);
ASSERT_EQ(event.code(), ecode);
ASSERT_FALSE(static_cast<bool>(uvw::ErrorEvent{0}));
ASSERT_TRUE(static_cast<bool>(uvw::ErrorEvent{ecode}));
ASSERT_FALSE(static_cast<bool>(uvw::error_event{0}));
ASSERT_TRUE(static_cast<bool>(uvw::error_event{ecode}));
}
TEST(Emitter, EmptyAndClear) {
TEST(Emitter, Functionalities) {
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());
ASSERT_FALSE(emitter.empty<uvw::ErrorEvent>());
ASSERT_TRUE(emitter.empty<FakeEvent>());
emitter.reset<FakeEvent>();
emitter.clear<FakeEvent>();
ASSERT_TRUE(emitter.has<uvw::error_event>());
ASSERT_FALSE(emitter.has<FakeEvent>());
ASSERT_FALSE(emitter.empty());
ASSERT_FALSE(emitter.empty<uvw::ErrorEvent>());
ASSERT_TRUE(emitter.empty<FakeEvent>());
emitter.reset<uvw::error_event>();
emitter.clear<uvw::ErrorEvent>();
ASSERT_FALSE(emitter.has<uvw::error_event>());
ASSERT_FALSE(emitter.has<FakeEvent>());
ASSERT_TRUE(emitter.empty());
ASSERT_TRUE(emitter.empty<uvw::ErrorEvent>());
ASSERT_TRUE(emitter.empty<FakeEvent>());
bool sentinel = false;
emitter.on<uvw::error_event>([](const auto &, auto &) {});
emitter.on<FakeEvent>([&](const auto &, auto &) { sentinel = true; });
emitter.on<uvw::ErrorEvent>([](const auto &, auto &) {});
emitter.on<FakeEvent>([](const auto &, auto &) {});
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>());
ASSERT_FALSE(sentinel);
ASSERT_TRUE(emitter.has<uvw::error_event>());
ASSERT_TRUE(emitter.has<FakeEvent>());
emitter.emit();
ASSERT_FALSE(emitter.empty());
ASSERT_FALSE(emitter.empty<FakeEvent>());
}
TEST(Emitter, Once) {
TestEmitter emitter{};
emitter.once<FakeEvent>([](const auto &, auto &) {});
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>());
ASSERT_TRUE(sentinel);
ASSERT_TRUE(emitter.has<uvw::error_event>());
ASSERT_TRUE(emitter.has<FakeEvent>());
emitter.reset();
ASSERT_FALSE(emitter.has<uvw::error_event>());
ASSERT_FALSE(emitter.has<FakeEvent>());
}

View File

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

View File

@ -5,40 +5,49 @@
TEST(FsEvent, Functionalities) {
const std::string filename = std::string{TARGET_FS_EVENT_DIR} + std::string{"/test.file"};
auto loop = uvw::Loop::getDefault();
auto handle = loop->resource<uvw::FsEventHandle>();
auto request = loop->resource<uvw::FileReq>();
auto loop = uvw::loop::get_default();
auto handle = loop->resource<uvw::fs_event_handle>();
auto request = loop->resource<uvw::file_req>();
bool checkFsEventEvent = false;
handle->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); });
request->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); });
handle->on<uvw::error_event>([&](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_EQ(std::string{event.filename}, std::string{"test.file"});
checkFsEventEvent = true;
hndl.stop();
ASSERT_EQ(0, hndl.stop());
hndl.close();
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) {
if(event.type == uvw::fs_req::fs_type::WRITE) {
req.close();
});
request->on<uvw::FsEvent<uvw::FileReq::Type::OPEN>>([](const auto &, auto &req) {
} else if(event.type == uvw::fs_req::fs_type::OPEN) {
req.write(std::unique_ptr<char[]>{new char[1]{42}}, 1, 0);
}
});
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>();
ASSERT_EQ(0, handle->start(std::string{TARGET_FS_EVENT_DIR}, uvw::fs_event_handle::event_flags::RECURSIVE));
auto flags = uvw::file_req::file_open_flags::CREAT | uvw::file_req::file_open_flags::RDWR | uvw::file_req::file_open_flags::TRUNC;
request->open(filename, flags, 0644);
ASSERT_EQ(handle->path(), std::string{TARGET_FS_EVENT_DIR});
ASSERT_TRUE(handle->active());
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();
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;
};
struct FakeHandle: uvw::Handle<FakeHandle, fake_handle_t> {
using Handle::Handle;
struct fake_handle: uvw::handle<fake_handle, fake_handle_t> {
using handle::handle;
template<typename... Args>
bool init(Args &&...) {
return initialize([](auto...) { return true; });
int init() override {
return 1;
}
};
TEST(Handle, Functionalities) {
auto loop = uvw::Loop::getDefault();
auto handle = loop->resource<uvw::AsyncHandle>();
auto loop = uvw::loop::get_default();
auto handle = loop->resource<uvw::async_handle>();
ASSERT_EQ(uvw::Utilities::guessHandle(handle->category()), uvw::HandleType::ASYNC);
ASSERT_EQ(handle->type(), uvw::HandleType::ASYNC);
ASSERT_EQ(uvw::utilities::guess_handle(handle->category()), uvw::handle_type::ASYNC);
ASSERT_EQ(handle->type(), uvw::handle_type::ASYNC);
ASSERT_TRUE(handle->active());
ASSERT_FALSE(handle->closing());
@ -38,18 +37,18 @@ TEST(Handle, Functionalities) {
ASSERT_NE(handle->size(), static_cast<decltype(handle->size())>(0));
ASSERT_EQ(handle->sendBufferSize(), static_cast<decltype(handle->sendBufferSize())>(0));
ASSERT_FALSE(handle->sendBufferSize(0));
ASSERT_LT(handle->send_buffer_size(), 0);
ASSERT_NE(0, handle->send_buffer_size(0));
ASSERT_EQ(handle->recvBufferSize(), static_cast<decltype(handle->recvBufferSize())>(0));
ASSERT_FALSE(handle->recvBufferSize(0));
ASSERT_LT(handle->recv_buffer_size(), 0);
ASSERT_NE(0, handle->recv_buffer_size(0));
ASSERT_NO_THROW(handle->fd());
}
TEST(Handle, InitializationFailure) {
auto loop = uvw::Loop::getDefault();
auto resource = loop->resource<FakeHandle>();
auto loop = uvw::loop::get_default();
auto resource = loop->resource<fake_handle>();
ASSERT_FALSE(static_cast<bool>(resource));
}

View File

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

View File

@ -2,23 +2,23 @@
#include <uvw/lib.h>
TEST(SharedLib, Failure) {
auto loop = uvw::Loop::getDefault();
auto lib = loop->resource<uvw::SharedLib>("foobar.so");
auto loop = uvw::loop::get_default();
auto lib = loop->resource<uvw::shared_lib>("foobar.so");
ASSERT_FALSE(static_cast<bool>(*lib));
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
lib.reset();
}
TEST(SharedLib, Success) {
auto loop = uvw::Loop::getDefault();
auto lib = loop->resource<uvw::SharedLib>(TARGET_LIB_SO);
auto loop = uvw::loop::get_default();
auto lib = loop->resource<uvw::shared_lib>(TARGET_LIB_SO);
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_NE(lib->sym<int(double *)>("fake_func"), nullptr);
double d{1.};

View File

@ -1,29 +1,28 @@
#include <gtest/gtest.h>
#include <uvw/loop.h>
#include <uvw/prepare.h>
#include <uvw/work.h>
#include <uvw.hpp>
TEST(Loop, DefaultLoop) {
auto def = uvw::Loop::getDefault();
auto def = uvw::loop::get_default();
ASSERT_TRUE(static_cast<bool>(def));
ASSERT_FALSE(def->alive());
ASSERT_NO_THROW(def->stop());
def->walk([](auto &) { FAIL(); });
auto def2 = uvw::loop::get_default();
auto def2 = uvw::Loop::getDefault();
ASSERT_EQ(def, def2);
ASSERT_EQ(0, def->close());
}
TEST(Loop, Functionalities) {
auto loop = uvw::Loop::create();
auto handle = loop->resource<uvw::PrepareHandle>();
auto req = loop->resource<uvw::WorkReq>([] {});
auto loop = uvw::loop::create();
auto handle = loop->resource<uvw::prepare_handle>();
auto req = loop->resource<uvw::work_req>([] {});
loop->on<uvw::ErrorEvent>([](auto &&...) { FAIL(); });
req->on<uvw::ErrorEvent>([](auto &&...) { FAIL(); });
handle->on<uvw::ErrorEvent>([](auto &&...) { FAIL(); });
loop->on<uvw::error_event>([](auto &&...) { FAIL(); });
req->on<uvw::error_event>([](auto &&...) { FAIL(); });
handle->on<uvw::error_event>([](auto &&...) { FAIL(); });
ASSERT_TRUE(static_cast<bool>(handle));
ASSERT_TRUE(static_cast<bool>(req));
@ -34,15 +33,15 @@ TEST(Loop, Functionalities) {
#ifndef _MSC_VER
// 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
ASSERT_FALSE(loop->alive());
ASSERT_FALSE(loop->timeout().first);
handle->start();
handle->on<uvw::PrepareEvent>([](const auto &, auto &hndl) {
hndl.loop().walk([](auto &) {
handle->on<uvw::prepare_event>([](const auto &, auto &hndl) {
hndl.parent().walk([](auto &) {
static bool trigger = true;
ASSERT_TRUE(trigger);
trigger = false;
@ -52,18 +51,52 @@ TEST(Loop, Functionalities) {
});
ASSERT_TRUE(loop->alive());
ASSERT_NO_THROW(loop->run());
ASSERT_EQ(0, loop->run());
loop->walk([](auto &) { FAIL(); });
ASSERT_NO_THROW(loop->run<uvw::Loop::Mode::ONCE>());
ASSERT_NO_THROW(loop->run<uvw::Loop::Mode::NOWAIT>());
ASSERT_EQ(0, loop->run(uvw::loop::run_mode::ONCE));
ASSERT_EQ(0, loop->run(uvw::loop::run_mode::NOWAIT));
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) {
auto loop = uvw::Loop::create();
auto loop = uvw::loop::create();
loop->data(std::make_shared<int>(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(*loop->data<int>(), 42);
ASSERT_EQ(0, loop->close());
}
TEST(Loop, Configure) {
auto loop = uvw::Loop::create();
ASSERT_NO_THROW(loop->configure(uvw::Loop::Configure::BLOCK_SIGNAL, 9));
ASSERT_NO_THROW(loop->run());
auto loop = uvw::loop::create();
ASSERT_EQ(0, loop->configure(uvw::loop::option::IDLE_TIME));
ASSERT_EQ(0, loop->run());
ASSERT_EQ(0, loop->close());
}
TEST(Loop, IdleTime) {
auto loop = uvw::Loop::create();
loop->configure(uvw::Loop::Configure::IDLE_TIME);
ASSERT_EQ(loop->idleTime().count(), 0u);
auto loop = uvw::loop::create();
loop->configure(uvw::loop::option::IDLE_TIME);
ASSERT_EQ(loop->idle_time().count(), 0u);
ASSERT_EQ(0, loop->close());
}
TEST(Loop, Raw) {
auto loop = uvw::Loop::getDefault();
const auto &cloop = uvw::Loop::getDefault();
auto loop = uvw::loop::get_default();
const auto &cloop = uvw::loop::get_default();
auto *raw = loop->raw();
auto *craw = cloop->raw();
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"};
#endif
auto loop = uvw::Loop::getDefault();
auto server = loop->resource<uvw::PipeHandle>();
auto client = loop->resource<uvw::PipeHandle>();
auto loop = uvw::loop::get_default();
auto server = loop->resource<uvw::pipe_handle>();
auto client = loop->resource<uvw::pipe_handle>();
server->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); });
client->on<uvw::ErrorEvent>([](const auto &, auto &) {
FAIL();
server->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
client->on<uvw::error_event>([](const auto &, auto &) { 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) {
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) {
client->on<uvw::write_event>([](const uvw::write_event &, uvw::pipe_handle &handle) {
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.readable());
@ -41,8 +39,9 @@ TEST(Pipe, ReadWrite) {
});
server->bind(sockname);
server->listen();
client->connect(sockname);
ASSERT_EQ(0, server->listen());
ASSERT_EQ(0, client->connect(sockname));
loop->run();
}
@ -56,35 +55,35 @@ TEST(Pipe, SockPeer) {
const auto peername = sockname;
#endif
auto loop = uvw::Loop::getDefault();
auto server = loop->resource<uvw::PipeHandle>();
auto client = loop->resource<uvw::PipeHandle>();
auto loop = uvw::loop::get_default();
auto server = loop->resource<uvw::pipe_handle>();
auto client = loop->resource<uvw::pipe_handle>();
server->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); });
client->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); });
server->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
client->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
server->once<uvw::ListenEvent>([&peername](const uvw::ListenEvent &, uvw::PipeHandle &handle) {
std::shared_ptr<uvw::PipeHandle> socket = handle.loop().resource<uvw::PipeHandle>();
server->on<uvw::listen_event>([&peername](const uvw::listen_event &, uvw::pipe_handle &handle) {
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::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();
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());
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);
handle.close();
});
server->bind(sockname);
server->listen();
client->connect(sockname);
ASSERT_EQ(0, server->listen());
ASSERT_EQ(0, client->connect(sockname));
loop->run();
}
@ -98,36 +97,38 @@ TEST(Pipe, Shutdown) {
auto data = std::unique_ptr<char[]>(new char[3]{'a', 'b', 'c'});
auto loop = uvw::Loop::getDefault();
auto server = loop->resource<uvw::PipeHandle>();
auto client = loop->resource<uvw::PipeHandle>();
auto loop = uvw::loop::get_default();
auto server = loop->resource<uvw::pipe_handle>();
auto client = loop->resource<uvw::pipe_handle>();
server->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); });
client->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); });
server->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
client->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
server->once<uvw::ListenEvent>([](const uvw::ListenEvent &, uvw::PipeHandle &handle) {
std::shared_ptr<uvw::PipeHandle> socket = handle.loop().resource<uvw::PipeHandle>();
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::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(); });
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(); });
handle.accept(*socket);
socket->read();
ASSERT_EQ(0, handle.accept(*socket));
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();
});
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.shutdown();
ASSERT_EQ(0, handle.shutdown());
});
server->bind(sockname);
server->listen();
client->connect(sockname);
ASSERT_EQ(0, server->listen());
ASSERT_EQ(0, client->connect(sockname));
loop->run();
}

View File

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

View File

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

View File

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

View File

@ -4,19 +4,17 @@
#include <uvw/async.h>
#include <uvw/request.hpp>
struct Res: uvw::Resource<Res, int> {};
TEST(Resource, Functionalities) {
ASSERT_FALSE(std::is_copy_constructible<uvw::AsyncHandle>::value);
ASSERT_FALSE(std::is_copy_assignable<uvw::AsyncHandle>::value);
ASSERT_FALSE(std::is_copy_constructible<uvw::async_handle>::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_assignable<uvw::AsyncHandle>::value);
ASSERT_FALSE(std::is_move_constructible<uvw::async_handle>::value);
ASSERT_FALSE(std::is_move_assignable<uvw::async_handle>::value);
auto loop = uvw::Loop::getDefault();
auto resource = loop->resource<uvw::AsyncHandle>();
auto loop = uvw::loop::get_default();
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));

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,29 +3,31 @@
#include <uvw/tty.h>
TEST(TTY, Functionalities) {
auto loop = uvw::Loop::getDefault();
auto handle = loop->resource<uvw::TTYHandle>(uvw::StdOUT, false);
auto timer = loop->resource<uvw::TimerHandle>();
auto loop = uvw::loop::get_default();
auto handle = loop->resource<uvw::tty_handle>(uvw::std_out, false);
auto timer = loop->resource<uvw::timer_handle>();
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);
checkWriteEvent = true;
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[]>('*');
handle->write(std::move(data), 1);
ASSERT_EQ(0, (handle->write(std::move(data), 1)));
hndl.close();
});
ASSERT_TRUE(handle->reset());
ASSERT_TRUE(!handle->readable() || handle->mode(uvw::TTYHandle::Mode::NORMAL));
ASSERT_NO_THROW(handle->getWinSize());
ASSERT_TRUE(handle->reset_mode());
ASSERT_TRUE(!handle->readable() || handle->mode(uvw::tty_handle::tty_mode::NORMAL));
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();
ASSERT_TRUE(checkWriteEvent);

View File

@ -2,15 +2,15 @@
#include <uvw/udp.h>
TEST(UDP, Functionalities) {
auto loop = uvw::Loop::getDefault();
auto handle = loop->resource<uvw::UDPHandle>();
auto loop = uvw::loop::get_default();
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_TRUE(handle->multicastMembership("224.0.0.1", "127.0.0.1", uvw::UDPHandle::Membership::JOIN_GROUP));
ASSERT_TRUE(handle->multicastMembership("224.0.0.1", "127.0.0.1", uvw::UDPHandle::Membership::LEAVE_GROUP));
ASSERT_TRUE(handle->multicastLoop(true));
ASSERT_TRUE(handle->multicastTtl(42));
ASSERT_TRUE(handle->multicastInterface("127.0.0.1"));
ASSERT_FALSE(handle->multicast_membership("0.0.0.0", "127.0.0.1", uvw::udp_handle::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->multicast_membership("224.0.0.1", "127.0.0.1", uvw::udp_handle::membership::LEAVE_GROUP));
ASSERT_TRUE(handle->multicast_loop(true));
ASSERT_TRUE(handle->multicast_ttl(42));
ASSERT_TRUE(handle->multicast_interface("127.0.0.1"));
ASSERT_TRUE(handle->broadcast(true));
ASSERT_TRUE(handle->ttl(42));
ASSERT_FALSE(handle->ttl(0));
@ -23,14 +23,15 @@ TEST(UDP, BindRecvStop) {
const std::string address = std::string{"127.0.0.1"};
const unsigned int port = 4242;
auto loop = uvw::Loop::getDefault();
auto handle = loop->resource<uvw::UDPHandle>();
auto loop = uvw::loop::get_default();
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();
loop->run();
@ -40,28 +41,28 @@ TEST(UDP, ReadTrySend) {
const std::string address = std::string{"127.0.0.1"};
const unsigned int port = 4242;
auto loop = uvw::Loop::getDefault();
auto server = loop->resource<uvw::UDPHandle>();
auto client = loop->resource<uvw::UDPHandle>();
auto loop = uvw::loop::get_default();
auto server = loop->resource<uvw::udp_handle>();
auto client = loop->resource<uvw::udp_handle>();
server->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); });
client->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); });
server->on<uvw::error_event>([](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();
handle.close();
});
server->bind(uvw::Addr{address, port});
server->recv();
ASSERT_EQ(0, (server->bind(uvw::socket_address{address, port})));
ASSERT_EQ(0, server->recv());
auto dataTrySend = std::unique_ptr<char[]>(new char[1]{'a'});
client->trySend(uvw::Addr{address, port}, dataTrySend.get(), 1);
client->trySend(address, port, nullptr, 0);
ASSERT_EQ(1, client->try_send(uvw::socket_address{address, port}, dataTrySend.get(), 1));
ASSERT_EQ(0, client->try_send(address, port, nullptr, 0));
client->trySend(uvw::Addr{address, port}, std::move(dataTrySend), 1);
client->trySend(address, port, std::unique_ptr<char[]>{}, 0);
ASSERT_EQ(1, client->try_send(uvw::socket_address{address, port}, std::move(dataTrySend), 1));
ASSERT_EQ(0, client->try_send(address, port, std::unique_ptr<char[]>{}, 0));
loop->run();
}
@ -70,30 +71,30 @@ TEST(UDP, ReadSend) {
const std::string address = std::string{"127.0.0.1"};
const unsigned int port = 4242;
auto loop = uvw::Loop::getDefault();
auto server = loop->resource<uvw::UDPHandle>();
auto client = loop->resource<uvw::UDPHandle>();
auto loop = uvw::loop::get_default();
auto server = loop->resource<uvw::udp_handle>();
auto client = loop->resource<uvw::udp_handle>();
server->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); });
client->on<uvw::ErrorEvent>([](const auto &, auto &) { FAIL(); });
server->on<uvw::error_event>([](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();
});
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();
});
server->bind(address, port);
server->recv();
ASSERT_EQ(0, (server->bind(address, port)));
ASSERT_EQ(0, server->recv());
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(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);
loop->run();
@ -103,15 +104,16 @@ TEST(UDP, Sock) {
const std::string address = std::string{"127.0.0.1"};
const unsigned int port = 4242;
auto loop = uvw::Loop::getDefault();
auto handle = loop->resource<uvw::UDPHandle>();
auto loop = uvw::loop::get_default();
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->recv();
uvw::Addr sock = handle->sock();
uvw::socket_address sock = handle->sock();
ASSERT_EQ(sock.ip, address);
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>
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) {
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::parent(), uvw::PidType{});
ASSERT_FALSE(uvw::Utilities::OS::homedir().empty());
ASSERT_FALSE(uvw::Utilities::OS::tmpdir().empty());
ASSERT_NE(uvw::Utilities::OS::hostname(), "");
ASSERT_NE(uvw::utilities::os::pid(), uvw::pid_type{});
ASSERT_NE(uvw::utilities::os::ppid(), uvw::pid_type{});
ASSERT_FALSE(uvw::utilities::os::homedir().empty());
ASSERT_FALSE(uvw::utilities::os::tmpdir().empty());
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", ""));
ASSERT_FALSE(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_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_FALSE(passwd.username().empty());
@ -105,67 +33,67 @@ TEST(Util, Utilities) {
ASSERT_FALSE(passwd.shell().empty());
#endif
ASSERT_EQ(uvw::Utilities::guessHandle(uvw::FileHandle{-1}), uvw::HandleType::UNKNOWN);
ASSERT_NE(uvw::Utilities::guessHandle(uvw::StdIN), uvw::HandleType::UNKNOWN);
ASSERT_EQ(uvw::utilities::guess_handle(uvw::file_handle{-1}), uvw::handle_type::UNKNOWN);
ASSERT_NE(uvw::utilities::guess_handle(uvw::std_in), uvw::handle_type::UNKNOWN);
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>();
ASSERT_EQ(uvw::Utilities::guessHandle(handle->category()), type);
ASSERT_EQ(uvw::utilities::guess_handle(handle->category()), type);
handle->close();
loop->run();
};
guessHandle(tag<uvw::AsyncHandle>{}, uvw::HandleType::ASYNC);
guessHandle(tag<uvw::CheckHandle>{}, uvw::HandleType::CHECK);
guessHandle(tag<uvw::FsEventHandle>{}, uvw::HandleType::FS_EVENT);
guessHandle(tag<uvw::FsPollHandle>{}, uvw::HandleType::FS_POLL);
guessHandle(tag<uvw::IdleHandle>{}, uvw::HandleType::IDLE);
guessHandle(tag<uvw::PipeHandle>{}, uvw::HandleType::PIPE);
guessHandle(tag<uvw::PrepareHandle>{}, uvw::HandleType::PREPARE);
guessHandle(tag<uvw::TCPHandle>{}, uvw::HandleType::TCP);
guessHandle(tag<uvw::TimerHandle>{}, uvw::HandleType::TIMER);
guessHandle(tag<uvw::UDPHandle>{}, uvw::HandleType::UDP);
guessHandle(tag<uvw::SignalHandle>{}, uvw::HandleType::SIGNAL);
guessHandle(tag<uvw::async_handle>{}, uvw::handle_type::ASYNC);
guessHandle(tag<uvw::check_handle>{}, uvw::handle_type::CHECK);
guessHandle(tag<uvw::fs_event_handle>{}, uvw::handle_type::FS_EVENT);
guessHandle(tag<uvw::fs_poll_handle>{}, uvw::handle_type::FS_POLL);
guessHandle(tag<uvw::idle_handle>{}, uvw::handle_type::IDLE);
guessHandle(tag<uvw::pipe_handle>{}, uvw::handle_type::PIPE);
guessHandle(tag<uvw::prepare_handle>{}, uvw::handle_type::PREPARE);
guessHandle(tag<uvw::tcp_handle>{}, uvw::handle_type::TCP);
guessHandle(tag<uvw::timer_handle>{}, uvw::handle_type::TIMER);
guessHandle(tag<uvw::udp_handle>{}, uvw::handle_type::UDP);
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_FALSE(cpuInfo[0].model.empty());
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_FALSE(interfaceAddresses[0].name.empty());
ASSERT_FALSE(interfaceAddresses[0].address.ip.empty());
ASSERT_FALSE(interfaceAddresses[0].netmask.ip.empty());
ASSERT_NO_THROW(uvw::Utilities::indexToName(0));
ASSERT_NO_THROW(uvw::Utilities::indexToIid(0));
ASSERT_NO_THROW(uvw::utilities::index_to_name(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); },
[](void *ptr, size_t size) { return realloc(ptr, size); },
[](size_t num, size_t size) { return calloc(num, size); },
[](void *ptr) { return free(ptr); }));
ASSERT_NO_THROW(uvw::Utilities::loadAverage());
ASSERT_NE(uvw::Utilities::totalMemory(), decltype(uvw::Utilities::totalMemory()){0});
ASSERT_NE(uvw::Utilities::uptime(), decltype(uvw::Utilities::uptime()){0});
ASSERT_NO_THROW(uvw::Utilities::rusage());
ASSERT_NE(uvw::Utilities::hrtime(), decltype(uvw::Utilities::hrtime()){0});
ASSERT_FALSE(uvw::Utilities::path().empty());
ASSERT_FALSE(uvw::Utilities::cwd().empty());
ASSERT_TRUE(uvw::Utilities::chdir(uvw::Utilities::cwd()));
ASSERT_NO_THROW(uvw::utilities::load_average());
ASSERT_NE(uvw::utilities::total_memory(), decltype(uvw::utilities::total_memory()){0});
ASSERT_NE(uvw::utilities::uptime(), decltype(uvw::utilities::uptime()){0});
ASSERT_NO_THROW(uvw::utilities::rusage());
ASSERT_NE(uvw::utilities::hrtime(), decltype(uvw::utilities::hrtime()){0});
ASSERT_FALSE(uvw::utilities::path().empty());
ASSERT_FALSE(uvw::utilities::cwd().empty());
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); }};
char *argv = fake.get();
argv[0] = '\0';
ASSERT_NE(uvw::Utilities::setupArgs(1, &argv), nullptr);
ASSERT_NE(uvw::Utilities::processTitle(), std::string{});
ASSERT_TRUE(uvw::Utilities::processTitle(uvw::Utilities::processTitle()));
ASSERT_NE(uvw::utilities::setup_args(1, &argv), nullptr);
ASSERT_NE(uvw::utilities::process_title(), std::string{});
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>
TEST(Work, RunTask) {
auto loop = uvw::Loop::getDefault();
auto handle = loop->resource<uvw::CheckHandle>();
auto loop = uvw::loop::get_default();
auto handle = loop->resource<uvw::check_handle>();
bool checkTask = false;
auto req = loop->resource<uvw::WorkReq>([&checkTask]() {
auto req = loop->resource<uvw::work_req>([&checkTask]() {
ASSERT_FALSE(checkTask);
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->start();
req->queue();
ASSERT_EQ(0, req->queue());
loop->run();
ASSERT_TRUE(checkTask);
}
TEST(Work, Cancellation) {
auto loop = uvw::Loop::getDefault();
auto handle = loop->resource<uvw::TimerHandle>();
auto loop = uvw::loop::get_default();
auto handle = loop->resource<uvw::timer_handle>();
bool checkErrorEvent = false;
handle->on<uvw::TimerEvent>([](const auto &, auto &hndl) {
handle->on<uvw::timer_event>([](const auto &, auto &hndl) {
hndl.stop();
hndl.close();
});
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::ErrorEvent>([&checkErrorEvent](const auto &, auto &) { checkErrorEvent = true; });
req->on<uvw::work_event>([](const auto &, auto &) {});
req->on<uvw::error_event>([&checkErrorEvent](const auto &, auto &) { checkErrorEvent = true; });
req->queue();
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();
ASSERT_TRUE(checkErrorEvent);