diff --git a/src/uvw/check.hpp b/src/uvw/check.hpp index 032690e3..b6cac22b 100644 --- a/src/uvw/check.hpp +++ b/src/uvw/check.hpp @@ -12,9 +12,8 @@ namespace uvw { class Check final: public Resource { - static void startCallback(Check &ref, uv_check_t*) { - ref.startCb(UVWError{}); - ref.startCb = nullptr; + static void startCallback(Check &, std::function &cb, uv_check_t*) { + cb(UVWError{}); } explicit Check(std::shared_ptr ref) @@ -30,14 +29,10 @@ public: } void start(std::function cb) noexcept { - auto func = Callback::get<&Check::startCallback>(*this); + using CB = Callback; + auto func = CB::on<&Check::startCallback>(*this, cb); auto err = uv_check_start(get(), func); - - if(err) { - startCb(UVWError{err}); - } else { - startCb = std::move(cb); - } + if(err) { cb(UVWError{err}); } } UVWError stop() noexcept { return UVWError{uv_check_stop(get())}; } @@ -45,7 +40,6 @@ public: explicit operator bool() { return initialized; } private: - std::function startCb; bool initialized; }; diff --git a/src/uvw/resource.hpp b/src/uvw/resource.hpp index ad8667bf..42582664 100644 --- a/src/uvw/resource.hpp +++ b/src/uvw/resource.hpp @@ -3,9 +3,11 @@ #include #include +#include #include #include #include "loop.hpp" +#include "error.hpp" namespace uvw { @@ -32,12 +34,18 @@ struct UVCallback; template struct UVCallback { - template - static auto get(T &); + template &, H, Args...)> + static auto once(T &, std::function); + + template &, H, Args...)> + static auto on(T &, std::function); private: - template - static void proto(H, Args...); + template &, H, Args...)> + static void protoOnce(H, Args...); + + template &, H, Args...)> + static void protoOn(H, Args...); }; @@ -49,10 +57,8 @@ class Resource: public std::enable_shared_from_this { template friend struct details::UVCallback; - static void closeCallback(T &ref, uv_handle_t*) { - Resource &res = ref; - res.closeCb(UVWError{}); - res.closeCb = nullptr; + static void closeCallback(T &, std::function &cb, uv_handle_t*) { + cb(UVWError{}); } protected: @@ -88,16 +94,16 @@ public: bool referenced() const noexcept { return !(uv_has_ref(get()) == 0); } void close(std::function cb) noexcept { - auto func = Callback::template get<&Resource::closeCallback>(*static_cast(this)); - closeCb = std::move(cb); + using CB = Callback; + auto func = CB::template once<&Resource::closeCallback>(*static_cast(this), std::move(cb)); uv_close(get(), func); } private: - std::function closeCb; std::shared_ptr pLoop; std::shared_ptr handle; std::shared_ptr leak; + std::function callback; }; @@ -105,24 +111,44 @@ namespace details { template -template -auto UVCallback::get(T &ref) { +template &, H, Args...)> +auto UVCallback::once(T &ref, std::function cb) { Resource &res = ref; + res.callback = std::move(cb); res.leak = res.shared_from_this(); res.template get()->data = static_cast(&ref); - return &UVCallback::proto; + return &UVCallback::protoOnce; } template -template -void UVCallback::proto(H handle, Args... args) { +template &, H, Args...)> +auto UVCallback::on(T &ref, std::function cb) { + Resource &res = ref; + res.callback = std::move(cb); + res.leak = res.shared_from_this(); + res.template get()->data = static_cast(&ref); + return &UVCallback::protoOn; +} + +template +template &, H, Args...)> +void UVCallback::protoOnce(H handle, Args... args) { T &ref = *(static_cast(details::get(handle))); + auto cb = ref.callback; auto ptr = ref.leak; ref.leak.reset(); - F(ref, handle, std::forward(args)...); + F(ref, ref.callback, handle, std::forward(args)...); + ref.callback = nullptr; (void)ptr; } +template +template &, H, Args...)> +void UVCallback::protoOn(H handle, Args... args) { + T &ref = *(static_cast(details::get(handle))); + F(ref, ref.callback, handle, std::forward(args)...); +} + } diff --git a/src/uvw/stream.hpp b/src/uvw/stream.hpp index c307d3dd..9462298a 100644 --- a/src/uvw/stream.hpp +++ b/src/uvw/stream.hpp @@ -11,9 +11,8 @@ namespace uvw { template class Stream: public Resource { - static void listenCallback(T &ref, uv_stream_t* srv, int status) { - ref.listenCb(UVWError{status}); - ref.listenCb = nullptr; + static void listenCallback(T &ref, std::function &cb, uv_stream_t* srv, int status) { + cb(UVWError{status}); } protected: @@ -24,15 +23,9 @@ public: void listen(int backlog, std::function cb) noexcept { using CB = typename Resource::template Callback; - - auto func = CB::get<&Stream::listenCallback>(*static_cast(this)); + auto func = CB::on<&Stream::listenCallback>(*static_cast(this), cb); auto err = uv_listen(this->template get(), backlog, func); - - if(err) { - listenCb(UVWError{err}); - } else { - listenCb = std::move(cb); - } + if(err) { cb(UVWError{err}); } } // TODO read diff --git a/src/uvw/tcp.hpp b/src/uvw/tcp.hpp index 48cf2871..ad2a58dc 100644 --- a/src/uvw/tcp.hpp +++ b/src/uvw/tcp.hpp @@ -65,6 +65,7 @@ private: template<> void Tcp::connect(std::string ip, int port, std::function cb) noexcept { + // TODO switch to the Callback model sockaddr_in addr; uv_ip4_addr(ip.c_str(), port, &addr); connCb = std::move(cb); @@ -79,6 +80,7 @@ void Tcp::connect(std::string ip, int port, std::function void Tcp::connect(std::string ip, int port, std::function cb) noexcept { + // TODO switch to the Callback model sockaddr_in6 addr; uv_ip6_addr(ip.c_str(), port, &addr); connCb = std::move(cb); diff --git a/src/uvw/timer.hpp b/src/uvw/timer.hpp index aeb9bf5d..6af3189e 100644 --- a/src/uvw/timer.hpp +++ b/src/uvw/timer.hpp @@ -14,9 +14,8 @@ namespace uvw { class Timer final: public Resource { - static void startCallback(Timer &ref, uv_timer_t*) { - ref.startCb(UVWError{}); - ref.startCb = nullptr; + static void startCallback(Timer &, std::function &cb, uv_timer_t*) { + cb(UVWError{}); } explicit Timer(std::shared_ptr ref) @@ -34,14 +33,10 @@ public: } void start(const Time &timeout, const Time &rep, std::function cb) noexcept { - auto func = Callback::get<&Timer::startCallback>(*this); + using CB = Callback; + auto func = CB::on<&Timer::startCallback>(*this, cb); auto err = uv_timer_start(get(), func, timeout.count(), rep.count()); - - if(err) { - startCb(UVWError{err}); - } else { - startCb = std::move(cb); - } + if(err) { cb(UVWError{err}); } } UVWError stop() noexcept { return UVWError{uv_timer_stop(get())}; }