feat: add C & Zig bindings for socket

This commit is contained in:
CJ van den Berg 2026-03-02 19:02:50 +00:00
parent e19ff271d0
commit d1cb42d53c
Signed by: neurocyte
GPG key ID: 8EB1E1BB660E3FB9
11 changed files with 209 additions and 13 deletions

91
src/c/socket.cpp Normal file
View file

@ -0,0 +1,91 @@
#include <thespian/c/context.h>
#include <thespian/c/socket.h>
#include <thespian/socket.hpp>
using socket_impl = thespian::socket_impl;
extern "C" {
auto thespian_socket_create(const char *tag, int fd)
-> struct thespian_socket_handle * {
try {
auto *h = thespian::socket::create(tag, fd).ref.release();
return reinterpret_cast<struct thespian_socket_handle *>(h); // NOLINT
} catch (const std::exception &e) {
thespian_set_last_error(e.what());
return nullptr;
} catch (...) {
thespian_set_last_error("unknown thespian_socket_create error");
return nullptr;
}
}
auto thespian_socket_write(struct thespian_socket_handle *handle,
const char *data, size_t len) -> int {
try {
thespian::socket_write(reinterpret_cast<socket_impl *>(handle), // NOLINT
std::string_view(data, len));
return 0;
} catch (const std::exception &e) {
thespian_set_last_error(e.what());
return -1;
} catch (...) {
thespian_set_last_error("unknown thespian_socket_write error");
return -1;
}
}
auto thespian_socket_write_binary(struct thespian_socket_handle *handle,
const uint8_t *data, size_t len) -> int {
try {
std::vector<uint8_t> buf(data, data + len); // NOLINT
thespian::socket_write_binary(
reinterpret_cast<socket_impl *>(handle), // NOLINT
buf);
return 0;
} catch (const std::exception &e) {
thespian_set_last_error(e.what());
return -1;
} catch (...) {
thespian_set_last_error("unknown thespian_socket_write_binary error");
return -1;
}
}
auto thespian_socket_read(struct thespian_socket_handle *handle) -> int {
try {
thespian::socket_read(reinterpret_cast<socket_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_socket_read error");
return -1;
}
}
auto thespian_socket_close(struct thespian_socket_handle *handle) -> int {
try {
thespian::socket_close(reinterpret_cast<socket_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_socket_close error");
return -1;
}
}
void thespian_socket_destroy(struct thespian_socket_handle *handle) {
try {
thespian::destroy_socket(reinterpret_cast<socket_impl *>(handle)); // NOLINT
} catch (const std::exception &e) {
thespian_set_last_error(e.what());
} catch (...) {
thespian_set_last_error("unknown thespian_socket_destroy error");
}
}
} // extern "C"

View file

@ -1136,6 +1136,16 @@ void socket::write(const vector<uint8_t> &data) { ref->write(data); }
void socket::read() { ref->read(); }
void socket::close() { ref->close(); }
// C API helpers - visibility requires complete types
void socket_write(socket_impl *h, string_view data) { h->write(data); }
void socket_write_binary(socket_impl *h, const vector<uint8_t> &data) {
h->write(data);
}
void socket_read(socket_impl *h) { h->read(); }
void socket_close(socket_impl *h) { h->close(); }
void destroy_socket(socket_impl *h) { delete h; }
namespace tcp {
struct acceptor_impl {

View file

@ -8,6 +8,7 @@ const c = @cImport({
@cInclude("thespian/c/signal.h");
@cInclude("thespian/c/unx.h");
@cInclude("thespian/c/tcp.h");
@cInclude("thespian/c/socket.h");
@cInclude("netinet/in.h");
});
const c_posix = if (builtin.os.tag != .windows) @cImport({
@ -848,6 +849,40 @@ pub const tcp_connector = struct {
}
};
pub const socket = struct {
handle: *c.struct_thespian_socket_handle,
const Self = @This();
pub fn init(tag_: []const u8, fd: i32) !Self {
return .{ .handle = c.thespian_socket_create(tag_, fd) orelse return log_last_error(error.ThespianSocketInitFailed) };
}
pub fn write(self: *const Self, data: []const u8) !void {
const ret = c.thespian_socket_write(self.handle, data.ptr, data.len);
if (ret < 0) return error.ThespianSocketWriteFailed;
}
pub fn write_binary(self: *const Self, data: []const u8) !void {
const ret = c.thespian_socket_write_binary(self.handle, data.ptr, data.len);
if (ret < 0) return error.ThespianSocketWriteBinaryFailed;
}
pub fn read(self: *const Self) !void {
const ret = c.thespian_socket_read(self.handle);
if (ret < 0) return error.ThespianSocketReadFailed;
}
pub fn close(self: *const Self) !void {
const ret = c.thespian_socket_close(self.handle);
if (ret < 0) return error.ThespianSocketCloseFailed;
}
pub fn deinit(self: *const Self) void {
c.thespian_socket_destroy(self.handle);
}
};
pub const timeout = struct {
handle: ?*c.struct_thespian_timeout_handle,