feat: implement a 2-way channel for message passing
This commit is contained in:
parent
52ac8d952f
commit
d5e66caf21
33
src/lib.zig
33
src/lib.zig
|
@ -1,8 +1,29 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
const Log2Int = std.math.Log2Int;
|
const Log2Int = std.math.Log2Int;
|
||||||
|
|
||||||
pub fn Channel(comptime T: type) type {
|
const EmuMessage = enum { Pause, Resume, Quit };
|
||||||
|
const GuiMessage = enum { Paused, Quit };
|
||||||
|
|
||||||
|
pub const TwoWayChannel = struct {
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
emu: Channel(EmuMessage),
|
||||||
|
gui: Channel(GuiMessage),
|
||||||
|
|
||||||
|
pub fn init(items: []u8) Self {
|
||||||
|
comptime std.debug.assert(@sizeOf(EmuMessage) == @sizeOf(GuiMessage));
|
||||||
|
comptime std.debug.assert(@sizeOf(@typeInfo([]u8).Pointer.child) == @sizeOf(EmuMessage));
|
||||||
|
|
||||||
|
std.debug.assert(items.len % 2 == 0);
|
||||||
|
|
||||||
|
const left = @ptrCast([*]EmuMessage, items)[0 .. items.len / 2];
|
||||||
|
const right = @ptrCast([*]GuiMessage, items)[items.len / 2 .. items.len];
|
||||||
|
|
||||||
|
return .{ .emu = Channel(EmuMessage).init(left), .gui = Channel(GuiMessage).init(right) };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fn Channel(comptime T: type) type {
|
||||||
return struct {
|
return struct {
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
const Index = usize;
|
const Index = usize;
|
||||||
|
@ -29,12 +50,12 @@ pub fn Channel(comptime T: type) type {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push(self: *Self, value: T) Error!void {
|
pub fn push(self: *Self, value: T) void {
|
||||||
const read_idx = self.read.load(.Acquire);
|
const read_idx = self.read.load(.Acquire);
|
||||||
const write_idx = self.write.load(.Acquire);
|
const write_idx = self.write.load(.Acquire);
|
||||||
|
|
||||||
// Check to see if Queue is full
|
// Check to see if Queue is full
|
||||||
if (write_idx - read_idx == self.buf.len) return Error.buffer_full;
|
if (write_idx - read_idx == self.buf.len) @panic("Channel: Buffer is full");
|
||||||
|
|
||||||
self.buf[self.mask(write_idx)] = value;
|
self.buf[self.mask(write_idx)] = value;
|
||||||
|
|
||||||
|
@ -49,7 +70,7 @@ pub fn Channel(comptime T: type) type {
|
||||||
if (read_idx == write_idx) return null;
|
if (read_idx == write_idx) return null;
|
||||||
|
|
||||||
std.atomic.fence(.Acquire);
|
std.atomic.fence(.Acquire);
|
||||||
const value = self.buf[self.mask(self.read)];
|
const value = self.buf[self.mask(read_idx)];
|
||||||
|
|
||||||
std.atomic.fence(.Release);
|
std.atomic.fence(.Release);
|
||||||
self.read.store(read_idx + 1, .Release);
|
self.read.store(read_idx + 1, .Release);
|
||||||
|
@ -159,4 +180,4 @@ pub inline fn rotr(comptime T: type, x: T, r: anytype) T {
|
||||||
|
|
||||||
const ar = @intCast(Log2Int(T), @mod(r, @typeInfo(T).Int.bits));
|
const ar = @intCast(Log2Int(T), @mod(r, @typeInfo(T).Int.bits));
|
||||||
return x >> ar | x << (1 +% ~ar);
|
return x >> ar | x << (1 +% ~ar);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue