From aaaae38fa1e3399a1b9bf0468edaf6d5e3bd9edc Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 25 Oct 2022 20:55:41 -0700 Subject: [PATCH] pkg/objc: more message send stuff --- pkg/objc/class.zig | 11 +++++++++++ pkg/objc/main.zig | 1 + pkg/objc/msg_send.zig | 19 ++++++++++++++++++- pkg/objc/object.zig | 10 ++++++++++ pkg/objc/sel.zig | 9 +++++++-- 5 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 pkg/objc/object.zig diff --git a/pkg/objc/class.zig b/pkg/objc/class.zig index 95dddb5af..f655c82eb 100644 --- a/pkg/objc/class.zig +++ b/pkg/objc/class.zig @@ -26,6 +26,17 @@ test "getClass" { test "msgSend" { const testing = std.testing; const NSObject = Class.getClass("NSObject").?; + + // Should work with primitives const id = NSObject.msgSend(c.id, objc.Sel.registerName("alloc"), .{}); try testing.expect(id != null); + { + const obj: objc.Object = .{ .value = id }; + obj.msgSend(void, objc.sel("dealloc"), .{}); + } + + // Should work with our wrappers + const obj = NSObject.msgSend(objc.Object, objc.Sel.registerName("alloc"), .{}); + try testing.expect(obj.value != null); + obj.msgSend(void, objc.sel("dealloc"), .{}); } diff --git a/pkg/objc/main.zig b/pkg/objc/main.zig index 6c6270d4c..6eefc51fe 100644 --- a/pkg/objc/main.zig +++ b/pkg/objc/main.zig @@ -1,5 +1,6 @@ pub const c = @import("c.zig"); pub usingnamespace @import("class.zig"); +pub usingnamespace @import("object.zig"); pub usingnamespace @import("sel.zig"); test { diff --git a/pkg/objc/msg_send.zig b/pkg/objc/msg_send.zig index 6f276b593..4f2eaf699 100644 --- a/pkg/objc/msg_send.zig +++ b/pkg/objc/msg_send.zig @@ -19,9 +19,26 @@ pub fn MsgSend(comptime T: type) type { sel: objc.Sel, args: anytype, ) Return { + // Build our function type and call it const Fn = MsgSendFn(Return, @TypeOf(target.value), @TypeOf(args)); const msg_send_ptr = @ptrCast(std.meta.FnPtr(Fn), &c.objc_msgSend); - return @call(.{}, msg_send_ptr, .{ target.value, sel } ++ args); + const result = @call(.{}, msg_send_ptr, .{ target.value, sel } ++ args); + + // This is a special nicety: if the return type is one of our + // public structs then we wrap the msgSend id result with it. + // This lets msgSend magically work with Object and so on. + const is_pkg_struct = comptime is_pkg_struct: { + for (@typeInfo(objc).Struct.decls) |decl| { + if (decl.is_pub and Return == @field(objc, decl.name)) { + break :is_pkg_struct true; + } + } + + break :is_pkg_struct false; + }; + + if (!is_pkg_struct) return result; + return .{ .value = result }; } }; } diff --git a/pkg/objc/object.zig b/pkg/objc/object.zig new file mode 100644 index 000000000..41c779eeb --- /dev/null +++ b/pkg/objc/object.zig @@ -0,0 +1,10 @@ +const std = @import("std"); +const c = @import("c.zig"); +const objc = @import("main.zig"); +const MsgSend = @import("msg_send.zig").MsgSend; + +pub const Object = struct { + value: c.id, + + pub usingnamespace MsgSend(Object); +}; diff --git a/pkg/objc/sel.zig b/pkg/objc/sel.zig index 4c4c62f7a..23c629f48 100644 --- a/pkg/objc/sel.zig +++ b/pkg/objc/sel.zig @@ -1,6 +1,11 @@ const std = @import("std"); const c = @import("c.zig"); +// Shorthand, equivalent to Sel.registerName +pub inline fn sel(name: [:0]const u8) Sel { + return Sel.registerName(name); +} + pub const Sel = struct { value: c.SEL, @@ -20,6 +25,6 @@ pub const Sel = struct { test { const testing = std.testing; - const sel = Sel.registerName("yo"); - try testing.expectEqualStrings("yo", sel.getName()); + const s = Sel.registerName("yo"); + try testing.expectEqualStrings("yo", s.getName()); }