2023-01-02 14:28:25 +00:00
|
|
|
const std = @import("std");
|
2023-08-01 11:35:04 +00:00
|
|
|
const stdx = @import("stdx");
|
2023-01-02 14:28:25 +00:00
|
|
|
const xev = @import("xev");
|
2024-01-11 15:40:15 +00:00
|
|
|
const coro = @import("coro.zig");
|
|
|
|
|
const executor = @import("executor.zig");
|
|
|
|
|
const channel_mod = @import("channel.zig");
|
|
|
|
|
const aio = @import("asyncio.zig");
|
|
|
|
|
const stack = @import("stack.zig");
|
2023-10-24 14:36:22 +00:00
|
|
|
|
|
|
|
|
pub const Condition = struct {
|
2024-01-11 15:40:15 +00:00
|
|
|
inner: executor.Condition,
|
2023-10-24 14:36:22 +00:00
|
|
|
|
|
|
|
|
pub fn init() Condition {
|
2024-01-11 15:40:15 +00:00
|
|
|
return .{ .inner = executor.Condition.init(&AsyncThread.current.executor.exec) };
|
2023-10-24 14:36:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn broadcast(self: *Condition) void {
|
2024-01-11 15:40:15 +00:00
|
|
|
self.inner.broadcast();
|
2023-10-24 14:36:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn signal(self: *Condition) void {
|
2024-01-11 15:40:15 +00:00
|
|
|
self.inner.signal();
|
2023-10-24 14:36:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn wait(self: *Condition) void {
|
2024-01-11 15:40:15 +00:00
|
|
|
self.inner.wait();
|
2023-10-24 14:36:22 +00:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2023-01-02 14:28:25 +00:00
|
|
|
pub fn Frame(comptime func: anytype) type {
|
2023-08-01 11:35:04 +00:00
|
|
|
const Signature = stdx.meta.FnSignature(func, null);
|
|
|
|
|
return FrameExx(func, Signature.ArgsT, Signature.ReturnT);
|
2023-01-02 14:28:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn FrameEx(comptime func: anytype, comptime argsT: type) type {
|
2023-08-01 11:35:04 +00:00
|
|
|
const Signature = stdx.meta.FnSignature(func, argsT);
|
|
|
|
|
return FrameExx(func, Signature.ArgsT, Signature.ReturnT);
|
2023-01-02 14:28:25 +00:00
|
|
|
}
|
|
|
|
|
|
2023-08-01 11:35:04 +00:00
|
|
|
fn FrameExx(comptime func: anytype, comptime argsT: type, comptime returnT: type) type {
|
2023-01-02 14:28:25 +00:00
|
|
|
return struct {
|
|
|
|
|
const Self = @This();
|
2024-01-11 15:40:15 +00:00
|
|
|
const FrameT = coro.FrameT(func, argsT);
|
2023-01-02 14:28:25 +00:00
|
|
|
|
|
|
|
|
inner: FrameT,
|
|
|
|
|
|
2023-08-01 11:35:04 +00:00
|
|
|
pub const wait = await_;
|
|
|
|
|
pub const await_ = awaitt;
|
|
|
|
|
pub fn awaitt(self: *Self) returnT {
|
2023-01-02 14:28:25 +00:00
|
|
|
defer {
|
|
|
|
|
self.inner.deinit();
|
2024-01-16 14:13:45 +00:00
|
|
|
AsyncThread.current.stack_allocator.destroy(&self.inner._frame.stack);
|
2023-01-02 14:28:25 +00:00
|
|
|
self.* = undefined;
|
|
|
|
|
}
|
2024-01-11 15:40:15 +00:00
|
|
|
return coro.xawait(self.inner);
|
2023-01-02 14:28:25 +00:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-01 11:35:04 +00:00
|
|
|
pub fn asyncc(comptime func: anytype, args: anytype) !FrameEx(func, @TypeOf(args)) {
|
|
|
|
|
const Signature = stdx.meta.FnSignature(func, @TypeOf(args));
|
2024-01-11 15:40:15 +00:00
|
|
|
const new_stack = try AsyncThread.current.stack_allocator.create();
|
2023-08-01 11:35:04 +00:00
|
|
|
return .{
|
2024-01-11 15:40:15 +00:00
|
|
|
.inner = try aio.xasync(func, @as(Signature.ArgsT, args), new_stack),
|
2023-08-01 11:35:04 +00:00
|
|
|
};
|
2023-01-02 14:28:25 +00:00
|
|
|
}
|
|
|
|
|
|
2023-08-01 11:35:04 +00:00
|
|
|
pub fn callBlocking(comptime func: anytype, args: anytype) stdx.meta.FnSignature(func, @TypeOf(args)).ReturnT {
|
|
|
|
|
const Signature = stdx.meta.FnSignature(func, @TypeOf(args));
|
2023-01-02 14:28:25 +00:00
|
|
|
|
|
|
|
|
const TaskT = struct {
|
|
|
|
|
const Self = @This();
|
|
|
|
|
|
|
|
|
|
_task: xev.ThreadPool.Task = .{ .callback = &Self.run },
|
|
|
|
|
|
2023-08-01 11:35:04 +00:00
|
|
|
event: threading.ResetEventSingle = .{},
|
|
|
|
|
args: Signature.ArgsT,
|
2023-01-02 14:28:25 +00:00
|
|
|
result: Signature.ReturnT = undefined,
|
|
|
|
|
|
|
|
|
|
pub fn run(task_: *xev.ThreadPool.Task) void {
|
|
|
|
|
const task: *Self = @alignCast(@fieldParentPtr("_task", task_));
|
2023-08-01 11:35:04 +00:00
|
|
|
task.result = @call(.auto, func, task.args);
|
|
|
|
|
task.event.set();
|
2023-01-02 14:28:25 +00:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var newtask: TaskT = .{
|
2023-08-01 11:35:04 +00:00
|
|
|
.args = args,
|
2023-01-02 14:28:25 +00:00
|
|
|
};
|
|
|
|
|
AsyncThread.current.thread_pool.schedule(xev.ThreadPool.Batch.from(&newtask._task));
|
2023-08-01 11:35:04 +00:00
|
|
|
newtask.event.wait();
|
2023-01-02 14:28:25 +00:00
|
|
|
|
2023-08-01 11:35:04 +00:00
|
|
|
return newtask.result;
|
2023-01-02 14:28:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn sleep(ms: u64) !void {
|
|
|
|
|
try aio.sleep(AsyncThread.current.executor, ms);
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-01 11:35:04 +00:00
|
|
|
pub const threading = struct {
|
|
|
|
|
const Waiter = struct {
|
2024-01-11 15:40:15 +00:00
|
|
|
frame: coro.Frame,
|
2023-08-01 11:35:04 +00:00
|
|
|
thread: *const AsyncThread,
|
|
|
|
|
next: ?*Waiter = null,
|
|
|
|
|
};
|
|
|
|
|
|
2024-01-11 15:40:15 +00:00
|
|
|
const WaiterQueue = stdx.queue.MPSC(Waiter);
|
2023-08-01 11:35:04 +00:00
|
|
|
|
|
|
|
|
pub const ResetEventSingle = struct {
|
|
|
|
|
const State = union(enum) {
|
|
|
|
|
unset,
|
|
|
|
|
waiting: *Waiter,
|
|
|
|
|
set,
|
|
|
|
|
|
|
|
|
|
const unset_state: State = .unset;
|
|
|
|
|
const set_state: State = .set;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
waiter: std.atomic.Value(*const State) = std.atomic.Value(*const State).init(&State.unset_state),
|
2023-01-02 14:28:25 +00:00
|
|
|
|
2023-08-01 11:35:04 +00:00
|
|
|
pub fn isSet(self: *ResetEventSingle) bool {
|
2024-01-11 15:40:15 +00:00
|
|
|
return self.waiter.load(.monotonic) == &State.set_state;
|
2023-08-01 11:35:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn reset(self: *ResetEventSingle) void {
|
|
|
|
|
self.waiter.store(&State.unset_state, .monotonic);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn set(self: *ResetEventSingle) void {
|
|
|
|
|
switch (self.waiter.swap(&State.set_state, .monotonic).*) {
|
|
|
|
|
.waiting => |waiter| {
|
|
|
|
|
waiter.thread.waiters_queue.push(waiter);
|
|
|
|
|
waiter.thread.wake();
|
|
|
|
|
},
|
|
|
|
|
else => {},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn wait(self: *ResetEventSingle) void {
|
|
|
|
|
var waiter: Waiter = .{
|
2024-01-11 15:40:15 +00:00
|
|
|
.frame = coro.xframe(),
|
2023-08-01 11:35:04 +00:00
|
|
|
.thread = AsyncThread.current,
|
|
|
|
|
};
|
|
|
|
|
var new_state: State = .{
|
|
|
|
|
.waiting = &waiter,
|
|
|
|
|
};
|
|
|
|
|
if (self.waiter.cmpxchgStrong(&State.unset_state, &new_state, .monotonic, .monotonic) == null) {
|
2024-03-14 11:43:33 +00:00
|
|
|
while (self.isSet() == false) {
|
|
|
|
|
coro.xsuspend();
|
|
|
|
|
}
|
2023-08-01 11:35:04 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
2023-01-02 14:28:25 +00:00
|
|
|
pub const AsyncThread = struct {
|
2024-01-16 14:13:45 +00:00
|
|
|
threadlocal var current: *AsyncThread = undefined;
|
2023-01-02 14:28:25 +00:00
|
|
|
|
|
|
|
|
executor: *aio.Executor,
|
2024-01-11 15:40:15 +00:00
|
|
|
stack_allocator: *stack.StackAllocator,
|
2023-01-02 14:28:25 +00:00
|
|
|
loop: *xev.Loop,
|
|
|
|
|
thread_pool: *xev.ThreadPool,
|
2023-08-01 11:35:04 +00:00
|
|
|
async_notifier: *xev.Async,
|
|
|
|
|
waiters_queue: *threading.WaiterQueue,
|
|
|
|
|
|
|
|
|
|
pub fn wake(self: *const AsyncThread) void {
|
|
|
|
|
self.async_notifier.notify() catch {};
|
|
|
|
|
}
|
2023-01-02 14:28:25 +00:00
|
|
|
|
2024-01-16 14:13:45 +00:00
|
|
|
fn wakerCallback(self: ?*AsyncThread, _: *xev.Loop, _: *xev.Completion, _: xev.Async.WaitError!void) xev.CallbackAction {
|
|
|
|
|
while (self.?.waiters_queue.pop()) |waiter| {
|
2024-01-11 15:40:15 +00:00
|
|
|
coro.xresume(waiter.frame);
|
2023-08-01 11:35:04 +00:00
|
|
|
}
|
|
|
|
|
return .rearm;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn main(allocator: std.mem.Allocator, comptime mainFunc: fn () anyerror!void) !void {
|
2023-01-02 14:28:25 +00:00
|
|
|
var thread_pool = xev.ThreadPool.init(.{});
|
|
|
|
|
defer {
|
|
|
|
|
thread_pool.shutdown();
|
|
|
|
|
thread_pool.deinit();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var loop = try xev.Loop.init(.{
|
|
|
|
|
.thread_pool = &thread_pool,
|
|
|
|
|
});
|
|
|
|
|
defer loop.deinit();
|
|
|
|
|
|
2024-01-11 15:40:15 +00:00
|
|
|
var executor_ = aio.Executor.init(&loop);
|
2023-01-02 14:28:25 +00:00
|
|
|
|
2023-08-01 11:35:04 +00:00
|
|
|
var async_notifier = try xev.Async.init();
|
|
|
|
|
defer async_notifier.deinit();
|
|
|
|
|
|
|
|
|
|
var waiters_queue: threading.WaiterQueue = undefined;
|
|
|
|
|
waiters_queue.init();
|
|
|
|
|
|
2024-01-11 15:40:15 +00:00
|
|
|
var stack_allocator = stack.StackAllocator.init(allocator);
|
|
|
|
|
defer stack_allocator.deinit();
|
2023-01-02 14:28:25 +00:00
|
|
|
|
2024-01-16 14:13:45 +00:00
|
|
|
var asyncThread: AsyncThread = .{
|
2024-01-11 15:40:15 +00:00
|
|
|
.executor = &executor_,
|
|
|
|
|
.stack_allocator = &stack_allocator,
|
2023-08-01 11:35:04 +00:00
|
|
|
.loop = &loop,
|
|
|
|
|
.thread_pool = &thread_pool,
|
|
|
|
|
.async_notifier = &async_notifier,
|
|
|
|
|
.waiters_queue = &waiters_queue,
|
|
|
|
|
};
|
2024-01-16 14:13:45 +00:00
|
|
|
AsyncThread.current = &asyncThread;
|
|
|
|
|
|
|
|
|
|
var c2: xev.Completion = undefined;
|
|
|
|
|
async_notifier.wait(AsyncThread.current.loop, &c2, AsyncThread, AsyncThread.current, &AsyncThread.wakerCallback);
|
2023-08-01 11:35:04 +00:00
|
|
|
|
2024-01-11 15:40:15 +00:00
|
|
|
// allocate the main coroutine stack, on the current thread's stack!
|
|
|
|
|
var mainStackData: stack.Stack.Data = undefined;
|
|
|
|
|
const mainStack = stack.Stack.init(&mainStackData);
|
|
|
|
|
|
|
|
|
|
return try aio.run(&executor_, mainFunc, .{}, mainStack);
|
2023-01-02 14:28:25 +00:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2023-08-01 11:35:04 +00:00
|
|
|
pub fn getStdIn() !File {
|
2023-01-02 14:28:25 +00:00
|
|
|
return File.init(std.io.getStdIn()) catch @panic("Unable to open stdin");
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-01 11:35:04 +00:00
|
|
|
pub fn getStdOut() File {
|
2023-01-02 14:28:25 +00:00
|
|
|
return File.init(std.io.getStdOut()) catch @panic("Unable to open stdout");
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-01 11:35:04 +00:00
|
|
|
pub fn getStdErr() File {
|
2023-01-02 14:28:25 +00:00
|
|
|
return File.init(std.io.getStdErr()) catch @panic("Unable to open stderr");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub const File = struct {
|
2023-08-01 11:35:04 +00:00
|
|
|
pub const SeekError = stdx.meta.FnSignature(File.seekTo, null).ReturnErrorSet.? || stdx.meta.FnSignature(File.seekBy, null).ReturnErrorSet.?;
|
|
|
|
|
pub const GetSeekPosError = SeekError || stdx.meta.FnSignature(File.stat, null).ReturnErrorSet.?;
|
|
|
|
|
pub const Reader = std.io.GenericReader(File, stdx.meta.FnSignature(File.read, null).ReturnErrorSet.?, File.read);
|
|
|
|
|
pub const Writer = std.io.GenericWriter(File, stdx.meta.FnSignature(File.write, null).ReturnErrorSet.?, File.write);
|
2023-01-02 14:28:25 +00:00
|
|
|
pub const SeekableStream = std.io.SeekableStream(
|
|
|
|
|
File,
|
|
|
|
|
SeekError,
|
|
|
|
|
GetSeekPosError,
|
|
|
|
|
seekTo,
|
|
|
|
|
seekBy,
|
|
|
|
|
getPos,
|
|
|
|
|
getEndPos,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
inner: aio.File,
|
|
|
|
|
|
|
|
|
|
fn asFile(self: File) std.fs.File {
|
|
|
|
|
return .{ .handle = self.inner.file.fd };
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-25 16:02:11 +00:00
|
|
|
pub fn handle(self: File) std.fs.File.Handle {
|
|
|
|
|
return self.inner.file.fd;
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-02 14:28:25 +00:00
|
|
|
pub fn init(file_: std.fs.File) !File {
|
|
|
|
|
return .{ .inner = aio.File.init(AsyncThread.current.executor, try xev.File.init(file_)) };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn open(path: []const u8, flags: std.fs.File.OpenFlags) !File {
|
2023-05-04 14:44:12 +00:00
|
|
|
return init(try callBlocking(std.fs.Dir.openFile, .{ std.fs.cwd(), path, flags }));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn access(path: []const u8, flags: std.fs.File.OpenFlags) !void {
|
|
|
|
|
return try callBlocking(std.fs.Dir.access, .{ std.fs.cwd(), path, flags });
|
2023-01-02 14:28:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn read(self: File, buf: []u8) !usize {
|
|
|
|
|
// NOTE(Corentin): Early return is required to avoid error with xev on Linux with io_uring backend.
|
2023-08-01 11:35:04 +00:00
|
|
|
if (buf.len == 0) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2023-01-02 14:28:25 +00:00
|
|
|
|
|
|
|
|
return self.inner.read(.{ .slice = buf }) catch |err| switch (err) {
|
|
|
|
|
// NOTE(Corentin): read shouldn't return an error on EOF, but a read length of 0 instead. This is to be iso with std.fs.File.
|
|
|
|
|
error.EOF => 0,
|
|
|
|
|
else => err,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn pread(self: File, buf: []u8, offset: u64) !usize {
|
|
|
|
|
// NOTE(Corentin): Early return is required to avoid error with xev on Linux with io_uring backend.
|
2023-08-01 11:35:04 +00:00
|
|
|
if (buf.len == 0) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2023-01-02 14:28:25 +00:00
|
|
|
|
|
|
|
|
return self.inner.pread(.{ .slice = buf }, offset) catch |err| switch (err) {
|
|
|
|
|
// NOTE(Corentin): pread shouldn't return an error on EOF, but a read length of 0 instead. This is to be iso with std.fs.File.
|
|
|
|
|
error.EOF => 0,
|
|
|
|
|
else => err,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn write(self: File, buf: []const u8) !usize {
|
|
|
|
|
return self.inner.write(.{ .slice = buf });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn pwrite(self: File, buf: []const u8, offset: u64) !usize {
|
|
|
|
|
return self.inner.pwrite(.{ .slice = buf }, offset);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn close(self: File) !void {
|
|
|
|
|
return self.inner.close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn reader(self: File) Reader {
|
|
|
|
|
return .{ .context = self };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn seekableStream(file: File) SeekableStream {
|
|
|
|
|
return .{ .context = file };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn writer(self: File) Writer {
|
|
|
|
|
return .{ .context = self };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn stat(self: File) !std.fs.File.Stat {
|
2023-05-04 14:44:12 +00:00
|
|
|
return try callBlocking(std.fs.File.stat, .{self.asFile()});
|
2023-01-02 14:28:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn seekBy(self: File, offset: i64) !void {
|
2023-05-04 14:44:12 +00:00
|
|
|
try callBlocking(std.fs.File.seekBy, .{ self.asFile(), offset });
|
2023-01-02 14:28:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn seekTo(self: File, offset: u64) !void {
|
2023-05-04 14:44:12 +00:00
|
|
|
try callBlocking(std.fs.File.seekTo, .{ self.asFile(), offset });
|
2023-01-02 14:28:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn getPos(self: File) !u64 {
|
2023-05-04 14:44:12 +00:00
|
|
|
return try callBlocking(std.fs.File.getPos, .{self.asFile()});
|
2023-01-02 14:28:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn getEndPos(self: File) !u64 {
|
2023-05-04 14:44:12 +00:00
|
|
|
return try callBlocking(std.fs.File.getEndPos, .{self.asFile()});
|
2023-01-02 14:28:25 +00:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
pub const Socket = struct {
|
2023-08-01 11:35:04 +00:00
|
|
|
pub fn Listener(comptime T: type) type {
|
|
|
|
|
return struct {
|
|
|
|
|
const Self = @This();
|
|
|
|
|
|
|
|
|
|
inner: T.Inner,
|
|
|
|
|
|
|
|
|
|
pub fn accept(self: *Self) !T {
|
|
|
|
|
return .{ .inner = try self.inner.accept() };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn close(self: *Self) !void {
|
|
|
|
|
return self.inner.close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn deinit(self: *Self) !void {
|
|
|
|
|
self.inner.shutdown();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-02 14:28:25 +00:00
|
|
|
pub const TCP = struct {
|
2023-08-01 11:35:04 +00:00
|
|
|
const Inner = aio.TCP;
|
|
|
|
|
|
|
|
|
|
pub const Reader = std.io.GenericReader(TCP, stdx.meta.FnSignature(TCP.read, null).ReturnErrorSet.?, TCP.read);
|
|
|
|
|
pub const Writer = std.io.GenericWriter(TCP, stdx.meta.FnSignature(TCP.write, null).ReturnErrorSet.?, TCP.write);
|
2023-01-02 14:28:25 +00:00
|
|
|
|
|
|
|
|
inner: aio.TCP,
|
|
|
|
|
|
2023-08-01 11:35:04 +00:00
|
|
|
pub fn listen(addr: std.net.Address) !Listener(TCP) {
|
|
|
|
|
var self: Listener(TCP) = .{
|
|
|
|
|
.inner = aio.TCP.init(AsyncThread.current.executor, try xev.TCP.init(addr)),
|
|
|
|
|
};
|
|
|
|
|
try self.inner.tcp.bind(addr);
|
|
|
|
|
try self.inner.tcp.listen(1024);
|
|
|
|
|
return self;
|
2023-01-02 14:28:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn deinit(self: *TCP) void {
|
|
|
|
|
self.inner.shutdown();
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-01 11:35:04 +00:00
|
|
|
pub fn accept(self: *TCP) !TCP {
|
|
|
|
|
return .{ .inner = try self.inner.accept() };
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-02 14:28:25 +00:00
|
|
|
pub fn connect(self: *TCP, addr: std.net.Address) !void {
|
|
|
|
|
return self.inner.connect(addr);
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-01 11:35:04 +00:00
|
|
|
pub fn read(self: TCP, buf: []u8) !usize {
|
2023-01-02 14:28:25 +00:00
|
|
|
return self.inner.read(.{ .slice = buf });
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-01 11:35:04 +00:00
|
|
|
pub fn write(self: TCP, buf: []const u8) !usize {
|
2023-01-02 14:28:25 +00:00
|
|
|
return self.inner.write(.{ .slice = buf });
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-01 11:35:04 +00:00
|
|
|
pub fn close(self: TCP) !void {
|
|
|
|
|
// defer self.* = undefined;
|
2023-01-02 14:28:25 +00:00
|
|
|
return self.inner.close();
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-01 11:35:04 +00:00
|
|
|
pub fn reader(self: TCP) Reader {
|
2023-01-02 14:28:25 +00:00
|
|
|
return .{ .context = self };
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-01 11:35:04 +00:00
|
|
|
pub fn writer(self: TCP) Writer {
|
2023-01-02 14:28:25 +00:00
|
|
|
return .{ .context = self };
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
pub const UDP = struct {
|
2023-08-01 11:35:04 +00:00
|
|
|
const Inner = aio.TCP;
|
|
|
|
|
|
|
|
|
|
pub const Reader = std.io.GenericReader(UDP, stdx.meta.FnSignature(UDP.read, null).ReturnErrorSet.?, UDP.read);
|
2023-01-02 14:28:25 +00:00
|
|
|
pub const WriterContext = struct {
|
|
|
|
|
file: UDP,
|
|
|
|
|
addr: std.net.Address,
|
|
|
|
|
};
|
2023-08-01 11:35:04 +00:00
|
|
|
pub const Writer = std.io.GenericWriter(WriterContext, stdx.meta.FnSignature(UDP.write, null).ReturnErrorSet.?, struct {
|
2023-05-04 14:44:12 +00:00
|
|
|
fn callBlocking(self: WriterContext, buf: []const u8) !usize {
|
2023-01-02 14:28:25 +00:00
|
|
|
return self.file.write(self.addr, buf);
|
|
|
|
|
}
|
|
|
|
|
}.call);
|
|
|
|
|
|
|
|
|
|
inner: aio.UDP,
|
|
|
|
|
|
2023-08-01 11:35:04 +00:00
|
|
|
pub fn listen(addr: std.net.Address) !Listener(UDP) {
|
|
|
|
|
var self: Listener(UDP) = .{
|
|
|
|
|
.inner = aio.UDP.init(AsyncThread.current.executor, try xev.UDP.init(addr)),
|
|
|
|
|
};
|
|
|
|
|
try self.inner.udp.bind(addr);
|
|
|
|
|
try self.inner.udp.listen(1024);
|
|
|
|
|
return self;
|
2023-01-02 14:28:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn read(self: UDP, buf: []u8) !usize {
|
|
|
|
|
return self.inner.read(.{ .slice = buf });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn write(self: UDP, addr: std.net.Address, buf: []const u8) !usize {
|
|
|
|
|
return self.inner.write(addr, .{ .slice = buf });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn close(self: *UDP) !void {
|
|
|
|
|
defer self.* = undefined;
|
|
|
|
|
return self.inner.close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn reader(self: File) Reader {
|
|
|
|
|
return .{ .context = self };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn writer(self: File, addr: std.net.Address) Writer {
|
|
|
|
|
return .{
|
|
|
|
|
.context = .{
|
|
|
|
|
.file = self,
|
|
|
|
|
.addr = addr,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
2023-10-24 14:36:22 +00:00
|
|
|
pub fn Channel(comptime T: type, capacity: usize) type {
|
|
|
|
|
return struct {
|
|
|
|
|
const Self = @This();
|
2024-01-11 15:40:15 +00:00
|
|
|
const Inner = channel_mod.Channel(T, capacity);
|
2023-10-24 14:36:22 +00:00
|
|
|
|
|
|
|
|
inner: Inner,
|
|
|
|
|
|
|
|
|
|
pub fn init() Self {
|
|
|
|
|
return .{ .inner = Inner.init(&AsyncThread.current.executor.exec) };
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-11 15:40:15 +00:00
|
|
|
pub fn initWithLen(len: usize) Self {
|
|
|
|
|
return .{ .inner = Inner.initWithLen(&AsyncThread.current.executor.exec, len) };
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-24 14:36:22 +00:00
|
|
|
pub fn close(self: *Self) void {
|
|
|
|
|
self.inner.close();
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-11 15:40:15 +00:00
|
|
|
pub fn try_send(self: *Self, val: T) bool {
|
|
|
|
|
return self.inner.try_send(val);
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-24 14:36:22 +00:00
|
|
|
pub fn send(self: *Self, val: T) void {
|
2024-02-28 15:47:37 +00:00
|
|
|
self.inner.send(val);
|
2023-10-24 14:36:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn recv(self: *Self) ?T {
|
|
|
|
|
return self.inner.recv();
|
|
|
|
|
}
|
2024-01-11 15:40:15 +00:00
|
|
|
|
|
|
|
|
pub fn try_recv(self: *Self) ?T {
|
|
|
|
|
return self.inner.try_recv();
|
|
|
|
|
}
|
2023-10-24 14:36:22 +00:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-11 15:40:15 +00:00
|
|
|
pub fn channel(comptime T: type, len: usize, comptime capacity: usize) Channel(T, capacity) {
|
|
|
|
|
return Channel(T, capacity).initWithLen(len);
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-02 14:28:25 +00:00
|
|
|
pub const Mutex = struct {
|
2024-03-14 11:43:33 +00:00
|
|
|
const VoidChannel = Channel(void, 1);
|
2023-01-02 14:28:25 +00:00
|
|
|
|
|
|
|
|
inner: VoidChannel,
|
|
|
|
|
|
|
|
|
|
pub fn init() Mutex {
|
2024-03-14 11:43:33 +00:00
|
|
|
return .{ .inner = VoidChannel.init() };
|
2023-01-02 14:28:25 +00:00
|
|
|
}
|
|
|
|
|
|
2024-03-14 11:43:33 +00:00
|
|
|
pub fn lock(self: *Mutex) void {
|
|
|
|
|
self.inner.send({});
|
2023-01-02 14:28:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn unlock(self: *Mutex) void {
|
|
|
|
|
_ = self.inner.recv();
|
|
|
|
|
}
|
|
|
|
|
};
|
2023-08-01 11:35:04 +00:00
|
|
|
|
2024-03-14 11:43:33 +00:00
|
|
|
pub const LogFn = fn (
|
2023-08-01 11:35:04 +00:00
|
|
|
comptime message_level: std.log.Level,
|
2024-03-14 11:43:33 +00:00
|
|
|
comptime scope: @TypeOf(.enum_literal),
|
2023-08-01 11:35:04 +00:00
|
|
|
comptime format: []const u8,
|
|
|
|
|
args: anytype,
|
2024-03-14 11:43:33 +00:00
|
|
|
) void;
|
2024-01-16 14:13:45 +00:00
|
|
|
|
2024-03-14 11:43:33 +00:00
|
|
|
pub fn logFn(comptime fallbackLogFn: LogFn) LogFn {
|
|
|
|
|
return struct {
|
|
|
|
|
const Self = @This();
|
|
|
|
|
|
|
|
|
|
var mu: ?Mutex = null;
|
|
|
|
|
|
|
|
|
|
pub fn call(
|
|
|
|
|
comptime message_level: std.log.Level,
|
|
|
|
|
comptime scope: @TypeOf(.enum_literal),
|
|
|
|
|
comptime format: []const u8,
|
|
|
|
|
args: anytype,
|
|
|
|
|
) void {
|
|
|
|
|
if (coro.inCoro() == false) {
|
|
|
|
|
return fallbackLogFn(message_level, scope, format, args);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const level_txt = comptime message_level.asText();
|
|
|
|
|
const prefix2 = if (scope == .default) ": " else "(" ++ @tagName(scope) ++ "): ";
|
|
|
|
|
const stderr = getStdErr().writer();
|
|
|
|
|
var bw = std.io.bufferedWriter(stderr);
|
|
|
|
|
const writer = bw.writer();
|
|
|
|
|
|
|
|
|
|
var mutex = Self.mu orelse blk: {
|
|
|
|
|
Self.mu = Mutex.init();
|
|
|
|
|
break :blk Self.mu.?;
|
|
|
|
|
};
|
|
|
|
|
mutex.lock();
|
|
|
|
|
defer mutex.unlock();
|
|
|
|
|
nosuspend {
|
|
|
|
|
writer.print(level_txt ++ prefix2 ++ format ++ "\n", args) catch return;
|
|
|
|
|
bw.flush() catch return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}.call;
|
2023-08-01 11:35:04 +00:00
|
|
|
}
|