diff options
Diffstat (limited to 'src/lib/channel.zig')
-rw-r--r-- | src/lib/channel.zig | 54 |
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; +} |