feat: implement a 2-way channel for message passing
This commit is contained in:
		
							
								
								
									
										33
									
								
								src/lib.zig
									
									
									
									
									
								
							
							
						
						
									
										33
									
								
								src/lib.zig
									
									
									
									
									
								
							@@ -1,8 +1,29 @@
 | 
			
		||||
const std = @import("std");
 | 
			
		||||
 | 
			
		||||
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 {
 | 
			
		||||
        const Self = @This();
 | 
			
		||||
        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 write_idx = self.write.load(.Acquire);
 | 
			
		||||
 | 
			
		||||
            // 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;
 | 
			
		||||
 | 
			
		||||
@@ -49,7 +70,7 @@ pub fn Channel(comptime T: type) type {
 | 
			
		||||
            if (read_idx == write_idx) return null;
 | 
			
		||||
 | 
			
		||||
            std.atomic.fence(.Acquire);
 | 
			
		||||
            const value = self.buf[self.mask(self.read)];
 | 
			
		||||
            const value = self.buf[self.mask(read_idx)];
 | 
			
		||||
 | 
			
		||||
            std.atomic.fence(.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));
 | 
			
		||||
    return x >> ar | x << (1 +% ~ar);
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user