diff --git a/pkg/macos/foundation.zig b/pkg/macos/foundation.zig index ca0536b8c..8b29ccfb3 100644 --- a/pkg/macos/foundation.zig +++ b/pkg/macos/foundation.zig @@ -2,6 +2,7 @@ pub const c = @import("foundation/c.zig"); pub usingnamespace @import("foundation/array.zig"); pub usingnamespace @import("foundation/base.zig"); pub usingnamespace @import("foundation/dictionary.zig"); +pub usingnamespace @import("foundation/number.zig"); pub usingnamespace @import("foundation/string.zig"); pub usingnamespace @import("foundation/type.zig"); pub usingnamespace @import("foundation/url.zig"); diff --git a/pkg/macos/foundation/c.zig b/pkg/macos/foundation/c.zig new file mode 100644 index 000000000..9bd571adb --- /dev/null +++ b/pkg/macos/foundation/c.zig @@ -0,0 +1,3 @@ +pub usingnamespace @cImport({ + @cInclude("CoreFoundation/CoreFoundation.h"); +}); diff --git a/pkg/macos/foundation/dictionary.zig b/pkg/macos/foundation/dictionary.zig index 6d9c6bd9e..8d74a90f1 100644 --- a/pkg/macos/foundation/dictionary.zig +++ b/pkg/macos/foundation/dictionary.zig @@ -2,11 +2,12 @@ const std = @import("std"); const assert = std.debug.assert; const Allocator = std.mem.Allocator; const foundation = @import("../foundation.zig"); +const c = @import("c.zig"); pub const Dictionary = opaque { pub fn create( - keys: ?[]*const anyopaque, - values: ?[]*const anyopaque, + keys: ?[]?*const anyopaque, + values: ?[]?*const anyopaque, ) Allocator.Error!*Dictionary { if (keys != null or values != null) { assert(keys != null); @@ -14,14 +15,14 @@ pub const Dictionary = opaque { assert(keys.?.len == values.?.len); } - return CFDictionaryCreate( + return @intToPtr(?*Dictionary, @ptrToInt(c.CFDictionaryCreate( null, - if (keys) |slice| slice.ptr else null, - if (values) |slice| slice.ptr else null, - if (keys) |slice| slice.len else 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks, - ) orelse Allocator.Error.OutOfMemory; + @ptrCast([*c]?*const anyopaque, if (keys) |slice| slice.ptr else null), + @ptrCast([*c]?*const anyopaque, if (values) |slice| slice.ptr else null), + @intCast(c.CFIndex, if (keys) |slice| slice.len else 0), + &c.kCFTypeDictionaryKeyCallBacks, + &c.kCFTypeDictionaryValueCallBacks, + ))) orelse Allocator.Error.OutOfMemory; } pub fn release(self: *Dictionary) void { @@ -29,36 +30,29 @@ pub const Dictionary = opaque { } pub fn getCount(self: *Dictionary) usize { - return CFDictionaryGetCount(self); + return @intCast(usize, c.CFDictionaryGetCount(@ptrCast(c.CFDictionaryRef, self))); } - pub extern "c" fn CFDictionaryCreate( - allocator: ?*anyopaque, - keys: ?[*]*const anyopaque, - values: ?[*]*const anyopaque, - num_values: usize, - key_callbacks: *const anyopaque, - value_callbacks: *const anyopaque, - ) ?*Dictionary; - pub extern "c" fn CFDictionaryGetCount(*Dictionary) usize; - - extern "c" var kCFTypeDictionaryKeyCallBacks: anyopaque; - extern "c" var kCFTypeDictionaryValueCallBacks: anyopaque; + pub fn getValue(self: *Dictionary, comptime V: type, key: ?*const anyopaque) ?*V { + return @intToPtr(?*V, @ptrToInt(c.CFDictionaryGetValue( + @ptrCast(c.CFDictionaryRef, self), + key, + ))); + } }; -// Just used for a test -extern "c" var kCFURLIsPurgeableKey: *const anyopaque; - test "dictionary" { const testing = std.testing; const str = try foundation.String.createWithBytes("hello", .unicode, false); defer str.release(); - var keys = [_]*const anyopaque{kCFURLIsPurgeableKey}; - var values = [_]*const anyopaque{str}; + var keys = [_]?*const anyopaque{c.kCFURLIsPurgeableKey}; + var values = [_]?*const anyopaque{str}; const dict = try Dictionary.create(&keys, &values); defer dict.release(); try testing.expectEqual(@as(usize, 1), dict.getCount()); + try testing.expect(dict.getValue(foundation.String, c.kCFURLIsPurgeableKey) != null); + try testing.expect(dict.getValue(foundation.String, c.kCFURLIsVolumeKey) == null); } diff --git a/pkg/macos/foundation/number.zig b/pkg/macos/foundation/number.zig new file mode 100644 index 000000000..289c9e8f1 --- /dev/null +++ b/pkg/macos/foundation/number.zig @@ -0,0 +1,79 @@ +const std = @import("std"); +const Allocator = std.mem.Allocator; +const foundation = @import("../foundation.zig"); +const c = @import("c.zig"); + +pub const Number = opaque { + pub fn create( + comptime type_: NumberType, + value: *const type_.ValueType(), + ) Allocator.Error!*Number { + return @intToPtr(?*Number, @ptrToInt(c.CFNumberCreate( + null, + @enumToInt(type_), + value, + ))) orelse Allocator.Error.OutOfMemory; + } + + pub fn getValue(self: *Number, comptime t: NumberType, ptr: *t.ValueType()) bool { + return c.CFNumberGetValue( + @ptrCast(c.CFNumberRef, self), + @enumToInt(t), + ptr, + ) == 1; + } + + pub fn release(self: *Number) void { + c.CFRelease(self); + } +}; + +pub const NumberType = enum(c.CFNumberType) { + sint8 = c.kCFNumberSInt8Type, + sint16 = c.kCFNumberSInt16Type, + sint32 = c.kCFNumberSInt32Type, + sint64 = c.kCFNumberSInt64Type, + float32 = c.kCFNumberFloat32Type, + float64 = c.kCFNumberFloat64Type, + char = c.kCFNumberCharType, + short = c.kCFNumberShortType, + int = c.kCFNumberIntType, + long = c.kCFNumberLongType, + long_long = c.kCFNumberLongLongType, + float = c.kCFNumberFloatType, + double = c.kCFNumberDoubleType, + cf_index = c.kCFNumberCFIndexType, + ns_integer = c.kCFNumberNSIntegerType, + cg_float = c.kCFNumberCGFloatType, + + pub fn ValueType(self: NumberType) type { + return switch (self) { + .sint8 => i8, + .sint16 => i16, + .sint32 => i32, + .sint64 => i64, + .float32 => f32, + .float64 => f64, + .char => u8, + .short => c_short, + .int => c_int, + .long => c_long, + .long_long => c_longlong, + .float => f32, + .double => f64, + else => unreachable, // TODO + }; + } +}; + +test { + const testing = std.testing; + + const inner: i8 = 42; + const v = try Number.create(.sint8, &inner); + defer v.release(); + + var result: i8 = undefined; + try testing.expect(v.getValue(.sint8, &result)); + try testing.expectEqual(result, inner); +}