refactor(main): remove one layer of indirection
This commit removes the BotAdapter.erased_callback function, which served as a generic version of BotAdapter.callback that was legible for zircon.MessageClosure. However, it is clearer to document how that mechanism works. Therefore we remove the BotAdapter.erased_callback and instead makes BotAdapter.callback match the zircon.MessageClosure.callbackFn signature.
This commit is contained in:
parent
7d444204ef
commit
2e1416eb21
1 changed files with 47 additions and 34 deletions
81
src/main.zig
81
src/main.zig
|
|
@ -44,11 +44,6 @@ pub fn main() !void {
|
|||
};
|
||||
}
|
||||
|
||||
pub const Adapter = struct {
|
||||
ptr: *anyopaque,
|
||||
callbackFn: *const fn (*anyopaque, zircon.Message) ?zircon.Message,
|
||||
};
|
||||
|
||||
/// BotAdapter is the closure that we register in zircon as the
|
||||
/// message callback.
|
||||
///
|
||||
|
|
@ -82,10 +77,23 @@ pub const BotAdapter = struct {
|
|||
/// See
|
||||
/// - https://modern.ircdocs.horse/, for what kinds of messages exists in the IRC protocol documentation,
|
||||
/// - https://github.com/Jassob/zircon/blob/main/src/message.zig, for zircon documentation.
|
||||
pub fn callback(self: *BotAdapter, message: zircon.Message) ?zircon.Message {
|
||||
///
|
||||
/// NOTE: This function does not have a self-parameter, this is
|
||||
/// because this function is called as a "generic" function
|
||||
/// that is parameterized in the pointer argument (otherwise
|
||||
/// zircon library would not be able to be reused).
|
||||
///
|
||||
/// That's why the first thing we do is perform some casting
|
||||
/// magic to convert our pointer back to a BotAdapter
|
||||
/// pointer. This is safe as long as we know that we
|
||||
/// registered a BotAdapter closure and there are no other
|
||||
/// callbacks registered.
|
||||
pub fn callback(ptr: *anyopaque, message: zircon.Message) ?zircon.Message {
|
||||
const self: *@This() = @ptrCast(@alignCast(ptr));
|
||||
|
||||
switch (message) {
|
||||
.PRIVMSG => |msg| {
|
||||
const nick = if (msg.prefix != null and msg.prefix.?.nick != null) msg.prefix.?.nick.? else "unknown";
|
||||
const nick = nickFromPrefix(msg.prefix);
|
||||
|
||||
// create message
|
||||
const bot_message = BotMessage.init_owned(
|
||||
|
|
@ -125,19 +133,23 @@ pub const BotAdapter = struct {
|
|||
return .{ .PRIVMSG = .{ .prefix = null, .targets = "#eru-admin", .text = err_msg } };
|
||||
}
|
||||
|
||||
pub fn erased_callback(self: *anyopaque, message: zircon.Message) ?zircon.Message {
|
||||
const a: *@This() = @ptrCast(@alignCast(self));
|
||||
return a.callback(message);
|
||||
}
|
||||
|
||||
pub fn closure(self: *BotAdapter) zircon.MessageClosure {
|
||||
return .{
|
||||
.ptr = self,
|
||||
.callbackFn = BotAdapter.erased_callback,
|
||||
.callbackFn = BotAdapter.callback,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/// nickFromPrefix returns a nick if it exists in the prefix or
|
||||
/// "unknown" otherwise.
|
||||
fn nickFromPrefix(prefix: ?zircon.Prefix) []const u8 {
|
||||
if (prefix == null or prefix.?.nick == null) {
|
||||
return "unknown";
|
||||
}
|
||||
return prefix.?.nick.?;
|
||||
}
|
||||
|
||||
/// toIRC converts a bot response and converts it to a IRC message.
|
||||
fn toIRC(response: BotResponse) zircon.Message {
|
||||
switch (response) {
|
||||
|
|
@ -150,30 +162,27 @@ fn toIRC(response: BotResponse) zircon.Message {
|
|||
}
|
||||
}
|
||||
|
||||
fn priv_msg(text: []const u8) zircon.Message {
|
||||
return .{ .PRIVMSG = .{
|
||||
.prefix = .{ .nick = "jassob", .host = "localhost", .user = "jassob" },
|
||||
.targets = "#test",
|
||||
.text = text,
|
||||
} };
|
||||
}
|
||||
|
||||
test "substitute" {
|
||||
var bot_adapter = try BotAdapter.init(std.testing.allocator);
|
||||
defer bot_adapter.deinit();
|
||||
const prefix = zircon.Prefix{ .nick = "jassob", .user = "jassob", .host = "localhost" };
|
||||
const msg = zircon.Message{
|
||||
.PRIVMSG = .{
|
||||
.prefix = prefix,
|
||||
.targets = "#test",
|
||||
.text = "hello world",
|
||||
},
|
||||
};
|
||||
if (bot_adapter.callback(msg)) |_| {
|
||||
var adapter = try BotAdapter.init(std.testing.allocator);
|
||||
defer adapter.deinit();
|
||||
if (BotAdapter.callback(&adapter, priv_msg("hello world"))) |_| {
|
||||
@panic("unexpected response");
|
||||
}
|
||||
const cmd_msg = zircon.Message{
|
||||
.PRIVMSG = .{
|
||||
.prefix = prefix,
|
||||
.targets = "#test",
|
||||
.text = "s/world/zig/",
|
||||
},
|
||||
};
|
||||
const response = bot_adapter.callback(cmd_msg);
|
||||
const response = BotAdapter.callback(&adapter, priv_msg("s/world/zig/"));
|
||||
|
||||
try std.testing.expect(response != null);
|
||||
try std.testing.expectEqualStrings("jassob: \"hello zig\"", response.?.PRIVMSG.text);
|
||||
try std.testing.expectEqualStrings(
|
||||
"jassob: \"hello zig\"",
|
||||
response.?.PRIVMSG.text,
|
||||
);
|
||||
}
|
||||
|
||||
test "get empty backlog message" {
|
||||
|
|
@ -182,5 +191,9 @@ test "get empty backlog message" {
|
|||
const msg = zircon.Message{
|
||||
.PRIVMSG = .{ .prefix = null, .targets = "#eru-admin", .text = "!backlog 0" },
|
||||
};
|
||||
try std.testing.expectEqualDeep("no matching message", bot_adapter.callback(msg).?.PRIVMSG.text);
|
||||
|
||||
try std.testing.expectEqualDeep(
|
||||
"no matching message",
|
||||
BotAdapter.callback(&bot_adapter, msg).?.PRIVMSG.text,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue