WIP: safer callbacks

This commit is contained in:
Michele Caini 2016-06-23 17:19:52 +02:00
parent d030c5c6f6
commit 8714fcf24a
4 changed files with 73 additions and 42 deletions

View File

@ -12,8 +12,8 @@ namespace uvw {
class Check final: public Resource<Check> {
static void proto(uv_check_t* h) {
static_cast<Check*>(h->data)->callback(UVWError{});
static void startCallback(uv_check_t* h) {
static_cast<Check*>(h->data)->startCb(UVWError{});
}
explicit Check(std::shared_ptr<Loop> ref)
@ -23,20 +23,18 @@ class Check final: public Resource<Check> {
}
public:
using Callback = std::function<void(UVWError)>;
template<typename... Args>
static std::shared_ptr<Check> create(Args&&... args) {
return std::shared_ptr<Check>{new Check{std::forward<Args>(args)...}};
}
void start(Callback cb) noexcept {
callback = std::move(cb);
void start(std::function<void(UVWError)> cb) noexcept {
startCb = std::move(cb);
get<uv_check_t>()->data = this;
auto err = uv_check_start(get<uv_check_t>(), &proto);
auto err = uv_check_start(get<uv_check_t>(), &startCallback);
if(err) {
callback(UVWError{err});
startCb(UVWError{err});
}
}
@ -45,7 +43,7 @@ public:
explicit operator bool() { return initialized; }
private:
Callback callback;
std::function<void(UVWError)> startCb;
bool initialized;
};

View File

@ -59,7 +59,8 @@ private:
class Loop final: public std::enable_shared_from_this<Loop> {
friend class BaseResource;
template<typename>
friend class Resource;
using Deleter = std::function<void(uv_loop_t *)>;

View File

@ -15,24 +15,55 @@ template<typename>
struct HandleType { };
class BaseResource {
template<typename>
class Resource;
template<typename>
struct UVCallback;
template<typename... Args>
struct UVCallback<Args...> {
template<typename T, T*(*F)(Args...)>
static auto get(T *res);
private:
template<typename T, T*(*F)(Args...)>
static void proto(Args... args);
};
template<typename T>
class Resource: public std::enable_shared_from_this<T> {
template<typename>
friend struct UVCallback;
static Resource<T>* closeCallback(uv_handle_t* h) {
auto ptr = static_cast<Resource<T>*>(h->data);
ptr->closeCb(UVWError{});
return ptr;
}
protected:
template<typename T>
explicit BaseResource(HandleType<T>, std::shared_ptr<Loop> r)
: pLoop{std::move(r)}, handle{std::make_shared<T>()}
template<typename U>
explicit Resource(HandleType<U>, std::shared_ptr<Loop> r)
: pLoop{std::move(r)}, handle{std::make_shared<U>()}
{ }
template<typename T>
T* get() const noexcept { return reinterpret_cast<T*>(handle.get()); }
template<typename U>
U* get() const noexcept { return reinterpret_cast<U*>(handle.get()); }
uv_loop_t* parent() const noexcept { return pLoop->loop.get(); }
public:
explicit BaseResource(const BaseResource &) = delete;
explicit BaseResource(BaseResource &&) = delete;
explicit Resource(const Resource &) = delete;
explicit Resource(Resource &&) = delete;
void operator=(const BaseResource &) = delete;
void operator=(BaseResource &&) = delete;
~Resource() { static_assert(std::is_base_of<Resource<T>, T>::value, "!"); }
void operator=(const Resource &) = delete;
void operator=(Resource &&) = delete;
std::shared_ptr<Loop> loop() const noexcept { return pLoop; }
@ -43,33 +74,35 @@ public:
void unreference() noexcept { uv_ref(get<uv_handle_t>()); }
bool referenced() const noexcept { return !(uv_has_ref(get<uv_handle_t>()) == 0); }
void close(std::function<void(UVWError)> cb) noexcept {
using UVCB = UVCallback<uv_handle_t*>;
auto func = UVCB::get<Resource<T>, &closeCallback>(this);
closeCb = std::move(cb);
uv_close(get<uv_handle_t>(), func);
}
private:
std::function<void(UVWError)> closeCb;
std::shared_ptr<Loop> pLoop;
std::shared_ptr<void> handle;
std::shared_ptr<void> ref;
};
template<typename T>
class Resource: public std::enable_shared_from_this<T>, public BaseResource {
static void proto(uv_handle_t* h) {
static_cast<Resource<T>*>(h->data)->callback(UVWError{});
}
template<typename... Args>
template<typename T, T*(*F)(Args...)>
void UVCallback<Args...>::proto(Args... args) {
T *res = F(std::forward<Args>(args)...);
res->ref = nullptr;
}
protected:
using BaseResource::BaseResource;
public:
using Callback = std::function<void(UVWError)>;
void close(Callback cb) noexcept {
callback = std::move(cb);
get<uv_handle_t>()->data = this;
uv_close(get<uv_handle_t>(), &proto);
}
private:
Callback callback;
};
template<typename... Args>
template<typename T, T*(*F)(Args...)>
auto UVCallback<Args...>::get(T *res) {
res->template get<uv_handle_t>()->data = res;
res->ref = res->shared_from_this();
return &proto<T, F>;
}
}

View File

@ -8,9 +8,8 @@ void f(uvw::Loop &loop) {
auto cb = [handle](uvw::UVWError err) mutable {
std::cout << "---" << ((bool)err) << std::endl;
uvw::Tcp &tcp = handle;
tcp.close([handle](uvw::UVWError err) mutable {
tcp.close([](uvw::UVWError err) mutable {
std::cout << "---" << ((bool)err) << std::endl;
handle = uvw::Handle<uvw::Tcp>{};
});
};