This commit is contained in:
parent
9b8ba849b0
commit
47b842d6b8
6 changed files with 35 additions and 35 deletions
|
@ -26,7 +26,7 @@ pub fn build(b: *std.Build) !void {
|
||||||
});
|
});
|
||||||
tests.linkSystemLibrary("objc");
|
tests.linkSystemLibrary("objc");
|
||||||
tests.linkFramework("Foundation");
|
tests.linkFramework("Foundation");
|
||||||
try addAppleSDK(b, &tests.root_module);
|
try addAppleSDK(b, tests.root_module);
|
||||||
b.installArtifact(tests);
|
b.installArtifact(tests);
|
||||||
|
|
||||||
const test_step = b.step("test", "Run tests");
|
const test_step = b.step("test", "Run tests");
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
|
const alloc = std.heap.raw_c_allocator;
|
||||||
|
|
||||||
const objc = @import("main.zig");
|
const objc = @import("main.zig");
|
||||||
|
|
||||||
// We have to use the raw C allocator for all heap allocation in here
|
// We have to use the raw C allocator for all heap allocation in here
|
||||||
// because the objc runtime expects `malloc` to be used. If you don't use
|
// because the objc runtime expects `malloc` to be used. If you don't use
|
||||||
// malloc you'll get segfaults because the objc runtime will try to free
|
// malloc you'll get segfaults because the objc runtime will try to free
|
||||||
// the memory with `free`.
|
// the memory with `free`.
|
||||||
const alloc = std.heap.raw_c_allocator;
|
|
||||||
|
|
||||||
/// Creates a new block type with captured (closed over) values.
|
/// Creates a new block type with captured (closed over) values.
|
||||||
///
|
///
|
||||||
/// The CapturesArg is the a struct of captured values that will become
|
/// The CapturesArg is the a struct of captured values that will become
|
||||||
|
@ -34,7 +34,7 @@ pub fn Block(
|
||||||
) type {
|
) type {
|
||||||
return struct {
|
return struct {
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
const captures_info = @typeInfo(Captures).Struct;
|
const captures_info = @typeInfo(Captures).@"struct";
|
||||||
const InvokeFn = FnType(anyopaque);
|
const InvokeFn = FnType(anyopaque);
|
||||||
const descriptor: Descriptor = .{
|
const descriptor: Descriptor = .{
|
||||||
.reserved = 0,
|
.reserved = 0,
|
||||||
|
@ -63,7 +63,7 @@ pub fn Block(
|
||||||
var ctx = try alloc.create(Context);
|
var ctx = try alloc.create(Context);
|
||||||
errdefer alloc.destroy(ctx);
|
errdefer alloc.destroy(ctx);
|
||||||
|
|
||||||
const flags: BlockFlags = .{ .stret = @typeInfo(Return) == .Struct };
|
const flags: BlockFlags = .{ .stret = @typeInfo(Return) == .@"struct" };
|
||||||
ctx.isa = NSConcreteStackBlock;
|
ctx.isa = NSConcreteStackBlock;
|
||||||
ctx.flags = @bitCast(flags);
|
ctx.flags = @bitCast(flags);
|
||||||
ctx.invoke = @ptrCast(func);
|
ctx.invoke = @ptrCast(func);
|
||||||
|
@ -120,7 +120,7 @@ pub fn Block(
|
||||||
}
|
}
|
||||||
|
|
||||||
return @Type(.{
|
return @Type(.{
|
||||||
.Fn = .{
|
.@"fn" = .{
|
||||||
.calling_convention = .C,
|
.calling_convention = .C,
|
||||||
.is_generic = false,
|
.is_generic = false,
|
||||||
.is_var_args = false,
|
.is_var_args = false,
|
||||||
|
@ -135,40 +135,40 @@ pub fn Block(
|
||||||
/// This is the type of a block structure that is passed as the first
|
/// This is the type of a block structure that is passed as the first
|
||||||
/// argument to any block invocation. See Block.
|
/// argument to any block invocation. See Block.
|
||||||
fn BlockContext(comptime Captures: type, comptime InvokeFn: type) type {
|
fn BlockContext(comptime Captures: type, comptime InvokeFn: type) type {
|
||||||
const captures_info = @typeInfo(Captures).Struct;
|
const captures_info = @typeInfo(Captures).@"struct";
|
||||||
var fields: [captures_info.fields.len + 5]std.builtin.Type.StructField = undefined;
|
var fields: [captures_info.fields.len + 5]std.builtin.Type.StructField = undefined;
|
||||||
fields[0] = .{
|
fields[0] = .{
|
||||||
.name = "isa",
|
.name = "isa",
|
||||||
.type = ?*anyopaque,
|
.type = ?*anyopaque,
|
||||||
.default_value = null,
|
.default_value_ptr = null,
|
||||||
.is_comptime = false,
|
.is_comptime = false,
|
||||||
.alignment = @alignOf(*anyopaque),
|
.alignment = @alignOf(*anyopaque),
|
||||||
};
|
};
|
||||||
fields[1] = .{
|
fields[1] = .{
|
||||||
.name = "flags",
|
.name = "flags",
|
||||||
.type = c_int,
|
.type = c_int,
|
||||||
.default_value = null,
|
.default_value_ptr = null,
|
||||||
.is_comptime = false,
|
.is_comptime = false,
|
||||||
.alignment = @alignOf(c_int),
|
.alignment = @alignOf(c_int),
|
||||||
};
|
};
|
||||||
fields[2] = .{
|
fields[2] = .{
|
||||||
.name = "reserved",
|
.name = "reserved",
|
||||||
.type = c_int,
|
.type = c_int,
|
||||||
.default_value = null,
|
.default_value_ptr = null,
|
||||||
.is_comptime = false,
|
.is_comptime = false,
|
||||||
.alignment = @alignOf(c_int),
|
.alignment = @alignOf(c_int),
|
||||||
};
|
};
|
||||||
fields[3] = .{
|
fields[3] = .{
|
||||||
.name = "invoke",
|
.name = "invoke",
|
||||||
.type = *const InvokeFn,
|
.type = *const InvokeFn,
|
||||||
.default_value = null,
|
.default_value_ptr = null,
|
||||||
.is_comptime = false,
|
.is_comptime = false,
|
||||||
.alignment = @typeInfo(*const InvokeFn).Pointer.alignment,
|
.alignment = @typeInfo(*const InvokeFn).pointer.alignment,
|
||||||
};
|
};
|
||||||
fields[4] = .{
|
fields[4] = .{
|
||||||
.name = "descriptor",
|
.name = "descriptor",
|
||||||
.type = *const Descriptor,
|
.type = *const Descriptor,
|
||||||
.default_value = null,
|
.default_value_ptr = null,
|
||||||
.is_comptime = false,
|
.is_comptime = false,
|
||||||
.alignment = @alignOf(*Descriptor),
|
.alignment = @alignOf(*Descriptor),
|
||||||
};
|
};
|
||||||
|
@ -183,14 +183,14 @@ fn BlockContext(comptime Captures: type, comptime InvokeFn: type) type {
|
||||||
fields[i] = .{
|
fields[i] = .{
|
||||||
.name = capture.name,
|
.name = capture.name,
|
||||||
.type = capture.type,
|
.type = capture.type,
|
||||||
.default_value = null,
|
.default_value_ptr = null,
|
||||||
.is_comptime = false,
|
.is_comptime = false,
|
||||||
.alignment = capture.alignment,
|
.alignment = capture.alignment,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return @Type(.{
|
return @Type(.{
|
||||||
.Struct = .{
|
.@"struct" = .{
|
||||||
.layout = .@"extern",
|
.layout = .@"extern",
|
||||||
.fields = &fields,
|
.fields = &fields,
|
||||||
.decls = &.{},
|
.decls = &.{},
|
||||||
|
|
|
@ -6,7 +6,7 @@ pub const c = @cImport({
|
||||||
/// This is a funky helper to help with the fact that some macOS
|
/// This is a funky helper to help with the fact that some macOS
|
||||||
/// SDKs have an i8 return value for bools and some have stdbool.
|
/// SDKs have an i8 return value for bools and some have stdbool.
|
||||||
pub fn boolResult(comptime Fn: type, result: anytype) bool {
|
pub fn boolResult(comptime Fn: type, result: anytype) bool {
|
||||||
const fn_info = @typeInfo(Fn).Fn;
|
const fn_info = @typeInfo(Fn).@"fn";
|
||||||
return switch (fn_info.return_type.?) {
|
return switch (fn_info.return_type.?) {
|
||||||
bool => result,
|
bool => result,
|
||||||
i8 => result == 1,
|
i8 => result == 1,
|
||||||
|
|
|
@ -57,8 +57,8 @@ pub const Class = struct {
|
||||||
// imp should be a function with C calling convention
|
// imp should be a function with C calling convention
|
||||||
// whose first two arguments are a `c.id` and a `c.SEL`.
|
// whose first two arguments are a `c.id` and a `c.SEL`.
|
||||||
pub fn replaceMethod(self: Class, name: [:0]const u8, imp: anytype) void {
|
pub fn replaceMethod(self: Class, name: [:0]const u8, imp: anytype) void {
|
||||||
const fn_info = @typeInfo(@TypeOf(imp)).Fn;
|
const fn_info = @typeInfo(@TypeOf(imp)).@"fn";
|
||||||
assert(fn_info.calling_convention == .C);
|
assert(fn_info.calling_convention.eql(.c));
|
||||||
assert(fn_info.is_var_args == false);
|
assert(fn_info.is_var_args == false);
|
||||||
assert(fn_info.params.len >= 2);
|
assert(fn_info.params.len >= 2);
|
||||||
assert(fn_info.params[0].type == c.id);
|
assert(fn_info.params[0].type == c.id);
|
||||||
|
@ -71,8 +71,8 @@ pub const Class = struct {
|
||||||
// whose first two arguments are a `c.id` and a `c.SEL`.
|
// whose first two arguments are a `c.id` and a `c.SEL`.
|
||||||
pub fn addMethod(self: Class, name: [:0]const u8, imp: anytype) !bool {
|
pub fn addMethod(self: Class, name: [:0]const u8, imp: anytype) !bool {
|
||||||
const Fn = @TypeOf(imp);
|
const Fn = @TypeOf(imp);
|
||||||
const fn_info = @typeInfo(Fn).Fn;
|
const fn_info = @typeInfo(Fn).@"fn";
|
||||||
assert(fn_info.calling_convention == .C);
|
assert(fn_info.calling_convention.eql(.c));
|
||||||
assert(fn_info.is_var_args == false);
|
assert(fn_info.is_var_args == false);
|
||||||
assert(fn_info.params.len >= 2);
|
assert(fn_info.params.len >= 2);
|
||||||
assert(fn_info.params[0].type == c.id);
|
assert(fn_info.params[0].type == c.id);
|
||||||
|
|
|
@ -83,14 +83,14 @@ pub const Encoding = union(enum) {
|
||||||
c.Class, objc.Class => .class,
|
c.Class, objc.Class => .class,
|
||||||
c.id, objc.Object => .object,
|
c.id, objc.Object => .object,
|
||||||
else => switch (@typeInfo(T)) {
|
else => switch (@typeInfo(T)) {
|
||||||
.Array => |arr| .{ .array = .{ .len = arr.len, .arr_type = arr.child } },
|
.array => |arr| .{ .array = .{ .len = arr.len, .arr_type = arr.child } },
|
||||||
.Struct => .{ .structure = .{ .struct_type = T, .show_type_spec = true } },
|
.@"struct" => .{ .structure = .{ .struct_type = T, .show_type_spec = true } },
|
||||||
.Union => .{ .@"union" = .{
|
.@"union" => .{ .@"union" = .{
|
||||||
.union_type = T,
|
.union_type = T,
|
||||||
.show_type_spec = true,
|
.show_type_spec = true,
|
||||||
} },
|
} },
|
||||||
.Pointer => |ptr| .{ .pointer = .{ .ptr_type = T, .size = ptr.size } },
|
.pointer => |ptr| .{ .pointer = .{ .ptr_type = T, .size = ptr.size } },
|
||||||
.Fn => |fn_info| .{ .function = fn_info },
|
.@"fn" => |fn_info| .{ .function = fn_info },
|
||||||
else => @compileError("unsupported type: " ++ @typeName(T)),
|
else => @compileError("unsupported type: " ++ @typeName(T)),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -129,7 +129,7 @@ pub const Encoding = union(enum) {
|
||||||
},
|
},
|
||||||
.structure => |s| {
|
.structure => |s| {
|
||||||
const struct_info = @typeInfo(s.struct_type);
|
const struct_info = @typeInfo(s.struct_type);
|
||||||
assert(struct_info.Struct.layout == .@"extern");
|
assert(struct_info.@"struct".layout == .@"extern");
|
||||||
|
|
||||||
// Strips the fully qualified type name to leave just the
|
// Strips the fully qualified type name to leave just the
|
||||||
// type name. Used in naming the Struct in an encoding.
|
// type name. Used in naming the Struct in an encoding.
|
||||||
|
@ -141,7 +141,7 @@ pub const Encoding = union(enum) {
|
||||||
// of the struct (determined by levels of pointer indirection)
|
// of the struct (determined by levels of pointer indirection)
|
||||||
if (s.show_type_spec) {
|
if (s.show_type_spec) {
|
||||||
try writer.writeAll("=");
|
try writer.writeAll("=");
|
||||||
inline for (struct_info.Struct.fields) |field| {
|
inline for (struct_info.@"struct".fields) |field| {
|
||||||
const field_encode = init(field.type);
|
const field_encode = init(field.type);
|
||||||
try field_encode.format(fmt, options, writer);
|
try field_encode.format(fmt, options, writer);
|
||||||
}
|
}
|
||||||
|
@ -151,7 +151,7 @@ pub const Encoding = union(enum) {
|
||||||
},
|
},
|
||||||
.@"union" => |u| {
|
.@"union" => |u| {
|
||||||
const union_info = @typeInfo(u.union_type);
|
const union_info = @typeInfo(u.union_type);
|
||||||
assert(union_info.Union.layout == .@"extern");
|
assert(union_info.@"union".layout == .@"extern");
|
||||||
|
|
||||||
// Strips the fully qualified type name to leave just the
|
// Strips the fully qualified type name to leave just the
|
||||||
// type name. Used in naming the Union in an encoding
|
// type name. Used in naming the Union in an encoding
|
||||||
|
@ -163,7 +163,7 @@ pub const Encoding = union(enum) {
|
||||||
// of the Union (determined by levels of pointer indirection)
|
// of the Union (determined by levels of pointer indirection)
|
||||||
if (u.show_type_spec) {
|
if (u.show_type_spec) {
|
||||||
try writer.writeAll("=");
|
try writer.writeAll("=");
|
||||||
inline for (union_info.Union.fields) |field| {
|
inline for (union_info.@"union".fields) |field| {
|
||||||
const field_encode = init(field.type);
|
const field_encode = init(field.type);
|
||||||
try field_encode.format(fmt, options, writer);
|
try field_encode.format(fmt, options, writer);
|
||||||
}
|
}
|
||||||
|
@ -174,7 +174,7 @@ pub const Encoding = union(enum) {
|
||||||
.bitfield => |b| try writer.print("b{}", .{b}), // not sure if needed from Zig -> Obj-C
|
.bitfield => |b| try writer.print("b{}", .{b}), // not sure if needed from Zig -> Obj-C
|
||||||
.pointer => |p| {
|
.pointer => |p| {
|
||||||
switch (p.size) {
|
switch (p.size) {
|
||||||
.One => {
|
.one => {
|
||||||
// get the pointer info (count of levels of direction
|
// get the pointer info (count of levels of direction
|
||||||
// and the underlying type)
|
// and the underlying type)
|
||||||
const pointer_info = indirectionCountAndType(p.ptr_type);
|
const pointer_info = indirectionCountAndType(p.ptr_type);
|
||||||
|
@ -206,7 +206,7 @@ pub const Encoding = union(enum) {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.function => |fn_info| {
|
.function => |fn_info| {
|
||||||
assert(fn_info.calling_convention == .C);
|
assert(fn_info.calling_convention.eql(.c));
|
||||||
|
|
||||||
// Return type is first in a method encoding
|
// Return type is first in a method encoding
|
||||||
const ret_type_enc = init(fn_info.return_type.?);
|
const ret_type_enc = init(fn_info.return_type.?);
|
||||||
|
@ -230,8 +230,8 @@ fn indirectionCountAndType(comptime T: type) struct {
|
||||||
} {
|
} {
|
||||||
var WalkType = T;
|
var WalkType = T;
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (@typeInfo(WalkType) == .Pointer) : (count += 1) {
|
while (@typeInfo(WalkType) == .pointer) : (count += 1) {
|
||||||
WalkType = @typeInfo(WalkType).Pointer.child;
|
WalkType = @typeInfo(WalkType).pointer.child;
|
||||||
}
|
}
|
||||||
|
|
||||||
return .{ .child = WalkType, .indirection_levels = count };
|
return .{ .child = WalkType, .indirection_levels = count };
|
||||||
|
|
|
@ -174,7 +174,7 @@ fn MsgSendFn(
|
||||||
comptime Target: type,
|
comptime Target: type,
|
||||||
comptime Args: type,
|
comptime Args: type,
|
||||||
) type {
|
) type {
|
||||||
const argsInfo = @typeInfo(Args).Struct;
|
const argsInfo = @typeInfo(Args).@"struct";
|
||||||
assert(argsInfo.is_tuple);
|
assert(argsInfo.is_tuple);
|
||||||
|
|
||||||
// Target must always be an "id". Lots of types (Class, Object, etc.)
|
// Target must always be an "id". Lots of types (Class, Object, etc.)
|
||||||
|
@ -203,7 +203,7 @@ fn MsgSendFn(
|
||||||
};
|
};
|
||||||
|
|
||||||
return @Type(.{
|
return @Type(.{
|
||||||
.Fn = .{
|
.@"fn" = .{
|
||||||
.calling_convention = .C,
|
.calling_convention = .C,
|
||||||
.is_generic = false,
|
.is_generic = false,
|
||||||
.is_var_args = false,
|
.is_var_args = false,
|
||||||
|
|
Loading…
Reference in a new issue