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
|
||||
|
||||
`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/>
|
||||
`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:
|
||||
|
||||
@ -346,24 +346,18 @@ It means that the following function types are all valid:
|
||||
* `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<event_type>(listener)`: the listener will be automatically
|
||||
removed after the first event of the given type.
|
||||
* `resource.on<event_type>(listener)`: to be used for long-running listeners.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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
|
||||
@ -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) {
|
||||
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 */ });
|
||||
srv.accept(*client);
|
||||
client->read();
|
||||
|
||||
@ -83,91 +83,32 @@ template<typename T>
|
||||
class emitter {
|
||||
struct base_handler {
|
||||
virtual ~base_handler() UVW_NOEXCEPT = default;
|
||||
virtual bool empty() const UVW_NOEXCEPT = 0;
|
||||
virtual void clear() UVW_NOEXCEPT = 0;
|
||||
virtual bool has() const UVW_NOEXCEPT = 0;
|
||||
virtual void reset() UVW_NOEXCEPT = 0;
|
||||
};
|
||||
|
||||
template<typename E>
|
||||
struct event_handler final: base_handler {
|
||||
using listener = std::function<void(E &, T &)>;
|
||||
using listener_list = std::list<std::pair<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) {
|
||||
if(!curr.first) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
bool has() const UVW_NOEXCEPT override {
|
||||
return static_cast<bool>(listener);
|
||||
}
|
||||
|
||||
void clear() UVW_NOEXCEPT override {
|
||||
if(publishing) {
|
||||
for(auto &&curr: once_list) {
|
||||
curr.first = true;
|
||||
}
|
||||
|
||||
for(auto &&curr: on_list) {
|
||||
curr.first = true;
|
||||
}
|
||||
} else {
|
||||
once_list.clear();
|
||||
on_list.clear();
|
||||
}
|
||||
void reset() UVW_NOEXCEPT override {
|
||||
listener = nullptr;
|
||||
}
|
||||
|
||||
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 on(std::function<void(E &, T &)> func) {
|
||||
listener = std::move(func);
|
||||
}
|
||||
|
||||
void publish(E event, T &ref) {
|
||||
listener_list curr;
|
||||
once_list.swap(curr);
|
||||
|
||||
publishing = true;
|
||||
|
||||
for(auto first = on_list.rbegin(), last = on_list.rend(); first != last; ++first) {
|
||||
if(!first->first) {
|
||||
first->second(event, ref);
|
||||
}
|
||||
if(listener) {
|
||||
listener(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:
|
||||
bool publishing{false};
|
||||
listener_list once_list{};
|
||||
listener_list on_list{};
|
||||
std::function<void(E &, T &)> listener;
|
||||
};
|
||||
|
||||
template<typename E>
|
||||
@ -188,32 +129,6 @@ protected:
|
||||
}
|
||||
|
||||
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 {
|
||||
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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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) {
|
||||
void on(std::function<void(E &, T &)> f) {
|
||||
return handler<E>().on(std::move(f));
|
||||
}
|
||||
|
||||
/**
|
||||
* @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.
|
||||
*
|
||||
* 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.
|
||||
* @brief Disconnects the listener for the given event type.
|
||||
*/
|
||||
template<typename E>
|
||||
connection<E> once(listener<E> f) {
|
||||
return handler<E>().once(std::move(f));
|
||||
void reset() UVW_NOEXCEPT {
|
||||
handler<E>().reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disconnects a listener from the event emitter.
|
||||
* @param conn A valid connection object
|
||||
* @brief Disconnects all listeners.
|
||||
*/
|
||||
template<typename E>
|
||||
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 {
|
||||
void reset() UVW_NOEXCEPT {
|
||||
for(auto &&curr: handlers) {
|
||||
curr.second->clear();
|
||||
curr.second->reset();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 UVW_NOEXCEPT {
|
||||
bool has() const UVW_NOEXCEPT {
|
||||
const auto id = type<E>();
|
||||
return (!handlers.count(id) || static_cast<event_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 UVW_NOEXCEPT {
|
||||
for(auto &&curr: handlers) {
|
||||
if(!curr.second->empty()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return (handlers.count(id) && static_cast<event_handler<E> &>(*handlers.at(id)).has());
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@ -32,8 +32,8 @@ UVW_INLINE void pipe_handle::connect(const std::string &name) {
|
||||
};
|
||||
|
||||
auto connect = parent().resource<details::connect_req>();
|
||||
connect->once<error_event>(listener);
|
||||
connect->once<connect_event>(listener);
|
||||
connect->on<error_event>(listener);
|
||||
connect->on<connect_event>(listener);
|
||||
connect->connect(&uv_pipe_connect, raw(), name.data());
|
||||
}
|
||||
|
||||
|
||||
@ -175,8 +175,8 @@ public:
|
||||
};
|
||||
|
||||
auto shutdown = this->parent().template resource<details::shutdown_req>();
|
||||
shutdown->template once<error_event>(listener);
|
||||
shutdown->template once<shutdown_event>(listener);
|
||||
shutdown->template on<error_event>(listener);
|
||||
shutdown->template on<shutdown_event>(listener);
|
||||
shutdown->shutdown(as_uv_stream());
|
||||
}
|
||||
|
||||
@ -265,8 +265,8 @@ public:
|
||||
ptr->publish(event);
|
||||
};
|
||||
|
||||
req->template once<error_event>(listener);
|
||||
req->template once<write_event>(listener);
|
||||
req->template on<error_event>(listener);
|
||||
req->template on<write_event>(listener);
|
||||
req->write(as_uv_stream());
|
||||
}
|
||||
|
||||
@ -288,8 +288,8 @@ public:
|
||||
ptr->publish(event);
|
||||
};
|
||||
|
||||
req->template once<error_event>(listener);
|
||||
req->template once<write_event>(listener);
|
||||
req->template on<error_event>(listener);
|
||||
req->template on<write_event>(listener);
|
||||
req->write(as_uv_stream());
|
||||
}
|
||||
|
||||
@ -319,8 +319,8 @@ public:
|
||||
ptr->publish(event);
|
||||
};
|
||||
|
||||
req->template once<error_event>(listener);
|
||||
req->template once<write_event>(listener);
|
||||
req->template on<error_event>(listener);
|
||||
req->template on<write_event>(listener);
|
||||
req->write(as_uv_stream(), send.as_uv_stream());
|
||||
}
|
||||
|
||||
@ -350,8 +350,8 @@ public:
|
||||
ptr->publish(event);
|
||||
};
|
||||
|
||||
req->template once<error_event>(listener);
|
||||
req->template once<write_event>(listener);
|
||||
req->template on<error_event>(listener);
|
||||
req->template on<write_event>(listener);
|
||||
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>();
|
||||
req->once<error_event>(listener);
|
||||
req->once<connect_event>(listener);
|
||||
req->on<error_event>(listener);
|
||||
req->on<connect_event>(listener);
|
||||
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);
|
||||
};
|
||||
|
||||
req->once<error_event>(listener);
|
||||
req->once<send_event>(listener);
|
||||
req->on<error_event>(listener);
|
||||
req->on<send_event>(listener);
|
||||
req->send(raw(), &addr);
|
||||
}
|
||||
|
||||
@ -166,8 +166,8 @@ UVW_INLINE void udp_handle::send(const sockaddr &addr, char *data, unsigned int
|
||||
ptr->publish(event);
|
||||
};
|
||||
|
||||
req->once<error_event>(listener);
|
||||
req->once<send_event>(listener);
|
||||
req->on<error_event>(listener);
|
||||
req->on<send_event>(listener);
|
||||
req->send(raw(), &addr);
|
||||
}
|
||||
|
||||
|
||||
@ -62,7 +62,7 @@ function(ADD_UVW_TEST TEST_NAME TEST_SOURCE)
|
||||
${TEST_NAME}
|
||||
PRIVATE
|
||||
$<$<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>)
|
||||
|
||||
@ -8,7 +8,7 @@ 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::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::shared_ptr<uvw::tcp_handle> client = srv.parent().resource<uvw::tcp_handle>();
|
||||
@ -43,7 +43,7 @@ void listen(uvw::loop &loop) {
|
||||
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;
|
||||
});
|
||||
|
||||
@ -55,12 +55,12 @@ 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::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;
|
||||
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;
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
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;
|
||||
});
|
||||
|
||||
|
||||
@ -24,125 +24,40 @@ TEST(ErrorEvent, Functionalities) {
|
||||
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 &) {});
|
||||
|
||||
ASSERT_FALSE(emitter.empty());
|
||||
ASSERT_FALSE(emitter.empty<uvw::error_event>());
|
||||
ASSERT_TRUE(emitter.empty<FakeEvent>());
|
||||
ASSERT_TRUE(emitter.has<uvw::error_event>());
|
||||
ASSERT_FALSE(emitter.has<FakeEvent>());
|
||||
|
||||
emitter.clear<FakeEvent>();
|
||||
emitter.reset<FakeEvent>();
|
||||
|
||||
ASSERT_FALSE(emitter.empty());
|
||||
ASSERT_FALSE(emitter.empty<uvw::error_event>());
|
||||
ASSERT_TRUE(emitter.empty<FakeEvent>());
|
||||
ASSERT_TRUE(emitter.has<uvw::error_event>());
|
||||
ASSERT_FALSE(emitter.has<FakeEvent>());
|
||||
|
||||
emitter.clear<uvw::error_event>();
|
||||
emitter.reset<uvw::error_event>();
|
||||
|
||||
ASSERT_TRUE(emitter.empty());
|
||||
ASSERT_TRUE(emitter.empty<uvw::error_event>());
|
||||
ASSERT_TRUE(emitter.empty<FakeEvent>());
|
||||
ASSERT_FALSE(emitter.has<uvw::error_event>());
|
||||
ASSERT_FALSE(emitter.has<FakeEvent>());
|
||||
|
||||
bool sentinel = false;
|
||||
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(emitter.empty<uvw::error_event>());
|
||||
ASSERT_FALSE(emitter.empty<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>());
|
||||
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>());
|
||||
}
|
||||
|
||||
@ -17,7 +17,7 @@ TEST(Pipe, ReadWrite) {
|
||||
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>();
|
||||
|
||||
socket->on<uvw::error_event>([](const uvw::error_event &, uvw::pipe_handle &) { FAIL(); });
|
||||
@ -28,11 +28,11 @@ TEST(Pipe, ReadWrite) {
|
||||
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();
|
||||
});
|
||||
|
||||
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.readable());
|
||||
|
||||
@ -63,7 +63,7 @@ TEST(Pipe, SockPeer) {
|
||||
server->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>();
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
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);
|
||||
|
||||
handle.close();
|
||||
@ -105,7 +105,7 @@ TEST(Pipe, Shutdown) {
|
||||
server->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>();
|
||||
|
||||
socket->on<uvw::error_event>([](const uvw::error_event &, uvw::pipe_handle &) { FAIL(); });
|
||||
@ -116,11 +116,11 @@ TEST(Pipe, Shutdown) {
|
||||
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();
|
||||
});
|
||||
|
||||
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.shutdown();
|
||||
});
|
||||
|
||||
@ -24,7 +24,7 @@ TEST(TCP, ReadWrite) {
|
||||
server->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>();
|
||||
|
||||
socket->on<uvw::error_event>([](const uvw::error_event &, uvw::tcp_handle &) { FAIL(); });
|
||||
@ -35,11 +35,11 @@ TEST(TCP, ReadWrite) {
|
||||
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();
|
||||
});
|
||||
|
||||
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.readable());
|
||||
|
||||
@ -67,7 +67,7 @@ TEST(TCP, SockPeer) {
|
||||
server->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>();
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
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();
|
||||
|
||||
ASSERT_EQ(addr.ip, address);
|
||||
@ -108,7 +108,7 @@ TEST(TCP, Shutdown) {
|
||||
server->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>();
|
||||
|
||||
socket->on<uvw::error_event>([](const uvw::error_event &, uvw::tcp_handle &) { FAIL(); });
|
||||
@ -119,11 +119,11 @@ TEST(TCP, Shutdown) {
|
||||
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();
|
||||
});
|
||||
|
||||
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();
|
||||
});
|
||||
|
||||
@ -144,13 +144,13 @@ TEST(TCP, WriteError) {
|
||||
bool checkTryWriteNakedPtrErrorEvent = false;
|
||||
|
||||
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->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->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->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);
|
||||
|
||||
loop->run();
|
||||
|
||||
@ -47,7 +47,7 @@ TEST(UDP, ReadTrySend) {
|
||||
server->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();
|
||||
handle.close();
|
||||
});
|
||||
@ -77,11 +77,11 @@ TEST(UDP, ReadSend) {
|
||||
server->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();
|
||||
});
|
||||
|
||||
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();
|
||||
});
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user