The Perl and Raku Conference 2025: Greenville, South Carolina - June 27-29 Learn more

#pragma once
#include <uv.h>
#include <panda/unievent/util.h>
#include <panda/unievent/error.h>
#include <panda/unievent/backend/HandleImpl.h>
namespace panda { namespace unievent { namespace backend { namespace uv {
static inline void uvx_strict (int err) { if (err) throw Error(uvx_error(err)); }
static inline std::error_code uvx_ce (int err) { return err ? uvx_error(err) : std::error_code(); }
template <class T = HandleImpl*, class X>
static inline T get_handle (X* uvhp) {
return static_cast<T>(reinterpret_cast<HandleImpl*>(uvhp->data));
}
template <class T = RequestImpl*, class X>
static inline T get_request (X* uvrp) {
return static_cast<T>(reinterpret_cast<RequestImpl*>(uvrp->data));
}
static inline void uvx_buf_alloc (string& buf, uv_buf_t* uvbuf) {
char* ptr = buf.shared_buf();
auto cap = buf.shared_capacity();
size_t align = (size_t(ptr) + cap) % sizeof(void*);
cap -= align;
auto availcap = cap - sizeof(string);
//TODO: optimize me. writing in the end is bad. size is usually 64k, which is 16 pages.
//data size is usually less than 4k and can be stored in one page, but writing in the and always needs 2 pagees: first and last
//buf.data() is not aligned because of string internal data, so align it before writeing
//also align ptr data + sizeof(string) in case of odd size of string itself
new ((string*)(ptr + availcap)) string(buf); // save string object at the end of the buffer, keeping it's internal ptr alive
uvbuf->base = ptr;
uvbuf->len = availcap;
}
static inline string uvx_detach_buf (const uv_buf_t* uvbuf) {
if (!uvbuf->base) return {}; // in some cases of eof there may be no buffer
auto buf_ptr = (string*)(uvbuf->base + uvbuf->len);
string ret = *buf_ptr;
buf_ptr->~string();
return ret;
}
#define UVX_FILL_BUFS(bufs, uvbufs) \
auto uvbufs = (uv_buf_t*)alloca(sizeof(uv_buf_t)*bufs.size()); \
uv_buf_t* ptr = uvbufs; \
for (const auto& str : bufs) { \
ptr->base = (char*)str.data(); \
ptr->len = str.length(); \
++ptr; \
}
template <class Handle, class Func>
static inline expected<net::SockAddr, std::error_code> uvx_sockaddr (Handle uvhp, Func&& f) {
net::SockAddr ret;
int err;
ret.assign_foreign([&](auto ptr, auto size_ptr){
err = f(uvhp, ptr, (int*)size_ptr);
return !err;
});
if (err) {
return make_unexpected(uvx_ce(err));
}
return ret;
}
static inline expected<fh_t, std::error_code> uvx_fileno (const uv_handle_t* p) {
uv_os_fd_t fd; //should be compatible type
int err = uv_fileno(p, &fd);
if (err) return make_unexpected(uvx_error(err));
return {fd};
}
static inline expected<int, std::error_code> uvx_recv_buffer_size (const uv_handle_t* p) {
int ret = 0;
auto err = uvx_ce(uv_recv_buffer_size((uv_handle_t*)p, &ret));
if (err) {
return make_unexpected(err);
} else {
return ret;
}
}
static inline std::error_code uvx_recv_buffer_size (uv_handle_t* p, int value) {
return uvx_ce(uv_recv_buffer_size(p, &value));
}
static inline expected<int, std::error_code> uvx_send_buffer_size (const uv_handle_t* p) {
int ret = 0;
auto err = uvx_ce(uv_send_buffer_size((uv_handle_t*)p, &ret));
if (err) {
return make_unexpected(err);
} else {
return ret;
}
}
static inline std::error_code uvx_send_buffer_size (uv_handle_t* p, int value) {
return uvx_ce(uv_send_buffer_size(p, &value));
}
}}}}