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