refactor: move command and EventHandler out of the tui module
This commit is contained in:
parent
f41fb97d02
commit
16c5471126
45 changed files with 132 additions and 81 deletions
194
src/EventHandler.zig
Normal file
194
src/EventHandler.zig
Normal file
|
@ -0,0 +1,194 @@
|
|||
const std = @import("std");
|
||||
const tp = @import("thespian");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const ArrayList = std.ArrayList;
|
||||
const Self = @This();
|
||||
const EventHandler = Self;
|
||||
|
||||
ptr: *anyopaque,
|
||||
vtable: *const VTable,
|
||||
|
||||
pub const VTable = struct {
|
||||
deinit: *const fn (ctx: *anyopaque) void,
|
||||
send: *const fn (ctx: *anyopaque, from: tp.pid_ref, m: tp.message) tp.result,
|
||||
type_name: []const u8,
|
||||
};
|
||||
|
||||
pub fn to_owned(pimpl: anytype) Self {
|
||||
const impl = @typeInfo(@TypeOf(pimpl));
|
||||
const child: type = impl.Pointer.child;
|
||||
return .{
|
||||
.ptr = pimpl,
|
||||
.vtable = comptime &.{
|
||||
.type_name = @typeName(child),
|
||||
.deinit = struct {
|
||||
pub fn deinit(ctx: *anyopaque) void {
|
||||
return child.deinit(@as(*child, @ptrCast(@alignCast(ctx))));
|
||||
}
|
||||
}.deinit,
|
||||
.send = struct {
|
||||
pub fn receive(ctx: *anyopaque, from_: tp.pid_ref, m: tp.message) tp.result {
|
||||
_ = try child.receive(@as(*child, @ptrCast(@alignCast(ctx))), from_, m);
|
||||
}
|
||||
}.receive,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
pub fn static(T: type) Self {
|
||||
return .{
|
||||
.ptr = &none,
|
||||
.vtable = comptime &.{
|
||||
.type_name = @typeName(T),
|
||||
.deinit = struct {
|
||||
pub fn deinit(_: *anyopaque) void {}
|
||||
}.deinit,
|
||||
.send = struct {
|
||||
pub fn receive(_: *anyopaque, from_: tp.pid_ref, m: tp.message) tp.result {
|
||||
_ = try T.receive(from_, m);
|
||||
}
|
||||
}.receive,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
var none = {};
|
||||
|
||||
pub fn to_unowned(pimpl: anytype) Self {
|
||||
const impl = @typeInfo(@TypeOf(pimpl));
|
||||
const child: type = impl.Pointer.child;
|
||||
return .{
|
||||
.ptr = pimpl,
|
||||
.vtable = comptime &.{
|
||||
.type_name = @typeName(child),
|
||||
.deinit = struct {
|
||||
pub fn deinit(_: *anyopaque) void {}
|
||||
}.deinit,
|
||||
.send = if (@hasDecl(child, "send")) struct {
|
||||
pub fn send(ctx: *anyopaque, from_: tp.pid_ref, m: tp.message) tp.result {
|
||||
_ = try child.send(@as(*child, @ptrCast(@alignCast(ctx))), from_, m);
|
||||
}
|
||||
}.send else struct {
|
||||
pub fn receive(ctx: *anyopaque, from_: tp.pid_ref, m: tp.message) tp.result {
|
||||
_ = try child.receive(@as(*child, @ptrCast(@alignCast(ctx))), from_, m);
|
||||
}
|
||||
}.receive,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
pub fn bind(pimpl: anytype, comptime f: *const fn (ctx: @TypeOf(pimpl), from: tp.pid_ref, m: tp.message) tp.result) Self {
|
||||
const impl = @typeInfo(@TypeOf(pimpl));
|
||||
const child: type = impl.Pointer.child;
|
||||
return .{
|
||||
.ptr = pimpl,
|
||||
.vtable = comptime &.{
|
||||
.type_name = @typeName(child),
|
||||
.deinit = struct {
|
||||
pub fn deinit(_: *anyopaque) void {}
|
||||
}.deinit,
|
||||
.send = struct {
|
||||
pub fn receive(ctx: *anyopaque, from_: tp.pid_ref, m: tp.message) tp.result {
|
||||
return @call(.auto, f, .{ @as(*child, @ptrCast(@alignCast(ctx))), from_, m });
|
||||
}
|
||||
}.receive,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: Self) void {
|
||||
return self.vtable.deinit(self.ptr);
|
||||
}
|
||||
|
||||
pub fn dynamic_cast(self: Self, comptime T: type) ?*T {
|
||||
return if (std.mem.eql(u8, self.vtable.type_name, @typeName(T)))
|
||||
@as(*T, @ptrCast(@alignCast(self.ptr)))
|
||||
else
|
||||
null;
|
||||
}
|
||||
|
||||
pub fn msg(self: Self, m: anytype) tp.result {
|
||||
return self.vtable.send(self.ptr, tp.self_pid(), tp.message.fmt(m));
|
||||
}
|
||||
|
||||
pub fn send(self: Self, from_: tp.pid_ref, m: tp.message) tp.result {
|
||||
return self.vtable.send(self.ptr, from_, m);
|
||||
}
|
||||
|
||||
pub fn empty(allocator: Allocator) !Self {
|
||||
const child: type = struct {};
|
||||
const widget = try allocator.create(child);
|
||||
widget.* = .{};
|
||||
return .{
|
||||
.ptr = widget,
|
||||
.plane = &widget.plane,
|
||||
.vtable = comptime &.{
|
||||
.type_name = @typeName(child),
|
||||
.deinit = struct {
|
||||
pub fn deinit(ctx: *anyopaque, allocator_: Allocator) void {
|
||||
return allocator_.destroy(@as(*child, @ptrCast(@alignCast(ctx))));
|
||||
}
|
||||
}.deinit,
|
||||
.send = struct {
|
||||
pub fn receive(_: *anyopaque, _: tp.pid_ref, _: tp.message) tp.result {
|
||||
return false;
|
||||
}
|
||||
}.receive,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
pub const List = struct {
|
||||
allocator: Allocator,
|
||||
list: ArrayList(EventHandler),
|
||||
recursion_check: bool = false,
|
||||
|
||||
pub fn init(allocator: Allocator) List {
|
||||
return .{
|
||||
.allocator = allocator,
|
||||
.list = ArrayList(EventHandler).init(allocator),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *List) void {
|
||||
for (self.list.items) |*i|
|
||||
i.deinit();
|
||||
self.list.deinit();
|
||||
}
|
||||
|
||||
pub fn add(self: *List, h: EventHandler) !void {
|
||||
(try self.list.addOne()).* = h;
|
||||
}
|
||||
|
||||
pub fn remove(self: *List, h: EventHandler) !void {
|
||||
return self.remove_ptr(h.ptr);
|
||||
}
|
||||
|
||||
pub fn remove_ptr(self: *List, p_: *anyopaque) void {
|
||||
for (self.list.items, 0..) |*p, i|
|
||||
if (p.ptr == p_)
|
||||
self.list.orderedRemove(i).deinit();
|
||||
}
|
||||
|
||||
pub fn msg(self: *const List, m: anytype) tp.result {
|
||||
return self.send(tp.self_pid(), tp.message.fmt(m));
|
||||
}
|
||||
|
||||
pub fn send(self: *const List, from: tp.pid_ref, m: tp.message) tp.result {
|
||||
if (self.recursion_check)
|
||||
@panic("recursive EventHandler call");
|
||||
const self_nonconst = @constCast(self);
|
||||
self_nonconst.recursion_check = true;
|
||||
defer self_nonconst.recursion_check = false;
|
||||
tp.trace(tp.channel.event, m);
|
||||
var buf: [tp.max_message_size]u8 = undefined;
|
||||
@memcpy(buf[0..m.buf.len], m.buf);
|
||||
const m_: tp.message = .{ .buf = buf[0..m.buf.len] };
|
||||
var e: ?error{Exit} = null;
|
||||
for (self.list.items) |*i|
|
||||
i.send(from, m_) catch |e_| {
|
||||
e = e_;
|
||||
};
|
||||
return if (e) |e_| e_;
|
||||
}
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue