WIP: going crazy with uv

This commit is contained in:
Michele Caini 2016-06-26 16:52:30 +02:00
parent 3a5d7e69c2
commit 2e5bb0f113
3 changed files with 63 additions and 43 deletions

View File

@ -12,10 +12,9 @@ namespace uvw {
class Check final: public Resource<Check> { class Check final: public Resource<Check> {
static Check* startCallback(uv_check_t* h) { static void startCallback(Check &ref, uv_check_t* h) {
Check *check = static_cast<Check*>(h->data); ref.startCb(UVWError{});
check->startCb(UVWError{}); ref.startCb = nullptr;
return check;
} }
explicit Check(std::shared_ptr<Loop> ref) explicit Check(std::shared_ptr<Loop> ref)
@ -31,14 +30,13 @@ public:
} }
void start(std::function<void(UVWError)> cb) noexcept { void start(std::function<void(UVWError)> cb) noexcept {
using UVCB = UVCallback<Check, uv_check_t*>; auto func = Callback<void(uv_check_t*)>::get<&Check::startCallback>(*this);
auto func = UVCB::get<&Check::startCallback>(this);
startCb = std::move(cb);
auto err = uv_check_start(get<uv_check_t>(), func); auto err = uv_check_start(get<uv_check_t>(), func);
if(err) { if(err) {
startCb(UVWError{err}); startCb(UVWError{err});
reset(); } else {
startCb = std::move(cb);
} }
} }

View File

@ -19,29 +19,46 @@ template<typename>
class Resource; class Resource;
template<typename T, typename... Args> namespace details {
struct UVCallback {
template<T*(*F)(Args...)>
static auto get(T *res); template<typename T>
void* get(T *handle) { return handle->data; }
template<typename T, typename F>
struct UVCallback;
template<typename T,typename H, typename... Args>
struct UVCallback<T, void(H, Args...)> {
template<void(*F)(T &, H, Args...)>
static auto get(T &);
private: private:
template<T*(*F)(Args...)> template<void(*F)(T &, H, Args...)>
static void proto(Args... args); static void proto(H, Args...);
}; };
}
template<typename T> template<typename T>
class Resource: public std::enable_shared_from_this<T> { class Resource: public std::enable_shared_from_this<T> {
template<typename, typename...> template<typename, typename>
friend struct UVCallback; friend struct details::UVCallback;
static Resource<T>* closeCallback(uv_handle_t* h) { static void closeCallback(T &ref, uv_handle_t* h) {
auto *ptr = static_cast<Resource<T>*>(h->data); Resource<T> &res = ref;
ptr->closeCb(UVWError{}); res.closeCb(UVWError{});
return ptr; res.closeCb = nullptr;
} }
protected: protected:
template<typename F>
using Callback = details::UVCallback<T, F>;
template<typename U> template<typename U>
explicit Resource(HandleType<U>, std::shared_ptr<Loop> r) explicit Resource(HandleType<U>, std::shared_ptr<Loop> r)
: pLoop{std::move(r)}, handle{std::make_shared<U>()} : pLoop{std::move(r)}, handle{std::make_shared<U>()}
@ -51,7 +68,6 @@ protected:
U* get() const noexcept { return reinterpret_cast<U*>(handle.get()); } U* get() const noexcept { return reinterpret_cast<U*>(handle.get()); }
uv_loop_t* parent() const noexcept { return pLoop->loop.get(); } uv_loop_t* parent() const noexcept { return pLoop->loop.get(); }
void reset() noexcept { ref = nullptr; }
public: public:
explicit Resource(const Resource &) = delete; explicit Resource(const Resource &) = delete;
@ -72,8 +88,7 @@ public:
bool referenced() const noexcept { return !(uv_has_ref(get<uv_handle_t>()) == 0); } bool referenced() const noexcept { return !(uv_has_ref(get<uv_handle_t>()) == 0); }
void close(std::function<void(UVWError)> cb) noexcept { void close(std::function<void(UVWError)> cb) noexcept {
using UVCB = UVCallback<Resource<T>, uv_handle_t*>; auto func = Callback<void(uv_handle_t*)>::template get<&Resource<T>::closeCallback>(*static_cast<T*>(this));
auto func = UVCB::template get<&Resource<T>::closeCallback>(this);
closeCb = std::move(cb); closeCb = std::move(cb);
uv_close(get<uv_handle_t>(), func); uv_close(get<uv_handle_t>(), func);
} }
@ -82,23 +97,32 @@ private:
std::function<void(UVWError)> closeCb; std::function<void(UVWError)> closeCb;
std::shared_ptr<Loop> pLoop; std::shared_ptr<Loop> pLoop;
std::shared_ptr<void> handle; std::shared_ptr<void> handle;
std::shared_ptr<void> ref; std::shared_ptr<void> leak;
}; };
template<typename T, typename... Args> namespace details {
template<T*(*F)(Args...)>
void UVCallback<T, Args...>::proto(Args... args) {
T *res = F(std::forward<Args>(args)...); template<typename T, typename H, typename... Args>
res->ref = nullptr; template<void(*F)(T &, H, Args...)>
auto UVCallback<T, void(H, Args...)>::get(T &ref) {
Resource<T> &res = ref;
res.leak = res.shared_from_this();
res.template get<uv_handle_t>()->data = static_cast<void*>(&ref);
return &UVCallback<T, void(H, Args...)>::proto<F>;
} }
template<typename T, typename... Args> template<typename T, typename H, typename... Args>
template<T*(*F)(Args...)> template<void(*F)(T &, H, Args...)>
auto UVCallback<T, Args...>::get(T *res) { void UVCallback<T, void(H, Args...)>::proto(H handle, Args... args) {
res->template get<uv_handle_t>()->data = res; T &ref = *(static_cast<T*>(details::get(handle)));
res->ref = res->shared_from_this(); F(ref, handle, std::forward<Args>(args)...);
return &UVCallback<T, Args...>::proto<F>; ref.leak.reset();
}
} }

View File

@ -14,10 +14,9 @@ namespace uvw {
class Timer final: public Resource<Timer> { class Timer final: public Resource<Timer> {
static Timer* startCallback(uv_timer_t* h) { static void startCallback(Timer &ref, uv_timer_t* h) {
Timer *timer = static_cast<Timer*>(h->data); ref.startCb(UVWError{});
timer->startCb(UVWError{}); ref.startCb = nullptr;
return timer;
} }
explicit Timer(std::shared_ptr<Loop> ref) explicit Timer(std::shared_ptr<Loop> ref)
@ -35,14 +34,13 @@ public:
} }
void start(const Time &timeout, const Time &rep, std::function<void(UVWError)> cb) noexcept { void start(const Time &timeout, const Time &rep, std::function<void(UVWError)> cb) noexcept {
using UVCB = UVCallback<Timer, uv_timer_t*>; auto func = Callback<void(uv_timer_t*)>::get<&Timer::startCallback>(*this);
auto func = UVCB::get<&Timer::startCallback>(this);
startCb = std::move(cb);
auto err = uv_timer_start(get<uv_timer_t>(), func, timeout.count(), rep.count()); auto err = uv_timer_start(get<uv_timer_t>(), func, timeout.count(), rep.count());
if(err) { if(err) {
startCb(UVWError{err}); startCb(UVWError{err});
reset(); } else {
startCb = std::move(cb);
} }
} }