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
|
/// BotAdapter is the closure that we register in zircon as the
|
||||||
/// message callback.
|
/// message callback.
|
||||||
///
|
///
|
||||||
|
|
@ -82,10 +77,23 @@ pub const BotAdapter = struct {
|
||||||
/// See
|
/// See
|
||||||
/// - https://modern.ircdocs.horse/, for what kinds of messages exists in the IRC protocol documentation,
|
/// - 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.
|
/// - 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) {
|
switch (message) {
|
||||||
.PRIVMSG => |msg| {
|
.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
|
// create message
|
||||||
const bot_message = BotMessage.init_owned(
|
const bot_message = BotMessage.init_owned(
|
||||||
|
|
@ -125,19 +133,23 @@ pub const BotAdapter = struct {
|
||||||
return .{ .PRIVMSG = .{ .prefix = null, .targets = "#eru-admin", .text = err_msg } };
|
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 {
|
pub fn closure(self: *BotAdapter) zircon.MessageClosure {
|
||||||
return .{
|
return .{
|
||||||
.ptr = self,
|
.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.
|
/// toIRC converts a bot response and converts it to a IRC message.
|
||||||
fn toIRC(response: BotResponse) zircon.Message {
|
fn toIRC(response: BotResponse) zircon.Message {
|
||||||
switch (response) {
|
switch (response) {
|
||||||
|
|
@ -150,30 +162,27 @@ fn toIRC(response: BotResponse) zircon.Message {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test "substitute" {
|
fn priv_msg(text: []const u8) zircon.Message {
|
||||||
var bot_adapter = try BotAdapter.init(std.testing.allocator);
|
return .{ .PRIVMSG = .{
|
||||||
defer bot_adapter.deinit();
|
.prefix = .{ .nick = "jassob", .host = "localhost", .user = "jassob" },
|
||||||
const prefix = zircon.Prefix{ .nick = "jassob", .user = "jassob", .host = "localhost" };
|
|
||||||
const msg = zircon.Message{
|
|
||||||
.PRIVMSG = .{
|
|
||||||
.prefix = prefix,
|
|
||||||
.targets = "#test",
|
.targets = "#test",
|
||||||
.text = "hello world",
|
.text = text,
|
||||||
},
|
} };
|
||||||
};
|
}
|
||||||
if (bot_adapter.callback(msg)) |_| {
|
|
||||||
|
test "substitute" {
|
||||||
|
var adapter = try BotAdapter.init(std.testing.allocator);
|
||||||
|
defer adapter.deinit();
|
||||||
|
if (BotAdapter.callback(&adapter, priv_msg("hello world"))) |_| {
|
||||||
@panic("unexpected response");
|
@panic("unexpected response");
|
||||||
}
|
}
|
||||||
const cmd_msg = zircon.Message{
|
const response = BotAdapter.callback(&adapter, priv_msg("s/world/zig/"));
|
||||||
.PRIVMSG = .{
|
|
||||||
.prefix = prefix,
|
|
||||||
.targets = "#test",
|
|
||||||
.text = "s/world/zig/",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const response = bot_adapter.callback(cmd_msg);
|
|
||||||
try std.testing.expect(response != null);
|
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" {
|
test "get empty backlog message" {
|
||||||
|
|
@ -182,5 +191,9 @@ test "get empty backlog message" {
|
||||||
const msg = zircon.Message{
|
const msg = zircon.Message{
|
||||||
.PRIVMSG = .{ .prefix = null, .targets = "#eru-admin", .text = "!backlog 0" },
|
.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