simpler emitter, better compile-time

This commit is contained in:
Michele Caini 2022-04-03 00:15:24 +02:00
parent ba337a7104
commit 3d3790c06c
12 changed files with 107 additions and 332 deletions

View File

@ -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();

View File

@ -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:

View File

@ -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());
} }

View File

@ -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());
} }

View File

@ -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);
} }

View File

@ -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);
} }

View File

@ -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>)

View File

@ -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;
}); });

View File

@ -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>());
} }

View File

@ -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();
}); });

View File

@ -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();

View File

@ -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();
}); });