simpler emitter, better compile-time
This commit is contained in:
parent
ba337a7104
commit
3d3790c06c
36
README.md
36
README.md
@ -329,10 +329,10 @@ No need to keep track of them.
|
|||||||
|
|
||||||
## The event-based approach
|
## The event-based approach
|
||||||
|
|
||||||
`uvw` offers an event-based approach, so resources are small event emitters
|
`uvw` offers an event-based approach where resources are small event emitters to
|
||||||
to which listeners can be attached.<br/>
|
which listeners are attached.<br/>
|
||||||
Attaching a listener to a resource is the recommended way to be notified about
|
Attaching listeners to resources is the recommended way to receive notifications
|
||||||
changes.<br/>
|
about their operations.<br/>
|
||||||
Listeners are callable objects of type `void(event_type &, resource_type &)`,
|
Listeners are callable objects of type `void(event_type &, resource_type &)`,
|
||||||
where:
|
where:
|
||||||
|
|
||||||
@ -346,24 +346,18 @@ It means that the following function types are all valid:
|
|||||||
* `void(event_type &, const resource_type &)`
|
* `void(event_type &, const resource_type &)`
|
||||||
* `void(const 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:
|
Please note that there is no need to keep around references to the resources,
|
||||||
they will pass themselves as an argument whenever an event is published.
|
since they pass themselves as an argument whenever an event is published.<br/>
|
||||||
|
The `on` member function is the way to go to register long-running listeners:
|
||||||
|
|
||||||
There exist two methods to attach a listener to a resource:
|
```cpp
|
||||||
|
resource.on<event_type>(listener)
|
||||||
|
```
|
||||||
|
|
||||||
* `resource.once<event_type>(listener)`: the listener will be automatically
|
To know if a listener exists for a given type, the class offers a `has` function
|
||||||
removed after the first event of the given type.
|
template. Similarly, the `reset` function template is be used to reset and thus
|
||||||
* `resource.on<event_type>(listener)`: to be used for long-running listeners.
|
disconnect listeners, if any. A non-template version of `reset` also exists to
|
||||||
|
clear an emitter as a whole.
|
||||||
Both of them return an object of type `resource_type::connection` (as an
|
|
||||||
example, `tcp_handle::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 `error_event` 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
|
All the other events are specific for the given resource and documented in the
|
||||||
@ -379,7 +373,7 @@ tcp->on<uvw::error_event>([](const uvw::error_event &, uvw::tcp_handle &) { /* s
|
|||||||
|
|
||||||
tcp->on<uvw::listen_event>([](const uvw::listen_event &, uvw::tcp_handle &srv) {
|
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>();
|
std::shared_ptr<uvw::tcp_handle> client = srv.parent().resource<uvw::tcp_handle>();
|
||||||
client->once<uvw::end_event>([](const uvw::end_event &, uvw::tcp_handle &client) { client.close(); });
|
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 */ });
|
client->on<uvw::data_event>([](const uvw::data_event &, uvw::tcp_handle &) { /* data received */ });
|
||||||
srv.accept(*client);
|
srv.accept(*client);
|
||||||
client->read();
|
client->read();
|
||||||
|
|||||||
@ -83,91 +83,32 @@ template<typename T>
|
|||||||
class emitter {
|
class emitter {
|
||||||
struct base_handler {
|
struct base_handler {
|
||||||
virtual ~base_handler() UVW_NOEXCEPT = default;
|
virtual ~base_handler() UVW_NOEXCEPT = default;
|
||||||
virtual bool empty() const UVW_NOEXCEPT = 0;
|
virtual bool has() const UVW_NOEXCEPT = 0;
|
||||||
virtual void clear() UVW_NOEXCEPT = 0;
|
virtual void reset() UVW_NOEXCEPT = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename E>
|
template<typename E>
|
||||||
struct event_handler final: base_handler {
|
struct event_handler final: base_handler {
|
||||||
using listener = std::function<void(E &, T &)>;
|
bool has() const UVW_NOEXCEPT override {
|
||||||
using listener_list = std::list<std::pair<bool, listener>>;
|
return static_cast<bool>(listener);
|
||||||
using connection = typename listener_list::iterator;
|
|
||||||
|
|
||||||
bool empty() const UVW_NOEXCEPT override {
|
|
||||||
for(auto &&curr: once_list) {
|
|
||||||
if(!curr.first) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto &&curr: on_list) {
|
void reset() UVW_NOEXCEPT override {
|
||||||
if(!curr.first) {
|
listener = nullptr;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear() UVW_NOEXCEPT override {
|
void on(std::function<void(E &, T &)> func) {
|
||||||
if(publishing) {
|
listener = std::move(func);
|
||||||
for(auto &&curr: once_list) {
|
|
||||||
curr.first = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(auto &&curr: on_list) {
|
|
||||||
curr.first = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
once_list.clear();
|
|
||||||
on_list.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
connection once(listener f) {
|
|
||||||
return once_list.emplace(once_list.cend(), false, std::move(f));
|
|
||||||
}
|
|
||||||
|
|
||||||
connection on(listener f) {
|
|
||||||
return on_list.emplace(on_list.cend(), false, std::move(f));
|
|
||||||
}
|
|
||||||
|
|
||||||
void erase(connection conn) UVW_NOEXCEPT {
|
|
||||||
conn->first = true;
|
|
||||||
|
|
||||||
if(!publishing) {
|
|
||||||
auto pred = [](auto &&elem) { return elem.first; };
|
|
||||||
once_list.remove_if(pred);
|
|
||||||
on_list.remove_if(pred);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void publish(E event, T &ref) {
|
void publish(E event, T &ref) {
|
||||||
listener_list curr;
|
if(listener) {
|
||||||
once_list.swap(curr);
|
listener(event, ref);
|
||||||
|
|
||||||
publishing = true;
|
|
||||||
|
|
||||||
for(auto first = on_list.rbegin(), last = on_list.rend(); first != last; ++first) {
|
|
||||||
if(!first->first) {
|
|
||||||
first->second(event, ref);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto first = curr.rbegin(), last = curr.rend(); first != last; ++first) {
|
|
||||||
if(!first->first) {
|
|
||||||
first->second(event, ref);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
publishing = false;
|
|
||||||
|
|
||||||
on_list.remove_if([](auto &&elem) { return elem.first; });
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool publishing{false};
|
std::function<void(E &, T &)> listener;
|
||||||
listener_list once_list{};
|
|
||||||
listener_list on_list{};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename E>
|
template<typename E>
|
||||||
@ -188,32 +129,6 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
template<typename E>
|
|
||||||
using listener = typename event_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 event_handler<E>::connection {
|
|
||||||
template<typename>
|
|
||||||
friend class emitter;
|
|
||||||
|
|
||||||
connection() = default;
|
|
||||||
connection(const connection &) = default;
|
|
||||||
connection(connection &&) = default;
|
|
||||||
|
|
||||||
connection(typename event_handler<E>::connection conn)
|
|
||||||
: event_handler<E>::connection{std::move(conn)} {}
|
|
||||||
|
|
||||||
connection &operator=(const connection &) = default;
|
|
||||||
connection &operator=(connection &&) = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
virtual ~emitter() UVW_NOEXCEPT {
|
virtual ~emitter() UVW_NOEXCEPT {
|
||||||
static_assert(std::is_base_of_v<emitter<T>, T>);
|
static_assert(std::is_base_of_v<emitter<T>, T>);
|
||||||
}
|
}
|
||||||
@ -221,93 +136,44 @@ public:
|
|||||||
/**
|
/**
|
||||||
* @brief Registers a long-lived listener with the event emitter.
|
* @brief Registers a long-lived listener with the event emitter.
|
||||||
*
|
*
|
||||||
* This method can be used to register a listener that is meant to be
|
* This method is used to register a listener with the emitter.<br/>
|
||||||
* invoked more than once for the given event type.<br/>
|
|
||||||
* The connection object returned by the method can be freely discarded. It
|
|
||||||
* can be used later to disconnect the listener, if needed.
|
|
||||||
*
|
|
||||||
* A listener is usually defined as a callable object assignable to a
|
* 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
|
* `std::function<void(const E &, T &)`, where `E` is the type of the event
|
||||||
* and `T` is the type of the resource.
|
* and `T` is the type of the resource.
|
||||||
*
|
*
|
||||||
* @param f A valid listener to be registered.
|
* @param f A valid listener to be registered.
|
||||||
* @return Connection object to be used later to disconnect the listener.
|
|
||||||
*/
|
*/
|
||||||
template<typename E>
|
template<typename E>
|
||||||
connection<E> on(listener<E> f) {
|
void on(std::function<void(E &, T &)> f) {
|
||||||
return handler<E>().on(std::move(f));
|
return handler<E>().on(std::move(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Registers a short-lived listener with the event emitter.
|
* @brief Disconnects the listener for the given event type.
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* 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>
|
template<typename E>
|
||||||
connection<E> once(listener<E> f) {
|
void reset() UVW_NOEXCEPT {
|
||||||
return handler<E>().once(std::move(f));
|
handler<E>().reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Disconnects a listener from the event emitter.
|
* @brief Disconnects all listeners.
|
||||||
* @param conn A valid connection object
|
|
||||||
*/
|
*/
|
||||||
template<typename E>
|
void reset() UVW_NOEXCEPT {
|
||||||
void erase(connection<E> conn) UVW_NOEXCEPT {
|
|
||||||
handler<E>().erase(std::move(conn));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Disconnects all the listeners for the given event type.
|
|
||||||
*/
|
|
||||||
template<typename E>
|
|
||||||
void clear() UVW_NOEXCEPT {
|
|
||||||
handler<E>().clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Disconnects all the listeners.
|
|
||||||
*/
|
|
||||||
void clear() UVW_NOEXCEPT {
|
|
||||||
for(auto &&curr: handlers) {
|
for(auto &&curr: handlers) {
|
||||||
curr.second->clear();
|
curr.second->reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Checks if there are listeners registered for the specific event.
|
* @brief Checks if there is a listener registered for the specific event.
|
||||||
* @return True if there are no listeners registered for the specific event,
|
* @return True if there is a listener registered for the specific event,
|
||||||
* false otherwise.
|
* false otherwise.
|
||||||
*/
|
*/
|
||||||
template<typename E>
|
template<typename E>
|
||||||
bool empty() const UVW_NOEXCEPT {
|
bool has() const UVW_NOEXCEPT {
|
||||||
const auto id = type<E>();
|
const auto id = type<E>();
|
||||||
return (!handlers.count(id) || static_cast<event_handler<E> &>(*handlers.at(id)).empty());
|
return (handlers.count(id) && static_cast<event_handler<E> &>(*handlers.at(id)).has());
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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 UVW_NOEXCEPT {
|
|
||||||
for(auto &&curr: handlers) {
|
|
||||||
if(!curr.second->empty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@ -32,8 +32,8 @@ UVW_INLINE void pipe_handle::connect(const std::string &name) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
auto connect = parent().resource<details::connect_req>();
|
auto connect = parent().resource<details::connect_req>();
|
||||||
connect->once<error_event>(listener);
|
connect->on<error_event>(listener);
|
||||||
connect->once<connect_event>(listener);
|
connect->on<connect_event>(listener);
|
||||||
connect->connect(&uv_pipe_connect, raw(), name.data());
|
connect->connect(&uv_pipe_connect, raw(), name.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -175,8 +175,8 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
auto shutdown = this->parent().template resource<details::shutdown_req>();
|
auto shutdown = this->parent().template resource<details::shutdown_req>();
|
||||||
shutdown->template once<error_event>(listener);
|
shutdown->template on<error_event>(listener);
|
||||||
shutdown->template once<shutdown_event>(listener);
|
shutdown->template on<shutdown_event>(listener);
|
||||||
shutdown->shutdown(as_uv_stream());
|
shutdown->shutdown(as_uv_stream());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,8 +265,8 @@ public:
|
|||||||
ptr->publish(event);
|
ptr->publish(event);
|
||||||
};
|
};
|
||||||
|
|
||||||
req->template once<error_event>(listener);
|
req->template on<error_event>(listener);
|
||||||
req->template once<write_event>(listener);
|
req->template on<write_event>(listener);
|
||||||
req->write(as_uv_stream());
|
req->write(as_uv_stream());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,8 +288,8 @@ public:
|
|||||||
ptr->publish(event);
|
ptr->publish(event);
|
||||||
};
|
};
|
||||||
|
|
||||||
req->template once<error_event>(listener);
|
req->template on<error_event>(listener);
|
||||||
req->template once<write_event>(listener);
|
req->template on<write_event>(listener);
|
||||||
req->write(as_uv_stream());
|
req->write(as_uv_stream());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -319,8 +319,8 @@ public:
|
|||||||
ptr->publish(event);
|
ptr->publish(event);
|
||||||
};
|
};
|
||||||
|
|
||||||
req->template once<error_event>(listener);
|
req->template on<error_event>(listener);
|
||||||
req->template once<write_event>(listener);
|
req->template on<write_event>(listener);
|
||||||
req->write(as_uv_stream(), send.as_uv_stream());
|
req->write(as_uv_stream(), send.as_uv_stream());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -350,8 +350,8 @@ public:
|
|||||||
ptr->publish(event);
|
ptr->publish(event);
|
||||||
};
|
};
|
||||||
|
|
||||||
req->template once<error_event>(listener);
|
req->template on<error_event>(listener);
|
||||||
req->template once<write_event>(listener);
|
req->template on<write_event>(listener);
|
||||||
req->write(as_uv_stream(), send.as_uv_stream());
|
req->write(as_uv_stream(), send.as_uv_stream());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -77,8 +77,8 @@ UVW_INLINE void tcp_handle::connect(const sockaddr &addr) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
auto req = parent().resource<details::connect_req>();
|
auto req = parent().resource<details::connect_req>();
|
||||||
req->once<error_event>(listener);
|
req->on<error_event>(listener);
|
||||||
req->once<connect_event>(listener);
|
req->on<connect_event>(listener);
|
||||||
req->connect(&uv_tcp_connect, raw(), &addr);
|
req->connect(&uv_tcp_connect, raw(), &addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -146,8 +146,8 @@ UVW_INLINE void udp_handle::send(const sockaddr &addr, std::unique_ptr<char[]> d
|
|||||||
ptr->publish(event);
|
ptr->publish(event);
|
||||||
};
|
};
|
||||||
|
|
||||||
req->once<error_event>(listener);
|
req->on<error_event>(listener);
|
||||||
req->once<send_event>(listener);
|
req->on<send_event>(listener);
|
||||||
req->send(raw(), &addr);
|
req->send(raw(), &addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,8 +166,8 @@ UVW_INLINE void udp_handle::send(const sockaddr &addr, char *data, unsigned int
|
|||||||
ptr->publish(event);
|
ptr->publish(event);
|
||||||
};
|
};
|
||||||
|
|
||||||
req->once<error_event>(listener);
|
req->on<error_event>(listener);
|
||||||
req->once<send_event>(listener);
|
req->on<send_event>(listener);
|
||||||
req->send(raw(), &addr);
|
req->send(raw(), &addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -62,7 +62,7 @@ function(ADD_UVW_TEST TEST_NAME TEST_SOURCE)
|
|||||||
${TEST_NAME}
|
${TEST_NAME}
|
||||||
PRIVATE
|
PRIVATE
|
||||||
$<$<NOT:$<PLATFORM_ID:Windows>>:-Wall>
|
$<$<NOT:$<PLATFORM_ID:Windows>>:-Wall>
|
||||||
$<$<PLATFORM_ID:Windows>:/EHsc>
|
$<$<PLATFORM_ID:Windows>:/EHsc -ftime-trace>
|
||||||
)
|
)
|
||||||
|
|
||||||
target_compile_definitions(${TEST_NAME} PRIVATE $<$<NOT:$<TARGET_EXISTS:uvw::uvw>>:UVW_AS_LIB>)
|
target_compile_definitions(${TEST_NAME} PRIVATE $<$<NOT:$<TARGET_EXISTS:uvw::uvw>>:UVW_AS_LIB>)
|
||||||
|
|||||||
@ -8,7 +8,7 @@ void listen(uvw::loop &loop) {
|
|||||||
std::shared_ptr<uvw::tcp_handle> tcp = loop.resource<uvw::tcp_handle>();
|
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->on<uvw::error_event>([](const uvw::error_event &, uvw::tcp_handle &) { assert(false); });
|
||||||
|
|
||||||
tcp->once<uvw::listen_event>([](const uvw::listen_event &, uvw::tcp_handle &srv) {
|
tcp->on<uvw::listen_event>([](const uvw::listen_event &, uvw::tcp_handle &srv) {
|
||||||
std::cout << "listen" << std::endl;
|
std::cout << "listen" << std::endl;
|
||||||
|
|
||||||
std::shared_ptr<uvw::tcp_handle> client = srv.parent().resource<uvw::tcp_handle>();
|
std::shared_ptr<uvw::tcp_handle> client = srv.parent().resource<uvw::tcp_handle>();
|
||||||
@ -43,7 +43,7 @@ void listen(uvw::loop &loop) {
|
|||||||
client->read();
|
client->read();
|
||||||
});
|
});
|
||||||
|
|
||||||
tcp->once<uvw::close_event>([](const uvw::close_event &, uvw::tcp_handle &) {
|
tcp->on<uvw::close_event>([](const uvw::close_event &, uvw::tcp_handle &) {
|
||||||
std::cout << "close" << std::endl;
|
std::cout << "close" << std::endl;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -55,12 +55,12 @@ void conn(uvw::loop &loop) {
|
|||||||
auto tcp = loop.resource<uvw::tcp_handle>();
|
auto tcp = loop.resource<uvw::tcp_handle>();
|
||||||
tcp->on<uvw::error_event>([](const uvw::error_event &, uvw::tcp_handle &) { assert(false); });
|
tcp->on<uvw::error_event>([](const uvw::error_event &, uvw::tcp_handle &) { assert(false); });
|
||||||
|
|
||||||
tcp->once<uvw::write_event>([](const uvw::write_event &, uvw::tcp_handle &handle) {
|
tcp->on<uvw::write_event>([](const uvw::write_event &, uvw::tcp_handle &handle) {
|
||||||
std::cout << "write" << std::endl;
|
std::cout << "write" << std::endl;
|
||||||
handle.close();
|
handle.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
tcp->once<uvw::connect_event>([](const uvw::connect_event &, uvw::tcp_handle &handle) {
|
tcp->on<uvw::connect_event>([](const uvw::connect_event &, uvw::tcp_handle &handle) {
|
||||||
std::cout << "connect" << std::endl;
|
std::cout << "connect" << std::endl;
|
||||||
|
|
||||||
auto dataTryWrite = std::unique_ptr<char[]>(new char[1]{'a'});
|
auto dataTryWrite = std::unique_ptr<char[]>(new char[1]{'a'});
|
||||||
@ -71,7 +71,7 @@ void conn(uvw::loop &loop) {
|
|||||||
handle.write(std::move(dataWrite), 2);
|
handle.write(std::move(dataWrite), 2);
|
||||||
});
|
});
|
||||||
|
|
||||||
tcp->once<uvw::close_event>([](const uvw::close_event &, uvw::tcp_handle &) {
|
tcp->on<uvw::close_event>([](const uvw::close_event &, uvw::tcp_handle &) {
|
||||||
std::cout << "close" << std::endl;
|
std::cout << "close" << std::endl;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -24,125 +24,40 @@ TEST(ErrorEvent, Functionalities) {
|
|||||||
ASSERT_TRUE(static_cast<bool>(uvw::error_event{ecode}));
|
ASSERT_TRUE(static_cast<bool>(uvw::error_event{ecode}));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Emitter, EmptyAndClear) {
|
TEST(Emitter, Functionalities) {
|
||||||
TestEmitter emitter{};
|
TestEmitter emitter{};
|
||||||
|
|
||||||
ASSERT_TRUE(emitter.empty());
|
|
||||||
|
|
||||||
emitter.on<uvw::error_event>([](const auto &, auto &) {});
|
emitter.on<uvw::error_event>([](const auto &, auto &) {});
|
||||||
|
|
||||||
ASSERT_FALSE(emitter.empty());
|
ASSERT_TRUE(emitter.has<uvw::error_event>());
|
||||||
ASSERT_FALSE(emitter.empty<uvw::error_event>());
|
ASSERT_FALSE(emitter.has<FakeEvent>());
|
||||||
ASSERT_TRUE(emitter.empty<FakeEvent>());
|
|
||||||
|
|
||||||
emitter.clear<FakeEvent>();
|
emitter.reset<FakeEvent>();
|
||||||
|
|
||||||
ASSERT_FALSE(emitter.empty());
|
ASSERT_TRUE(emitter.has<uvw::error_event>());
|
||||||
ASSERT_FALSE(emitter.empty<uvw::error_event>());
|
ASSERT_FALSE(emitter.has<FakeEvent>());
|
||||||
ASSERT_TRUE(emitter.empty<FakeEvent>());
|
|
||||||
|
|
||||||
emitter.clear<uvw::error_event>();
|
emitter.reset<uvw::error_event>();
|
||||||
|
|
||||||
ASSERT_TRUE(emitter.empty());
|
ASSERT_FALSE(emitter.has<uvw::error_event>());
|
||||||
ASSERT_TRUE(emitter.empty<uvw::error_event>());
|
ASSERT_FALSE(emitter.has<FakeEvent>());
|
||||||
ASSERT_TRUE(emitter.empty<FakeEvent>());
|
|
||||||
|
|
||||||
|
bool sentinel = false;
|
||||||
emitter.on<uvw::error_event>([](const auto &, auto &) {});
|
emitter.on<uvw::error_event>([](const auto &, auto &) {});
|
||||||
emitter.on<FakeEvent>([](const auto &, auto &) {});
|
emitter.on<FakeEvent>([&](const auto &, auto &) { sentinel = true; });
|
||||||
|
|
||||||
ASSERT_FALSE(emitter.empty());
|
ASSERT_FALSE(sentinel);
|
||||||
ASSERT_FALSE(emitter.empty<uvw::error_event>());
|
ASSERT_TRUE(emitter.has<uvw::error_event>());
|
||||||
ASSERT_FALSE(emitter.empty<FakeEvent>());
|
ASSERT_TRUE(emitter.has<FakeEvent>());
|
||||||
|
|
||||||
emitter.clear();
|
|
||||||
|
|
||||||
ASSERT_TRUE(emitter.empty());
|
|
||||||
ASSERT_TRUE(emitter.empty<uvw::error_event>());
|
|
||||||
ASSERT_TRUE(emitter.empty<FakeEvent>());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(Emitter, On) {
|
|
||||||
TestEmitter emitter{};
|
|
||||||
|
|
||||||
emitter.on<FakeEvent>([](const auto &, auto &) {});
|
|
||||||
|
|
||||||
ASSERT_FALSE(emitter.empty());
|
|
||||||
ASSERT_FALSE(emitter.empty<FakeEvent>());
|
|
||||||
|
|
||||||
emitter.emit();
|
emitter.emit();
|
||||||
|
|
||||||
ASSERT_FALSE(emitter.empty());
|
ASSERT_TRUE(sentinel);
|
||||||
ASSERT_FALSE(emitter.empty<FakeEvent>());
|
ASSERT_TRUE(emitter.has<uvw::error_event>());
|
||||||
}
|
ASSERT_TRUE(emitter.has<FakeEvent>());
|
||||||
|
|
||||||
TEST(Emitter, Once) {
|
emitter.reset();
|
||||||
TestEmitter emitter{};
|
|
||||||
|
ASSERT_FALSE(emitter.has<uvw::error_event>());
|
||||||
emitter.once<FakeEvent>([](const auto &, auto &) {});
|
ASSERT_FALSE(emitter.has<FakeEvent>());
|
||||||
|
|
||||||
ASSERT_FALSE(emitter.empty());
|
|
||||||
ASSERT_FALSE(emitter.empty<FakeEvent>());
|
|
||||||
|
|
||||||
emitter.emit();
|
|
||||||
|
|
||||||
ASSERT_TRUE(emitter.empty());
|
|
||||||
ASSERT_TRUE(emitter.empty<FakeEvent>());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(Emitter, OnceAndErase) {
|
|
||||||
TestEmitter emitter{};
|
|
||||||
|
|
||||||
auto conn = emitter.once<FakeEvent>([](const auto &, auto &) {});
|
|
||||||
|
|
||||||
ASSERT_FALSE(emitter.empty());
|
|
||||||
ASSERT_FALSE(emitter.empty<FakeEvent>());
|
|
||||||
|
|
||||||
emitter.erase(conn);
|
|
||||||
|
|
||||||
ASSERT_TRUE(emitter.empty());
|
|
||||||
ASSERT_TRUE(emitter.empty<FakeEvent>());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(Emitter, OnAndErase) {
|
|
||||||
TestEmitter emitter{};
|
|
||||||
|
|
||||||
auto conn = emitter.on<FakeEvent>([](const auto &, auto &) {});
|
|
||||||
|
|
||||||
ASSERT_FALSE(emitter.empty());
|
|
||||||
ASSERT_FALSE(emitter.empty<FakeEvent>());
|
|
||||||
|
|
||||||
emitter.erase(conn);
|
|
||||||
|
|
||||||
ASSERT_TRUE(emitter.empty());
|
|
||||||
ASSERT_TRUE(emitter.empty<FakeEvent>());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(Emitter, CallbackClear) {
|
|
||||||
TestEmitter emitter{};
|
|
||||||
|
|
||||||
emitter.on<FakeEvent>([](const auto &, auto &ref) {
|
|
||||||
ref.template on<FakeEvent>([](const auto &, auto &) {});
|
|
||||||
ref.clear();
|
|
||||||
});
|
|
||||||
|
|
||||||
ASSERT_FALSE(emitter.empty());
|
|
||||||
ASSERT_FALSE(emitter.empty<FakeEvent>());
|
|
||||||
|
|
||||||
emitter.emit();
|
|
||||||
|
|
||||||
ASSERT_TRUE(emitter.empty());
|
|
||||||
ASSERT_TRUE(emitter.empty<FakeEvent>());
|
|
||||||
|
|
||||||
emitter.on<FakeEvent>([](const auto &, auto &ref) {
|
|
||||||
ref.clear();
|
|
||||||
ref.template on<FakeEvent>([](const auto &, auto &) {});
|
|
||||||
});
|
|
||||||
|
|
||||||
ASSERT_FALSE(emitter.empty());
|
|
||||||
ASSERT_FALSE(emitter.empty<FakeEvent>());
|
|
||||||
|
|
||||||
emitter.emit();
|
|
||||||
|
|
||||||
ASSERT_FALSE(emitter.empty());
|
|
||||||
ASSERT_FALSE(emitter.empty<FakeEvent>());
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,7 +17,7 @@ TEST(Pipe, ReadWrite) {
|
|||||||
FAIL();
|
FAIL();
|
||||||
});
|
});
|
||||||
|
|
||||||
server->once<uvw::listen_event>([](const uvw::listen_event &, uvw::pipe_handle &handle) {
|
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>();
|
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::error_event>([](const uvw::error_event &, uvw::pipe_handle &) { FAIL(); });
|
||||||
@ -28,11 +28,11 @@ TEST(Pipe, ReadWrite) {
|
|||||||
socket->read();
|
socket->read();
|
||||||
});
|
});
|
||||||
|
|
||||||
client->once<uvw::write_event>([](const uvw::write_event &, uvw::pipe_handle &handle) {
|
client->on<uvw::write_event>([](const uvw::write_event &, uvw::pipe_handle &handle) {
|
||||||
handle.close();
|
handle.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
client->once<uvw::connect_event>([](const uvw::connect_event &, uvw::pipe_handle &handle) {
|
client->on<uvw::connect_event>([](const uvw::connect_event &, uvw::pipe_handle &handle) {
|
||||||
ASSERT_TRUE(handle.writable());
|
ASSERT_TRUE(handle.writable());
|
||||||
ASSERT_TRUE(handle.readable());
|
ASSERT_TRUE(handle.readable());
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ TEST(Pipe, SockPeer) {
|
|||||||
server->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
|
server->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
|
||||||
client->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
|
client->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
|
||||||
|
|
||||||
server->once<uvw::listen_event>([&peername](const uvw::listen_event &, uvw::pipe_handle &handle) {
|
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>();
|
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::error_event>([](const uvw::error_event &, uvw::pipe_handle &) { FAIL(); });
|
||||||
@ -76,7 +76,7 @@ TEST(Pipe, SockPeer) {
|
|||||||
ASSERT_EQ(handle.sock(), peername);
|
ASSERT_EQ(handle.sock(), peername);
|
||||||
});
|
});
|
||||||
|
|
||||||
client->once<uvw::connect_event>([&peername](const uvw::connect_event &, uvw::pipe_handle &handle) {
|
client->on<uvw::connect_event>([&peername](const uvw::connect_event &, uvw::pipe_handle &handle) {
|
||||||
ASSERT_EQ(handle.peer(), peername);
|
ASSERT_EQ(handle.peer(), peername);
|
||||||
|
|
||||||
handle.close();
|
handle.close();
|
||||||
@ -105,7 +105,7 @@ TEST(Pipe, Shutdown) {
|
|||||||
server->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
|
server->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
|
||||||
client->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
|
client->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
|
||||||
|
|
||||||
server->once<uvw::listen_event>([](const uvw::listen_event &, uvw::pipe_handle &handle) {
|
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>();
|
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::error_event>([](const uvw::error_event &, uvw::pipe_handle &) { FAIL(); });
|
||||||
@ -116,11 +116,11 @@ TEST(Pipe, Shutdown) {
|
|||||||
socket->read();
|
socket->read();
|
||||||
});
|
});
|
||||||
|
|
||||||
client->once<uvw::shutdown_event>([](const uvw::shutdown_event &, uvw::pipe_handle &handle) {
|
client->on<uvw::shutdown_event>([](const uvw::shutdown_event &, uvw::pipe_handle &handle) {
|
||||||
handle.close();
|
handle.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
client->once<uvw::connect_event>([&data](const uvw::connect_event &, uvw::pipe_handle &handle) {
|
client->on<uvw::connect_event>([&data](const uvw::connect_event &, uvw::pipe_handle &handle) {
|
||||||
handle.write(data.get(), 3);
|
handle.write(data.get(), 3);
|
||||||
handle.shutdown();
|
handle.shutdown();
|
||||||
});
|
});
|
||||||
|
|||||||
@ -24,7 +24,7 @@ TEST(TCP, ReadWrite) {
|
|||||||
server->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
|
server->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
|
||||||
client->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
|
client->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
|
||||||
|
|
||||||
server->once<uvw::listen_event>([](const uvw::listen_event &, uvw::tcp_handle &handle) {
|
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>();
|
std::shared_ptr<uvw::tcp_handle> socket = handle.parent().resource<uvw::tcp_handle>();
|
||||||
|
|
||||||
socket->on<uvw::error_event>([](const uvw::error_event &, uvw::tcp_handle &) { FAIL(); });
|
socket->on<uvw::error_event>([](const uvw::error_event &, uvw::tcp_handle &) { FAIL(); });
|
||||||
@ -35,11 +35,11 @@ TEST(TCP, ReadWrite) {
|
|||||||
socket->read();
|
socket->read();
|
||||||
});
|
});
|
||||||
|
|
||||||
client->once<uvw::write_event>([](const uvw::write_event &, uvw::tcp_handle &handle) {
|
client->on<uvw::write_event>([](const uvw::write_event &, uvw::tcp_handle &handle) {
|
||||||
handle.close();
|
handle.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
client->once<uvw::connect_event>([](const uvw::connect_event &, uvw::tcp_handle &handle) {
|
client->on<uvw::connect_event>([](const uvw::connect_event &, uvw::tcp_handle &handle) {
|
||||||
ASSERT_TRUE(handle.writable());
|
ASSERT_TRUE(handle.writable());
|
||||||
ASSERT_TRUE(handle.readable());
|
ASSERT_TRUE(handle.readable());
|
||||||
|
|
||||||
@ -67,7 +67,7 @@ TEST(TCP, SockPeer) {
|
|||||||
server->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
|
server->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
|
||||||
client->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
|
client->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
|
||||||
|
|
||||||
server->once<uvw::listen_event>([&address](const uvw::listen_event &, uvw::tcp_handle &handle) {
|
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>();
|
std::shared_ptr<uvw::tcp_handle> socket = handle.parent().resource<uvw::tcp_handle>();
|
||||||
|
|
||||||
socket->on<uvw::error_event>([](const uvw::error_event &, uvw::tcp_handle &) { FAIL(); });
|
socket->on<uvw::error_event>([](const uvw::error_event &, uvw::tcp_handle &) { FAIL(); });
|
||||||
@ -82,7 +82,7 @@ TEST(TCP, SockPeer) {
|
|||||||
ASSERT_EQ(addr.ip, address);
|
ASSERT_EQ(addr.ip, address);
|
||||||
});
|
});
|
||||||
|
|
||||||
client->once<uvw::connect_event>([&address](const uvw::connect_event &, uvw::tcp_handle &handle) {
|
client->on<uvw::connect_event>([&address](const uvw::connect_event &, uvw::tcp_handle &handle) {
|
||||||
uvw::socket_address addr = handle.peer();
|
uvw::socket_address addr = handle.peer();
|
||||||
|
|
||||||
ASSERT_EQ(addr.ip, address);
|
ASSERT_EQ(addr.ip, address);
|
||||||
@ -108,7 +108,7 @@ TEST(TCP, Shutdown) {
|
|||||||
server->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
|
server->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
|
||||||
client->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
|
client->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
|
||||||
|
|
||||||
server->once<uvw::listen_event>([](const uvw::listen_event &, uvw::tcp_handle &handle) {
|
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>();
|
std::shared_ptr<uvw::tcp_handle> socket = handle.parent().resource<uvw::tcp_handle>();
|
||||||
|
|
||||||
socket->on<uvw::error_event>([](const uvw::error_event &, uvw::tcp_handle &) { FAIL(); });
|
socket->on<uvw::error_event>([](const uvw::error_event &, uvw::tcp_handle &) { FAIL(); });
|
||||||
@ -119,11 +119,11 @@ TEST(TCP, Shutdown) {
|
|||||||
socket->read();
|
socket->read();
|
||||||
});
|
});
|
||||||
|
|
||||||
client->once<uvw::shutdown_event>([](const uvw::shutdown_event &, uvw::tcp_handle &handle) {
|
client->on<uvw::shutdown_event>([](const uvw::shutdown_event &, uvw::tcp_handle &handle) {
|
||||||
handle.close();
|
handle.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
client->once<uvw::connect_event>([](const uvw::connect_event &, uvw::tcp_handle &handle) {
|
client->on<uvw::connect_event>([](const uvw::connect_event &, uvw::tcp_handle &handle) {
|
||||||
handle.shutdown();
|
handle.shutdown();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -144,13 +144,13 @@ TEST(TCP, WriteError) {
|
|||||||
bool checkTryWriteNakedPtrErrorEvent = false;
|
bool checkTryWriteNakedPtrErrorEvent = false;
|
||||||
|
|
||||||
handle->close();
|
handle->close();
|
||||||
handle->once<uvw::error_event>([&checkWriteSmartPtrErrorEvent](const auto &, auto &) { checkWriteSmartPtrErrorEvent = true; });
|
handle->on<uvw::error_event>([&checkWriteSmartPtrErrorEvent](const auto &, auto &) { checkWriteSmartPtrErrorEvent = true; });
|
||||||
handle->write(std::unique_ptr<char[]>{}, 0);
|
handle->write(std::unique_ptr<char[]>{}, 0);
|
||||||
handle->once<uvw::error_event>([&checkWriteNakedPtrErrorEvent](const auto &, auto &) { checkWriteNakedPtrErrorEvent = true; });
|
handle->on<uvw::error_event>([&checkWriteNakedPtrErrorEvent](const auto &, auto &) { checkWriteNakedPtrErrorEvent = true; });
|
||||||
handle->write(nullptr, 0);
|
handle->write(nullptr, 0);
|
||||||
handle->once<uvw::error_event>([&checkTryWriteSmartPtrErrorEvent](const auto &, auto &) { checkTryWriteSmartPtrErrorEvent = true; });
|
handle->on<uvw::error_event>([&checkTryWriteSmartPtrErrorEvent](const auto &, auto &) { checkTryWriteSmartPtrErrorEvent = true; });
|
||||||
handle->try_write(std::unique_ptr<char[]>{}, 0);
|
handle->try_write(std::unique_ptr<char[]>{}, 0);
|
||||||
handle->once<uvw::error_event>([&checkTryWriteNakedPtrErrorEvent](const auto &, auto &) { checkTryWriteNakedPtrErrorEvent = true; });
|
handle->on<uvw::error_event>([&checkTryWriteNakedPtrErrorEvent](const auto &, auto &) { checkTryWriteNakedPtrErrorEvent = true; });
|
||||||
handle->try_write(nullptr, 0);
|
handle->try_write(nullptr, 0);
|
||||||
|
|
||||||
loop->run();
|
loop->run();
|
||||||
|
|||||||
@ -47,7 +47,7 @@ TEST(UDP, ReadTrySend) {
|
|||||||
server->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
|
server->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
|
||||||
client->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
|
client->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
|
||||||
|
|
||||||
server->once<uvw::udp_data_event>([&client](const uvw::udp_data_event &, uvw::udp_handle &handle) {
|
server->on<uvw::udp_data_event>([&client](const uvw::udp_data_event &, uvw::udp_handle &handle) {
|
||||||
client->close();
|
client->close();
|
||||||
handle.close();
|
handle.close();
|
||||||
});
|
});
|
||||||
@ -77,11 +77,11 @@ TEST(UDP, ReadSend) {
|
|||||||
server->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
|
server->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
|
||||||
client->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
|
client->on<uvw::error_event>([](const auto &, auto &) { FAIL(); });
|
||||||
|
|
||||||
server->once<uvw::udp_data_event>([](const uvw::udp_data_event &, uvw::udp_handle &handle) {
|
server->on<uvw::udp_data_event>([](const uvw::udp_data_event &, uvw::udp_handle &handle) {
|
||||||
handle.close();
|
handle.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
client->once<uvw::send_event>([](const uvw::send_event &, uvw::udp_handle &handle) {
|
client->on<uvw::send_event>([](const uvw::send_event &, uvw::udp_handle &handle) {
|
||||||
handle.close();
|
handle.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user