aboutsummaryrefslogtreecommitdiff
path: root/src/lib/channel.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/channel.zig')
-rw-r--r--src/lib/channel.zig54
1 files changed, 54 insertions, 0 deletions
diff --git a/src/lib/channel.zig b/src/lib/channel.zig
new file mode 100644
index 0000000..de02f2b
--- /dev/null
+++ b/src/lib/channel.zig
@@ -0,0 +1,54 @@
+// SPDX-FileCopyrightText: 2024 Himbeer <himbeer@disroot.org>
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+
+const std = @import("std");
+const Allocator = std.mem.Allocator;
+
+pub const Error = error{
+ WouldBlock,
+};
+
+pub const Messages = std.TailQueue([]const u8);
+var message_allocator: Allocator = undefined;
+
+const Queues = std.AutoArrayHashMap(usize, Messages);
+var queues: Queues = undefined;
+
+// The channel takes ownership of `bytes`.
+pub fn pass(channel: usize, bytes: []const u8) !void {
+ const entry = try queues.getOrPut(channel);
+ if (!entry.found_existing) {
+ initQueue(entry.value_ptr);
+ }
+
+ const node = try message_allocator.create(Messages.Node);
+ node.data = bytes;
+ entry.value_ptr.append(node);
+}
+
+pub fn receive(channel: usize, buffer: []u8) !usize {
+ const messages = queues.getPtr(channel) orelse return Error.WouldBlock;
+ const message = messages.popFirst() orelse return Error.WouldBlock;
+
+ defer message_allocator.free(message.data);
+ defer message_allocator.destroy(message);
+
+ const len = @min(buffer.len, message.data.len);
+ @memcpy(buffer[0..len], message.data[0..len]);
+
+ return len;
+}
+
+fn initQueue(messages: *Messages) void {
+ messages.* = .{};
+}
+
+pub fn init(allocator: Allocator) void {
+ queues = Queues.init(allocator);
+ message_allocator = allocator;
+}
+
+pub fn messageAllocator() Allocator {
+ return message_allocator;
+}