uvw v3 (#263)
This commit is contained in:
parent
3636701fc2
commit
70697f4ae9
@ -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
30
.github/workflows/sanitizer.yml
vendored
Normal 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
|
||||
@ -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
129
README.md
@ -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
5
TODO
Normal 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
|
||||
@ -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"
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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.
|
||||
*
|
||||
* It’s 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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
119
src/uvw/dns.h
119
src/uvw/dns.h
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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
76
src/uvw/enum.hpp
Normal 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
|
||||
519
src/uvw/fs.cpp
519
src/uvw/fs.cpp
@ -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);
|
||||
}
|
||||
|
||||
|
||||
800
src/uvw/fs.h
800
src/uvw/fs.h
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 can’t.
|
||||
* 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 can’t.
|
||||
*
|
||||
* 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.
|
||||
|
||||
@ -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 it’s 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 doesn’t 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 doesn’t 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;
|
||||
}
|
||||
};
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
152
src/uvw/loop.cpp
152
src/uvw/loop.cpp
@ -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
|
||||
|
||||
244
src/uvw/loop.h
244
src/uvw/loop.h
@ -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 don’t 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 don’t 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 loop’s callbacks in another.
|
||||
* This can be used in conjunction with `run(loop::run_mode::NOWAIT)` to
|
||||
* poll in one thread and run the event loop’s 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 loop’s 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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
* it’s required that it represents a valid pipe.<br/>
|
||||
* An ErrorEvent event is emitted in case of errors.
|
||||
* it’s 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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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
|
||||
|
||||
356
src/uvw/stream.h
356
src/uvw/stream.h
@ -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 won’t queue a write request if it can’t 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 won’t queue a write request if it can’t 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());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
108
src/uvw/tcp.cpp
108
src/uvw/tcp.cpp
@ -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
|
||||
|
||||
160
src/uvw/tcp.h
160
src/uvw/tcp.h
@ -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
|
||||
* it’s 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 Nagle’s 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
|
||||
|
||||
@ -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(), ¶ms, &createCallback, this));
|
||||
return (0 == uv_thread_create_ex(raw(), ¶ms, &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
|
||||
|
||||
152
src/uvw/thread.h
152
src/uvw/thread.h
@ -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 (it’s 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.
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
};
|
||||
|
||||
|
||||
@ -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 {
|
||||
|
||||
|
||||
307
src/uvw/udp.cpp
307
src/uvw/udp.cpp
@ -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
|
||||
|
||||
462
src/uvw/udp.h
462
src/uvw/udp.h
@ -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 won’t queue a send request if it can’t 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 won’t queue a send request if it can’t 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
|
||||
|
||||
@ -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
|
||||
269
src/uvw/util.cpp
269
src/uvw/util.cpp
@ -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();
|
||||
}
|
||||
|
||||
|
||||
363
src/uvw/util.h
363
src/uvw/util.h
@ -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 don’t 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 library’s 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
89
src/uvw/uv_type.hpp
Normal 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
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
@ -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>());
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
@ -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));
|
||||
}
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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.};
|
||||
|
||||
@ -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());
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
@ -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));
|
||||
|
||||
|
||||
@ -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());
|
||||
|
||||
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
146
test/uvw/tcp.cpp
146
test/uvw/tcp.cpp
@ -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);
|
||||
}
|
||||
|
||||
@ -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();
|
||||
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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});
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
@ -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
22
test/uvw/uv_type.cpp
Normal 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);
|
||||
}
|
||||
@ -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);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user