diff --git a/src/Server.zig b/src/Server.zig index a943678..1ccdf34 100644 --- a/src/Server.zig +++ b/src/Server.zig @@ -45,7 +45,7 @@ cursor: Cursor, // Lua data keymaps: std.AutoHashMap(u64, Keymap), -hooks: std.ArrayList(*Hook), +hooks: std.AutoHashMap(i32, *Hook), events: Events, remote_lua_clients: std.DoublyLinkedList, @@ -102,7 +102,7 @@ pub fn init(self: *Server) void { .cursor = undefined, .remote_lua_manager = RemoteLuaManager.init() catch Utils.oomPanic(), .keymaps = .init(gpa), - .hooks = try .initCapacity(gpa, 10), // TODO: choose how many slots to start with + .hooks = .init(gpa), .events = try .init(gpa), .remote_lua_clients = .{}, }; diff --git a/src/lua/Hook.zig b/src/lua/Hook.zig index e128c27..1969021 100644 --- a/src/lua/Hook.zig +++ b/src/lua/Hook.zig @@ -5,54 +5,70 @@ const zlua = @import("zlua"); const THook = @import("../types/Hook.zig"); const Utils = @import("../Utils.zig"); +const LuaUtils = @import("LuaUtils.zig"); const gpa = std.heap.c_allocator; const server = &@import("../main.zig").server; /// ---Create a new hook on an event -/// ---@param string|string[] event(s) -/// ---@param table options +/// ---@param events string|string[] +/// ---@param options table +/// ---@return number id pub fn add(L: *zlua.Lua) i32 { L.checkType(2, .table); - errdefer Utils.oomPanic(); - var hook: *THook = try gpa.create(THook); - hook.events = try std.ArrayList([]const u8).initCapacity(gpa, 1); + var hook: *THook = gpa.create(THook) catch Utils.oomPanic(); // We support both a string and a table of strings as the first value of // add. Regardless of which type is passed in we create an arraylist of // []const u8's if (L.isTable(1)) { + hook.events = gpa.alloc(comptime []const u8, L.objectLen(1)) catch Utils.oomPanic(); + var i: u32 = 0; L.pushNil(); while (L.next(1)) { if (L.isString(-1)) { const s = L.checkString(-1); - try hook.events.append(gpa, s); + hook.events[i] = gpa.dupe(u8, s) catch Utils.oomPanic(); + i += 1; } L.pop(1); } } else if (L.isString(1)) { + hook.events = gpa.alloc(comptime []const u8, 1) catch Utils.oomPanic(); const s = L.checkString(1); - try hook.events.append(gpa, s); + hook.events[0] = gpa.dupe(u8, s) catch Utils.oomPanic(); } _ = L.pushString("callback"); _ = L.getTable(2); if (L.isFunction(-1)) { - hook.options.lua_cb_ref_idx = try L.ref(zlua.registry_index); + hook.options.lua_cb_ref_idx = L.ref(zlua.registry_index) catch Utils.oomPanic(); } - try server.hooks.append(gpa, hook); + // TEST: this should be safe as the lua_cb_ref_idx's should never be the same + // but that all really depends on the implementation of the hashmap + server.hooks.put(hook.options.lua_cb_ref_idx, hook) catch Utils.oomPanic(); - for (hook.events.items) |value| { - try server.events.put(value, hook); + for (hook.events) |value| { + server.events.put(value, hook) catch Utils.oomPanic(); } - return 0; + L.pushInteger(hook.options.lua_cb_ref_idx); + return 1; } +/// ---Create an existing hook +/// ---@param id number +/// ---@return boolean has it been deleted pub fn del(L: *zlua.Lua) i32 { - // TODO: impl - _ = L; - return 0; + const hook_id = LuaUtils.coerceInteger(i32, L.checkInteger(1)) catch L.raiseErrorStr("hook id must be a valid number", .{}); + const hook = server.hooks.get(hook_id); + if (hook == null) L.raiseErrorStr("hook {} does not exist", .{hook_id}); + + for (hook.?.events) |value| { + server.events.del(value, hook.?); + } + L.pushBoolean(server.hooks.remove(hook_id)); + return 1; } diff --git a/src/types/Events.zig b/src/types/Events.zig index 02a69b4..f437856 100644 --- a/src/types/Events.zig +++ b/src/types/Events.zig @@ -4,6 +4,8 @@ const std = @import("std"); const Hook = @import("Hook.zig"); +const server = &@import("../main.zig").server; + const Node = struct { hook: *const Hook, node: std.SinglyLinkedList.Node, @@ -36,8 +38,15 @@ pub fn put(self: *Events, key: []const u8, hook: *const Hook) !void { ll.prepend(&data.node); } -// TODO: figure out deletion -// pub fn del(self: *Events, key: ???) !void {} +pub fn del(self: *Events, key: []const u8, hook: *const Hook) void { + if (self.events.get(key)) |e| { + var node = e.first; + while (node) |n| : (node = n.next) { + const data: *Node = @fieldParentPtr("node", n); + if (data.hook.options.lua_cb_ref_idx == hook.options.lua_cb_ref_idx) e.remove(n); + } + } +} pub fn exec(self: *Events, event: []const u8, args: anytype) void { if (self.events.get(event)) |e| { diff --git a/src/types/Hook.zig b/src/types/Hook.zig index 364f29c..6c6a155 100644 --- a/src/types/Hook.zig +++ b/src/types/Hook.zig @@ -11,7 +11,7 @@ const Event = @import("Events.zig"); const RemoteLua = @import("../RemoteLua.zig"); const Lua = &@import("../main.zig").lua; -events: std.ArrayList([]const u8), // a list of events +events: [][]const u8, // a list of events options: struct { // group: []const u8, // TODO: do we need groups? /// This is the location of the callback lua function in the lua registry