Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use the linker for selectors instead of the runtime #18

Merged
merged 1 commit into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions avf_audio_manual.zig
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const c = @import("c.zig");
const cf = @import("core_foundation.zig");
const ns = @import("foundation.zig");
const objc = @import("objc.zig");

// ------------------------------------------------------------------------------------------------
// Types
Expand Down
39 changes: 7 additions & 32 deletions generator.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1063,7 +1063,6 @@ fn Generator(comptime WriterType: type) type {
try self.generateEnumerations();
try self.generateContainers();
try self.generateClasses();
try self.generateSelectors();
try self.generateInit();
}

Expand All @@ -1077,22 +1076,9 @@ fn Generator(comptime WriterType: type) type {
}
}

fn generateSelectors(self: *Self) !void {
var it = self.selectors.iterator();
while (it.next()) |entry| {
const method_name = entry.key_ptr.*;
try self.writer.print("var sel_", .{});
try self.generateSelectorName(method_name);
try self.writer.print(": *c.objc_selector = undefined;\n", .{});
}
try self.writer.print("\n", .{});
}

fn generateInit(self: *Self) !void {
try self.writer.print("pub fn init() void {{\n", .{});
try self.generateInitClasses();
try self.writer.print("\n", .{});
try self.generateInitSelectors();
try self.writer.print("}}\n", .{});
}

Expand All @@ -1106,16 +1092,6 @@ fn Generator(comptime WriterType: type) type {
}
}

fn generateInitSelectors(self: *Self) !void {
var it = self.selectors.iterator();
while (it.next()) |entry| {
const method_name = entry.key_ptr.*;
try self.writer.print(" sel_", .{});
try self.generateSelectorName(method_name);
try self.writer.print(" = c.sel_registerName(\"{s}\").?;\n", .{method_name});
}
}

fn generateEnumerations(self: *Self) !void {
for (self.enums.items) |e| {
try self.writer.writeAll("\n");
Expand Down Expand Up @@ -1283,9 +1259,7 @@ fn Generator(comptime WriterType: type) type {
try self.writer.print(") ", .{});
try self.generateType(method.return_type);
try self.writer.print(" {{\n", .{});
try self.writer.writeAll(" return @as(");
try self.generateObjcSignature(method);
try self.writer.writeAll(", @ptrCast(&c.objc_msgSend))(");
try self.writer.writeAll(" return objc.msgSend(");
try self.generateMethodArgs(method);
try self.writer.print(");\n", .{});
try self.writer.print(" }}\n", .{});
Expand Down Expand Up @@ -1371,13 +1345,14 @@ fn Generator(comptime WriterType: type) type {
} else {
try self.writer.print("T.class()", .{});
}
try self.writer.print(", sel_", .{});
try self.generateSelectorName(method.name);

for (method.params.items) |param| {
try self.writer.writeAll(", ");
try self.writer.print(", \"{s}\", ", .{method.name});
try self.generateType(method.return_type);
try self.writer.writeAll(", .{");
for (method.params.items, 0..) |param, i| {
if (i != 0) try self.writer.writeAll(", ");
try self.writer.print("{s}_", .{param.name});
}
try self.writer.writeAll("}");
}

fn getBlockType(param: Param) ?Type.Function {
Expand Down
1 change: 1 addition & 0 deletions metal_manual.zig
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const c = @import("c.zig");
const cf = @import("core_foundation.zig");
const ns = @import("foundation.zig");
const objc = @import("objc.zig");

// ------------------------------------------------------------------------------------------------
// Opaque types
Expand Down
2,256 changes: 19 additions & 2,237 deletions src/app_kit.zig

Large diffs are not rendered by default.

393 changes: 98 additions & 295 deletions src/avf_audio.zig

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion src/core_midi.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,4 @@ const ns = @import("foundation.zig");

// ------------------------------------------------------------------------------------------------
// Types

pub fn init() void {}
1,251 changes: 321 additions & 930 deletions src/foundation.zig

Large diffs are not rendered by default.

5,247 changes: 1,538 additions & 3,709 deletions src/metal.zig

Large diffs are not rendered by default.

64 changes: 62 additions & 2 deletions src/objc.zig
Original file line number Diff line number Diff line change
@@ -1,8 +1,68 @@
const std = @import("std");
const builtin = @import("builtin");

extern fn objc_autoreleasePoolPop(pool: *anyopaque) void;
extern fn objc_autoreleasePoolPush() *anyopaque;

pub const autoreleasePoolPop = objc_autoreleasePoolPop;
pub const autoreleasePoolPush = objc_autoreleasePoolPush;

const c = @import("c.zig");
pub const Protocol = c.objc_object;
// APIs that are part of libobjc's public API.
pub const Protocol = opaque {};

/// Calls `objc_msgSend(receiver, selector, args...)` (or `objc_msgSend_stret` if needed).
///
/// Be careful. The return type and argument types *must* match the Objective-C method's signature.
/// No compile-time verification is performed.
pub fn msgSend(receiver: anytype, comptime selector: []const u8, return_type: type, args: anytype) return_type {
const n_colons = comptime std.mem.count(u8, selector, ":");
if (comptime n_colons != args.len) {
@compileError(std.fmt.comptimePrint(
"Selector `{s}` has {} argument{s}, but {} were given",
.{ selector, n_colons, (if (n_colons == 1) "" else "s"), args.len },
));
}

// TODO: Consider run-time signature verification if `builtin.mode == .Debug` (or use some other
// toggle). Register the selector, then call `class_getInstanceMethod()` or
// `class_getClassMethod()`, then call `method_getTypeEncoding()`, and then parse the string and
// validate it against `receiver` and `args`.

const fn_type = comptime init: {
var params: []const std.builtin.Type.Fn.Param = &.{
.{
.is_generic = false,
.is_noalias = false,
.type = @TypeOf(receiver),
},
.{
.is_generic = false,
.is_noalias = false,
.type = [*:0]c_char,
},
};
for (@typeInfo(@TypeOf(args)).Struct.fields) |field| {
params = params ++
.{.{
.is_generic = false,
.is_noalias = false,
.type = field.type,
}};
}
break :init std.builtin.Type{
.Fn = .{
.calling_convention = .C,
.is_generic = false,
.is_var_args = false,
.return_type = return_type,
.params = params,
},
};
};

const needs_fpret = comptime builtin.target.cpu.arch == .x86_64 and (return_type == f32 or return_type == f64);
const needs_stret = comptime builtin.target.cpu.arch == .x86_64 and @sizeOf(return_type) > 16;
const msg_send_fn_name = comptime if (needs_stret) "objc_msgSend_stret" else if (needs_fpret) "objc_msgSend_fpret" else "objc_msgSend";
const msg_send_fn = @extern(*const @Type(fn_type), .{ .name = msg_send_fn_name ++ "$" ++ selector });
return @call(.auto, msg_send_fn, .{ receiver, undefined } ++ args);
}
108 changes: 27 additions & 81 deletions src/quartz_core.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const c = @import("c.zig");
const cg = @import("core_graphics.zig");
const mtl = @import("metal.zig");
const ns = @import("foundation.zig");
const objc = @import("objc.zig");

pub const Layer = opaque {
pub fn class() *c.objc_class {
Expand All @@ -24,10 +25,10 @@ pub const MetalDrawable = opaque {
pub usingnamespace mtl.Drawable.Methods(T);

pub fn texture(self_: *T) *mtl.Texture {
return @as(*const fn (*T, *c.objc_selector) callconv(.C) *mtl.Texture, @ptrCast(&c.objc_msgSend))(self_, sel_texture);
return objc.msgSend(self_, "texture", *mtl.Texture, .{});
}
pub fn layer(self_: *T) *MetalLayer {
return @as(*const fn (*T, *c.objc_selector) callconv(.C) *MetalLayer, @ptrCast(&c.objc_msgSend))(self_, sel_layer);
return objc.msgSend(self_, "layer", *MetalLayer, .{});
}
};
}
Expand All @@ -44,139 +45,84 @@ pub const MetalLayer = opaque {
pub usingnamespace Layer.Methods(T);

pub fn nextDrawable(self_: *T) ?*MetalDrawable {
return @as(*const fn (*T, *c.objc_selector) callconv(.C) ?*MetalDrawable, @ptrCast(&c.objc_msgSend))(self_, sel_nextDrawable);
return objc.msgSend(self_, "nextDrawable", ?*MetalDrawable, .{});
}
pub fn device(self_: *T) ?*mtl.Device {
return @as(*const fn (*T, *c.objc_selector) callconv(.C) ?*mtl.Device, @ptrCast(&c.objc_msgSend))(self_, sel_device);
return objc.msgSend(self_, "device", ?*mtl.Device, .{});
}
pub fn setDevice(self_: *T, device_: ?*mtl.Device) void {
return @as(*const fn (*T, *c.objc_selector, ?*mtl.Device) callconv(.C) void, @ptrCast(&c.objc_msgSend))(self_, sel_setDevice_, device_);
return objc.msgSend(self_, "setDevice:", void, .{device_});
}
pub fn preferredDevice(self_: *T) ?*mtl.Device {
return @as(*const fn (*T, *c.objc_selector) callconv(.C) ?*mtl.Device, @ptrCast(&c.objc_msgSend))(self_, sel_preferredDevice);
return objc.msgSend(self_, "preferredDevice", ?*mtl.Device, .{});
}
pub fn pixelFormat(self_: *T) mtl.PixelFormat {
return @as(*const fn (*T, *c.objc_selector) callconv(.C) mtl.PixelFormat, @ptrCast(&c.objc_msgSend))(self_, sel_pixelFormat);
return objc.msgSend(self_, "pixelFormat", mtl.PixelFormat, .{});
}
pub fn setPixelFormat(self_: *T, pixelFormat_: mtl.PixelFormat) void {
return @as(*const fn (*T, *c.objc_selector, mtl.PixelFormat) callconv(.C) void, @ptrCast(&c.objc_msgSend))(self_, sel_setPixelFormat_, pixelFormat_);
return objc.msgSend(self_, "setPixelFormat:", void, .{pixelFormat_});
}
pub fn framebufferOnly(self_: *T) bool {
return @as(*const fn (*T, *c.objc_selector) callconv(.C) bool, @ptrCast(&c.objc_msgSend))(self_, sel_framebufferOnly);
return objc.msgSend(self_, "framebufferOnly", bool, .{});
}
pub fn setFramebufferOnly(self_: *T, framebufferOnly_: bool) void {
return @as(*const fn (*T, *c.objc_selector, bool) callconv(.C) void, @ptrCast(&c.objc_msgSend))(self_, sel_setFramebufferOnly_, framebufferOnly_);
return objc.msgSend(self_, "setFramebufferOnly:", void, .{framebufferOnly_});
}
pub fn drawableSize(self_: *T) cg.Size {
return @as(*const fn (*T, *c.objc_selector) callconv(.C) cg.Size, @ptrCast(&c.objc_msgSend))(self_, sel_drawableSize);
return objc.msgSend(self_, "drawableSize", cg.Size, .{});
}
pub fn setDrawableSize(self_: *T, drawableSize_: cg.Size) void {
return @as(*const fn (*T, *c.objc_selector, cg.Size) callconv(.C) void, @ptrCast(&c.objc_msgSend))(self_, sel_setDrawableSize_, drawableSize_);
return objc.msgSend(self_, "setDrawableSize:", void, .{drawableSize_});
}
pub fn maximumDrawableCount(self_: *T) ns.UInteger {
return @as(*const fn (*T, *c.objc_selector) callconv(.C) ns.UInteger, @ptrCast(&c.objc_msgSend))(self_, sel_maximumDrawableCount);
return objc.msgSend(self_, "maximumDrawableCount", ns.UInteger, .{});
}
pub fn setMaximumDrawableCount(self_: *T, maximumDrawableCount_: ns.UInteger) void {
return @as(*const fn (*T, *c.objc_selector, ns.UInteger) callconv(.C) void, @ptrCast(&c.objc_msgSend))(self_, sel_setMaximumDrawableCount_, maximumDrawableCount_);
return objc.msgSend(self_, "setMaximumDrawableCount:", void, .{maximumDrawableCount_});
}
pub fn presentsWithTransaction(self_: *T) bool {
return @as(*const fn (*T, *c.objc_selector) callconv(.C) bool, @ptrCast(&c.objc_msgSend))(self_, sel_presentsWithTransaction);
return objc.msgSend(self_, "presentsWithTransaction", bool, .{});
}
pub fn setPresentsWithTransaction(self_: *T, presentsWithTransaction_: bool) void {
return @as(*const fn (*T, *c.objc_selector, bool) callconv(.C) void, @ptrCast(&c.objc_msgSend))(self_, sel_setPresentsWithTransaction_, presentsWithTransaction_);
return objc.msgSend(self_, "setPresentsWithTransaction:", void, .{presentsWithTransaction_});
}
pub fn colorspace(self_: *T) cg.ColorSpaceRef {
return @as(*const fn (*T, *c.objc_selector) callconv(.C) cg.ColorSpaceRef, @ptrCast(&c.objc_msgSend))(self_, sel_colorspace);
return objc.msgSend(self_, "colorspace", cg.ColorSpaceRef, .{});
}
pub fn setColorspace(self_: *T, colorspace_: cg.ColorSpaceRef) void {
return @as(*const fn (*T, *c.objc_selector, cg.ColorSpaceRef) callconv(.C) void, @ptrCast(&c.objc_msgSend))(self_, sel_setColorspace_, colorspace_);
return objc.msgSend(self_, "setColorspace:", void, .{colorspace_});
}
pub fn wantsExtendedDynamicRangeContent(self_: *T) bool {
return @as(*const fn (*T, *c.objc_selector) callconv(.C) bool, @ptrCast(&c.objc_msgSend))(self_, sel_wantsExtendedDynamicRangeContent);
return objc.msgSend(self_, "wantsExtendedDynamicRangeContent", bool, .{});
}
pub fn setWantsExtendedDynamicRangeContent(self_: *T, wantsExtendedDynamicRangeContent_: bool) void {
return @as(*const fn (*T, *c.objc_selector, bool) callconv(.C) void, @ptrCast(&c.objc_msgSend))(self_, sel_setWantsExtendedDynamicRangeContent_, wantsExtendedDynamicRangeContent_);
return objc.msgSend(self_, "setWantsExtendedDynamicRangeContent:", void, .{wantsExtendedDynamicRangeContent_});
}
// pub fn EDRMetadata(self_: *T) ?*EDRMetadata {
// return @as(*const fn (*T, *c.objc_selector) callconv(.C) ?*EDRMetadata, @ptrCast(&c.objc_msgSend))(self_, sel_EDRMetadata);
// return objc.msgSend(self_, "EDRMetadata", ?*EDRMetadata, .{});
// }
// pub fn setEDRMetadata(self_: *T, EDRMetadata_: ?*EDRMetadata) void {
// return @as(*const fn (*T, *c.objc_selector, ?*EDRMetadata) callconv(.C) void, @ptrCast(&c.objc_msgSend))(self_, sel_setEDRMetadata_, EDRMetadata_);
// return objc.msgSend(self_, "setEDRMetadata:", void, .{EDRMetadata_});
// }
pub fn displaySyncEnabled(self_: *T) bool {
return @as(*const fn (*T, *c.objc_selector) callconv(.C) bool, @ptrCast(&c.objc_msgSend))(self_, sel_displaySyncEnabled);
return objc.msgSend(self_, "displaySyncEnabled", bool, .{});
}
pub fn setDisplaySyncEnabled(self_: *T, displaySyncEnabled_: bool) void {
return @as(*const fn (*T, *c.objc_selector, bool) callconv(.C) void, @ptrCast(&c.objc_msgSend))(self_, sel_setDisplaySyncEnabled_, displaySyncEnabled_);
return objc.msgSend(self_, "setDisplaySyncEnabled:", void, .{displaySyncEnabled_});
}
pub fn allowsNextDrawableTimeout(self_: *T) bool {
return @as(*const fn (*T, *c.objc_selector) callconv(.C) bool, @ptrCast(&c.objc_msgSend))(self_, sel_allowsNextDrawableTimeout);
return objc.msgSend(self_, "allowsNextDrawableTimeout", bool, .{});
}
pub fn setAllowsNextDrawableTimeout(self_: *T, allowsNextDrawableTimeout_: bool) void {
return @as(*const fn (*T, *c.objc_selector, bool) callconv(.C) void, @ptrCast(&c.objc_msgSend))(self_, sel_setAllowsNextDrawableTimeout_, allowsNextDrawableTimeout_);
return objc.msgSend(self_, "setAllowsNextDrawableTimeout:", void, .{allowsNextDrawableTimeout_});
}
};
}
};
var class_Layer: *c.objc_class = undefined;
var class_MetalLayer: *c.objc_class = undefined;
var sel_setColorspace_: *c.objc_selector = undefined;
//var sel_EDRMetadata: *c.objc_selector = undefined;
var sel_setWantsExtendedDynamicRangeContent_: *c.objc_selector = undefined;
var sel_setDevice_: *c.objc_selector = undefined;
var sel_setPixelFormat_: *c.objc_selector = undefined;
var sel_setPresentsWithTransaction_: *c.objc_selector = undefined;
var sel_setMaximumDrawableCount_: *c.objc_selector = undefined;
var sel_setDrawableSize_: *c.objc_selector = undefined;
var sel_device: *c.objc_selector = undefined;
var sel_drawableSize: *c.objc_selector = undefined;
var sel_framebufferOnly: *c.objc_selector = undefined;
var sel_texture: *c.objc_selector = undefined;
var sel_developerHUDProperties: *c.objc_selector = undefined;
var sel_wantsExtendedDynamicRangeContent: *c.objc_selector = undefined;
var sel_preferredDevice: *c.objc_selector = undefined;
var sel_allowsNextDrawableTimeout: *c.objc_selector = undefined;
var sel_maximumDrawableCount: *c.objc_selector = undefined;
var sel_presentsWithTransaction: *c.objc_selector = undefined;
var sel_displaySyncEnabled: *c.objc_selector = undefined;
var sel_pixelFormat: *c.objc_selector = undefined;
var sel_colorspace: *c.objc_selector = undefined;
var sel_setDisplaySyncEnabled_: *c.objc_selector = undefined;
var sel_setFramebufferOnly_: *c.objc_selector = undefined;
var sel_setAllowsNextDrawableTimeout_: *c.objc_selector = undefined;
var sel_layer: *c.objc_selector = undefined;
var sel_nextDrawable: *c.objc_selector = undefined;
var sel_setEDRMetadata_: *c.objc_selector = undefined;
var sel_setDeveloperHUDProperties_: *c.objc_selector = undefined;

pub fn init() void {
class_Layer = c.objc_getClass("CALayer").?;
class_MetalLayer = c.objc_getClass("CAMetalLayer").?;

sel_setColorspace_ = c.sel_registerName("setColorspace:").?;
//sel_EDRMetadata = c.sel_registerName("EDRMetadata").?;
sel_setWantsExtendedDynamicRangeContent_ = c.sel_registerName("setWantsExtendedDynamicRangeContent:").?;
sel_setDevice_ = c.sel_registerName("setDevice:").?;
sel_setPixelFormat_ = c.sel_registerName("setPixelFormat:").?;
sel_setPresentsWithTransaction_ = c.sel_registerName("setPresentsWithTransaction:").?;
sel_setMaximumDrawableCount_ = c.sel_registerName("setMaximumDrawableCount:").?;
sel_setDrawableSize_ = c.sel_registerName("setDrawableSize:").?;
sel_device = c.sel_registerName("device").?;
sel_drawableSize = c.sel_registerName("drawableSize").?;
sel_framebufferOnly = c.sel_registerName("framebufferOnly").?;
sel_texture = c.sel_registerName("texture").?;
sel_wantsExtendedDynamicRangeContent = c.sel_registerName("wantsExtendedDynamicRangeContent").?;
sel_preferredDevice = c.sel_registerName("preferredDevice").?;
sel_allowsNextDrawableTimeout = c.sel_registerName("allowsNextDrawableTimeout").?;
sel_maximumDrawableCount = c.sel_registerName("maximumDrawableCount").?;
sel_presentsWithTransaction = c.sel_registerName("presentsWithTransaction").?;
sel_displaySyncEnabled = c.sel_registerName("displaySyncEnabled").?;
sel_pixelFormat = c.sel_registerName("pixelFormat").?;
sel_colorspace = c.sel_registerName("colorspace").?;
sel_setDisplaySyncEnabled_ = c.sel_registerName("setDisplaySyncEnabled:").?;
sel_setFramebufferOnly_ = c.sel_registerName("setFramebufferOnly:").?;
sel_setAllowsNextDrawableTimeout_ = c.sel_registerName("setAllowsNextDrawableTimeout:").?;
sel_layer = c.sel_registerName("layer").?;
sel_nextDrawable = c.sel_registerName("nextDrawable").?;
sel_setEDRMetadata_ = c.sel_registerName("setEDRMetadata:").?;
}
Loading