feat: add C & Zig bindings for unix acceptor and connector

This commit is contained in:
CJ van den Berg 2026-03-02 18:43:49 +00:00
parent 628e990f6e
commit ed91a28f5f
Signed by: neurocyte
GPG key ID: 8EB1E1BB660E3FB9
9 changed files with 283 additions and 0 deletions

134
src/c/unx.cpp Normal file
View file

@ -0,0 +1,134 @@
#include <thespian/c/context.h>
#include <thespian/c/unx.h>
#include <thespian/unx.hpp>
using thespian::unx::acceptor_impl;
using thespian::unx::connector_impl;
using thespian::unx::mode;
extern "C" {
namespace {
static auto to_cpp_mode(thespian_unx_mode m) -> mode {
return m == THESPIAN_UNX_MODE_ABSTRACT ? mode::abstract : mode::file;
}
} // namespace
auto thespian_unx_acceptor_create(const char *tag)
-> struct thespian_unx_acceptor_handle * {
try {
auto *h = thespian::unx::acceptor::create(tag).ref.release();
return reinterpret_cast<struct thespian_unx_acceptor_handle *>(h); // NOLINT
} catch (const std::exception &e) {
thespian_set_last_error(e.what());
return nullptr;
} catch (...) {
thespian_set_last_error("unknown thespian_unx_acceptor_create error");
return nullptr;
}
}
auto thespian_unx_acceptor_listen(struct thespian_unx_acceptor_handle *handle,
const char *path, thespian_unx_mode m)
-> int {
try {
thespian::unx::acceptor_listen(
reinterpret_cast<acceptor_impl *>(handle), // NOLINT
path, to_cpp_mode(m));
return 0;
} catch (const std::exception &e) {
thespian_set_last_error(e.what());
return -1;
} catch (...) {
thespian_set_last_error("unknown thespian_unx_acceptor_listen error");
return -1;
}
}
auto thespian_unx_acceptor_close(struct thespian_unx_acceptor_handle *handle)
-> int {
try {
thespian::unx::acceptor_close(
reinterpret_cast<acceptor_impl *>(handle)); // NOLINT
return 0;
} catch (const std::exception &e) {
thespian_set_last_error(e.what());
return -1;
} catch (...) {
thespian_set_last_error("unknown thespian_unx_acceptor_close error");
return -1;
}
}
void thespian_unx_acceptor_destroy(
struct thespian_unx_acceptor_handle *handle) {
try {
thespian::unx::destroy_acceptor(
reinterpret_cast<acceptor_impl *>(handle)); // NOLINT
} catch (const std::exception &e) {
thespian_set_last_error(e.what());
} catch (...) {
thespian_set_last_error("unknown thespian_unx_acceptor_destroy error");
}
}
auto thespian_unx_connector_create(const char *tag)
-> struct thespian_unx_connector_handle * {
try {
auto *h = thespian::unx::connector::create(tag).ref.release();
return reinterpret_cast<struct thespian_unx_connector_handle *>( // NOLINT
h);
} catch (const std::exception &e) {
thespian_set_last_error(e.what());
return nullptr;
} catch (...) {
thespian_set_last_error("unknown thespian_unx_connector_create error");
return nullptr;
}
}
auto thespian_unx_connector_connect(
struct thespian_unx_connector_handle *handle, const char *path,
thespian_unx_mode m) -> int {
try {
thespian::unx::connector_connect(
reinterpret_cast<connector_impl *>(handle), // NOLINT
path, to_cpp_mode(m));
return 0;
} catch (const std::exception &e) {
thespian_set_last_error(e.what());
return -1;
} catch (...) {
thespian_set_last_error("unknown thespian_unx_connector_connect error");
return -1;
}
}
auto thespian_unx_connector_cancel(struct thespian_unx_connector_handle *handle)
-> int {
try {
thespian::unx::connector_cancel(
reinterpret_cast<connector_impl *>(handle)); // NOLINT
return 0;
} catch (const std::exception &e) {
thespian_set_last_error(e.what());
return -1;
} catch (...) {
thespian_set_last_error("unknown thespian_unx_connector_cancel error");
return -1;
}
}
void thespian_unx_connector_destroy(
struct thespian_unx_connector_handle *handle) {
try {
thespian::unx::destroy_connector(
reinterpret_cast<connector_impl *>(handle)); // NOLINT
} catch (const std::exception &e) {
thespian_set_last_error(e.what());
} catch (...) {
thespian_set_last_error("unknown thespian_unx_connector_destroy error");
}
}
} // extern "C"

View file

@ -1396,6 +1396,22 @@ void connector::connect(string_view path, mode m) { ref->connect(path, m); }
void connector::cancel() { ref->cancel(); }
// C API helpers - must be defined where acceptor_impl/connector_impl are
// complete
void acceptor_listen(acceptor_impl *h, std::string_view path, mode m) {
h->listen(path, m);
}
void acceptor_close(acceptor_impl *h) { h->close(); }
void connector_connect(connector_impl *h, std::string_view path, mode m) {
h->connect(path, m);
}
void connector_cancel(connector_impl *h) { h->cancel(); }
void destroy_acceptor(acceptor_impl *h) { delete h; }
void destroy_connector(connector_impl *h) { delete h; }
} // namespace unx
namespace endpoint {

View file

@ -6,6 +6,7 @@ const c = @cImport({
@cInclude("thespian/c/metronome.h");
@cInclude("thespian/c/timeout.h");
@cInclude("thespian/c/signal.h");
@cInclude("thespian/c/unx.h");
});
const c_posix = if (builtin.os.tag != .windows) @cImport({
@cInclude("thespian/backtrace.h");
@ -741,6 +742,61 @@ pub const metronome = struct {
}
};
pub const unx_mode = enum(u8) {
file = 0,
abstract = 1,
};
pub const unx_acceptor = struct {
handle: *c.struct_thespian_unx_acceptor_handle,
const Self = @This();
pub fn init(tag_: []const u8) !Self {
return .{ .handle = c.thespian_unx_acceptor_create(tag_) orelse return log_last_error(error.ThespianUnxAcceptorInitFailed) };
}
pub fn listen(self: *const Self, path: []const u8, mode: unx_mode) !void {
const mval: u8 = @intCast(mode);
const ret = c.thespian_unx_acceptor_listen(self.handle, path, mval);
if (ret < 0) return error.ThespianUnxAcceptorListenFailed;
}
pub fn close(self: *const Self) !void {
const ret = c.thespian_unx_acceptor_close(self.handle);
if (ret < 0) return error.ThespianUnxAcceptorCloseFailed;
}
pub fn deinit(self: *const Self) void {
c.thespian_unx_acceptor_destroy(self.handle);
}
};
pub const unx_connector = struct {
handle: *c.struct_thespian_unx_connector_handle,
const Self = @This();
pub fn init(tag_: []const u8) !Self {
return .{ .handle = c.thespian_unx_connector_create(tag_) orelse return log_last_error(error.ThespianUnxConnectorInitFailed) };
}
pub fn connect(self: *const Self, path: []const u8, mode: unx_mode) !void {
const mval: u8 = @intCast(mode);
const ret = c.thespian_unx_connector_connect(self.handle, path, mval);
if (ret < 0) return error.ThespianUnxConnectorConnectFailed;
}
pub fn cancel(self: *const Self) !void {
const ret = c.thespian_unx_connector_cancel(self.handle);
if (ret < 0) return error.ThespianUnxConnectorCancelFailed;
}
pub fn deinit(self: *const Self) void {
c.thespian_unx_connector_destroy(self.handle);
}
};
pub const timeout = struct {
handle: ?*c.struct_thespian_timeout_handle,