From e0453eefd0f128fd4d930d21011d373589b65548 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20=28xq=29=20Quei=C3=9Fner?= Date: Wed, 28 Jul 2021 10:01:27 +0200 Subject: [PATCH 1/7] Update to latest master. --- examples.zig | 23 ++++++++++++----------- interface.zig | 14 ++++++++++---- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/examples.zig b/examples.zig index 94340c9..a6c8f47 100644 --- a/examples.zig +++ b/examples.zig @@ -30,8 +30,8 @@ test "Simple NonOwning interface" { var fooer = try Fooer.init(&f); defer fooer.deinit(); - expectEqual(@as(usize, 42), fooer.call("foo", .{})); - expectEqual(@as(usize, 43), fooer.call("foo", .{})); + try expectEqual(@as(usize, 42), fooer.call("foo", .{})); + try expectEqual(@as(usize, 43), fooer.call("foo", .{})); } }; @@ -56,7 +56,7 @@ test "Comptime only interface" { }; comptime var iface = try TestIFace.init(TestType{ .state = 0 }); - expectEqual(@as(u8, 42), iface.call("foo", .{42})); + try expectEqual(@as(u8, 42), iface.call("foo", .{42})); } test "Owning interface with optional function and a non-method function" { @@ -65,7 +65,7 @@ test "Owning interface with optional function and a non-method function" { const TestOwningIface = Interface(struct { someFn: ?fn (*const SelfType, usize, usize) usize, otherFn: fn (*SelfType, usize) anyerror!void, - thirdFn: fn(usize) usize, + thirdFn: fn (usize) usize, }, interface.Storage.Owning); const TestStruct = struct { @@ -92,8 +92,8 @@ test "Owning interface with optional function and a non-method function" { defer iface_instance.deinit(); try iface_instance.call("otherFn", .{100}); - expectEqual(@as(usize, 42), iface_instance.call("someFn", .{ 0, 42 }).?); - expectEqual(@as(usize, 101), iface_instance.call("thirdFn", .{ 100 })); + try expectEqual(@as(usize, 42), iface_instance.call("someFn", .{ 0, 42 }).?); + try expectEqual(@as(usize, 101), iface_instance.call("thirdFn", .{100})); } }; @@ -118,7 +118,7 @@ test "Interface with virtual async function implemented by an async function" { self.frame = @frame(); } self.state += 1; - suspend; + suspend {} self.state += 1; } }; @@ -127,11 +127,11 @@ test "Interface with virtual async function implemented by an async function" { var instance = try AsyncIFace.init(&i); _ = async instance.call("foo", .{}); - expectEqual(@as(usize, 0), i.state); + try expectEqual(@as(usize, 0), i.state); resume i.frame; - expectEqual(@as(usize, 1), i.state); + try expectEqual(@as(usize, 1), i.state); resume i.frame; - expectEqual(@as(usize, 2), i.state); + try expectEqual(@as(usize, 2), i.state); } test "Interface with virtual async function implemented by a blocking function" { @@ -143,6 +143,7 @@ test "Interface with virtual async function implemented by a blocking function" const Self = @This(); pub fn readBytes(self: Self, outBuf: []u8) void { + _ = self; for (outBuf) |*c| { c.* = 3; } @@ -154,5 +155,5 @@ test "Interface with virtual async function implemented by a blocking function" var buf: [256]u8 = undefined; try await async instance.call("readBytes", .{buf[0..]}); - expectEqual([_]u8{3} ** 256, buf); + try expectEqual([_]u8{3} ** 256, buf); } diff --git a/interface.zig b/interface.zig index cf6616e..52b0cf7 100644 --- a/interface.zig +++ b/interface.zig @@ -6,7 +6,7 @@ const assert = std.debug.assert; const expect = std.testing.expect; const expectEqual = std.testing.expectEqual; -pub const SelfType = opaque{}; +pub const SelfType = opaque {}; fn makeSelfPtr(ptr: anytype) *SelfType { if (comptime !trait.isSingleItemPtr(@TypeOf(ptr))) { @@ -65,7 +65,9 @@ pub const Storage = struct { return self.erased_ptr; } - pub fn deinit(comptime self: Comptime) void {} + pub fn deinit(comptime self: Comptime) void { + _ = self; + } }; pub const NonOwning = struct { @@ -88,7 +90,9 @@ pub const Storage = struct { return self.erased_ptr; } - pub fn deinit(self: NonOwning) void {} + pub fn deinit(self: NonOwning) void { + _ = self; + } }; pub const Owning = struct { @@ -158,7 +162,9 @@ pub const Storage = struct { return makeSelfPtr(&self.mem[0]); } - pub fn deinit(self: Self) void {} + pub fn deinit(self: Self) void { + _ = self; + } }; } From 09312252ff5e0d16d13ccb832518581688aa348f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20=22xq=22=20Quei=C3=9Fner?= Date: Thu, 21 Oct 2021 08:50:36 +0200 Subject: [PATCH 2/7] Fixes type. --- interface.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface.zig b/interface.zig index 52b0cf7..1d1dd12 100644 --- a/interface.zig +++ b/interface.zig @@ -147,7 +147,7 @@ pub const Storage = struct { .mem = undefined, }; if (ImplSize > 0) { - std.mem.copy(u8, self.mem[0..], @ptrCast([*]const u8, &args[0])[0..ImplSize]); + std.mem.copy(u8, self.mem[0..], @ptrCast([*]const u8, &value)[0..ImplSize]); } return TInterface{ From ab41779b74dd135e1bc20c1b63b4a2e1bc3ca253 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20=22xq=22=20Quei=C3=9Fner?= Date: Wed, 9 Mar 2022 17:26:23 +0100 Subject: [PATCH 3/7] Update to latest master. --- interface.zig | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/interface.zig b/interface.zig index 1d1dd12..f41d815 100644 --- a/interface.zig +++ b/interface.zig @@ -259,9 +259,10 @@ fn getFunctionFromImpl(comptime name: []const u8, comptime FnT: type, comptime I // Find the candidate in the implementation type. for (std.meta.declarations(ImplT)) |decl| { if (std.mem.eql(u8, name, decl.name)) { - switch (decl.data) { - .Fn => |fn_decl| { - const args = @typeInfo(fn_decl.fn_type).Fn.args; + const data = @field(ImplT, decl.name); + switch (@typeInfo(@TypeOf(data))) { + .Fn => |fn_type| { + const args = fn_type.args; if (args.len == 0) { return @field(ImplT, name); @@ -271,7 +272,7 @@ fn getFunctionFromImpl(comptime name: []const u8, comptime FnT: type, comptime I const arg0_type = args[0].arg_type.?; const is_method = arg0_type == ImplT or arg0_type == *ImplT or arg0_type == *const ImplT; - const candidate_cc = @typeInfo(fn_decl.fn_type).Fn.calling_convention; + const candidate_cc = fn_type.calling_convention; switch (candidate_cc) { .Async, .Unspecified => {}, else => return null, From 85264c69da99783c581c057e98d1caa901cf445b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20=22xq=22=20Quei=C3=9Fner?= Date: Thu, 12 Jan 2023 08:21:47 +0100 Subject: [PATCH 4/7] Update to 0.11.0-dev.1253+fcee1bf99 --- examples.zig | 126 +++++++++++++++++++++++++------------------------- interface.zig | 85 +++++++++++++++++++--------------- 2 files changed, 113 insertions(+), 98 deletions(-) diff --git a/examples.zig b/examples.zig index a6c8f47..411860e 100644 --- a/examples.zig +++ b/examples.zig @@ -11,7 +11,7 @@ test "Simple NonOwning interface" { const NonOwningTest = struct { fn run() !void { const Fooer = Interface(struct { - foo: fn (*SelfType) usize, + foo: *const fn (*SelfType) usize, }, interface.Storage.NonOwning); const TestFooer = struct { @@ -42,7 +42,7 @@ test "Simple NonOwning interface" { test "Comptime only interface" { // return error.SkipZigTest; const TestIFace = Interface(struct { - foo: fn (*SelfType, u8) u8, + foo: *const fn (*SelfType, u8) u8, }, interface.Storage.Comptime); const TestType = struct { @@ -63,9 +63,9 @@ test "Owning interface with optional function and a non-method function" { const OwningOptionalFuncTest = struct { fn run() !void { const TestOwningIface = Interface(struct { - someFn: ?fn (*const SelfType, usize, usize) usize, - otherFn: fn (*SelfType, usize) anyerror!void, - thirdFn: fn (usize) usize, + someFn: ?*const fn (*const SelfType, usize, usize) usize, + otherFn: *const fn (*SelfType, usize) anyerror!void, + thirdFn: *const fn (usize) usize, }, interface.Storage.Owning); const TestStruct = struct { @@ -100,60 +100,62 @@ test "Owning interface with optional function and a non-method function" { try OwningOptionalFuncTest.run(); } -test "Interface with virtual async function implemented by an async function" { - const AsyncIFace = Interface(struct { - const async_call_stack_size = 1024; - - foo: fn (*SelfType) callconv(.Async) void, - }, interface.Storage.NonOwning); - - const Impl = struct { - const Self = @This(); - - state: usize, - frame: anyframe = undefined, - - pub fn foo(self: *Self) void { - suspend { - self.frame = @frame(); - } - self.state += 1; - suspend {} - self.state += 1; - } - }; - - var i = Impl{ .state = 0 }; - var instance = try AsyncIFace.init(&i); - _ = async instance.call("foo", .{}); - - try expectEqual(@as(usize, 0), i.state); - resume i.frame; - try expectEqual(@as(usize, 1), i.state); - resume i.frame; - try expectEqual(@as(usize, 2), i.state); -} - -test "Interface with virtual async function implemented by a blocking function" { - const AsyncIFace = Interface(struct { - readBytes: fn (*SelfType, []u8) callconv(.Async) anyerror!void, - }, interface.Storage.Inline(8)); - - const Impl = struct { - const Self = @This(); - - pub fn readBytes(self: Self, outBuf: []u8) void { - _ = self; - for (outBuf) |*c| { - c.* = 3; - } - } - }; - - var instance = try AsyncIFace.init(Impl{}); - - var buf: [256]u8 = undefined; - try await async instance.call("readBytes", .{buf[0..]}); - - try expectEqual([_]u8{3} ** 256, buf); -} +// TODO: Include async tests when async is implemented in stage2! + +// test "Interface with virtual async function implemented by an async function" { +// const AsyncIFace = Interface(struct { +// const async_call_stack_size = 1024; + +// foo: *const fn (*SelfType) callconv(.Async) void, +// }, interface.Storage.NonOwning); + +// const Impl = struct { +// const Self = @This(); + +// state: usize, +// frame: anyframe = undefined, + +// pub fn foo(self: *Self) void { +// suspend { +// self.frame = @frame(); +// } +// self.state += 1; +// suspend {} +// self.state += 1; +// } +// }; + +// var i = Impl{ .state = 0 }; +// var instance = try AsyncIFace.init(&i); +// _ = async instance.call("foo", .{}); + +// try expectEqual(@as(usize, 0), i.state); +// resume i.frame; +// try expectEqual(@as(usize, 1), i.state); +// resume i.frame; +// try expectEqual(@as(usize, 2), i.state); +// } + +// test "Interface with virtual async function implemented by a blocking function" { +// const AsyncIFace = Interface(struct { +// readBytes: *const fn (*SelfType, []u8) callconv(.Async) anyerror!void, +// }, interface.Storage.Inline(8)); + +// const Impl = struct { +// const Self = @This(); + +// pub fn readBytes(self: Self, outBuf: []u8) void { +// _ = self; +// for (outBuf) |*c| { +// c.* = 3; +// } +// } +// }; + +// var instance = try AsyncIFace.init(Impl{}); + +// var buf: [256]u8 = undefined; +// try await async instance.call("readBytes", .{buf[0..]}); + +// try expectEqual([_]u8{3} ** 256, buf); +// } diff --git a/interface.zig b/interface.zig index f41d815..6b8d981 100644 --- a/interface.zig +++ b/interface.zig @@ -45,7 +45,7 @@ pub const Storage = struct { fn makeInit(comptime TInterface: type) type { return struct { - fn init(obj: anytype) !TInterface { + fn init(comptime obj: anytype) !TInterface { const ImplType = PtrChildOrSelf(@TypeOf(obj)); comptime var obj_holder = obj; @@ -96,22 +96,25 @@ pub const Storage = struct { }; pub const Owning = struct { - allocator: *mem.Allocator, + allocator: mem.Allocator, mem: []u8, fn makeInit(comptime TInterface: type) type { return struct { - fn init(obj: anytype, allocator: *std.mem.Allocator) !TInterface { + fn init(obj: anytype, allocator: std.mem.Allocator) !TInterface { const AllocT = @TypeOf(obj); - var ptr = try allocator.create(AllocT); + const base = try allocator.alignedAlloc(u8, @alignOf(AllocT), @sizeOf(AllocT)); + errdefer allocator.free(base); + + var ptr = @ptrCast(*AllocT, base.ptr); ptr.* = obj; return TInterface{ .vtable_ptr = &comptime makeVTable(TInterface.VTable, PtrChildOrSelf(AllocT)), .storage = Owning{ .allocator = allocator, - .mem = std.mem.asBytes(ptr)[0..], + .mem = base, }, }; } @@ -123,8 +126,7 @@ pub const Storage = struct { } pub fn deinit(self: Owning) void { - const result = self.allocator.shrinkBytes(self.mem, 0, 0, 0, 0); - assert(result == 0); + self.allocator.free(self.mem); } }; @@ -243,12 +245,12 @@ fn makeCall( const is_const = CurrSelfType == *const SelfType; const self = if (is_const) constSelfPtrAs(self_ptr, ImplT) else selfPtrAs(self_ptr, ImplT); const fptr = @field(ImplT, name); - const first_arg_ptr = comptime std.meta.trait.is(.Pointer)(@typeInfo(@TypeOf(fptr)).Fn.args[0].arg_type.?); + const first_arg_ptr = comptime std.meta.trait.is(.Pointer)(@typeInfo(@TypeOf(fptr)).Fn.params[0].type.?); const self_arg = if (first_arg_ptr) .{self} else .{self.*}; return switch (call_type) { - .BothBlocking => @call(.{ .modifier = .always_inline }, fptr, self_arg ++ args), - .AsyncCallsBlocking, .BothAsync => await @call(.{ .modifier = .async_kw }, fptr, self_arg ++ args), + .BothBlocking => @call(.always_inline, fptr, self_arg ++ args), + .AsyncCallsBlocking, .BothAsync => await @call(.async_kw, fptr, self_arg ++ args), .BlockingCallsAsync => @compileError("Trying to implement blocking virtual function " ++ name ++ " with async implementation."), }; } @@ -262,14 +264,14 @@ fn getFunctionFromImpl(comptime name: []const u8, comptime FnT: type, comptime I const data = @field(ImplT, decl.name); switch (@typeInfo(@TypeOf(data))) { .Fn => |fn_type| { - const args = fn_type.args; + const args = fn_type.params; if (args.len == 0) { return @field(ImplT, name); } if (args.len > 0) { - const arg0_type = args[0].arg_type.?; + const arg0_type = args[0].type.?; const is_method = arg0_type == ImplT or arg0_type == *ImplT or arg0_type == *const ImplT; const candidate_cc = fn_type.calling_convention; @@ -279,7 +281,7 @@ fn getFunctionFromImpl(comptime name: []const u8, comptime FnT: type, comptime I } const Return = @typeInfo(FnT).Fn.return_type orelse noreturn; - const CurrSelfType = @typeInfo(FnT).Fn.args[0].arg_type.?; + const CurrSelfType = @typeInfo(FnT).Fn.params[0].type.?; const call_type: GenCallType = switch (our_cc) { .Async => if (candidate_cc == .Async) .BothAsync else .AsyncCallsBlocking, @@ -296,32 +298,32 @@ fn getFunctionFromImpl(comptime name: []const u8, comptime FnT: type, comptime I return switch (args.len) { 1 => struct { fn impl(self_ptr: CurrSelfType) callconv(our_cc) Return { - return @call(.{ .modifier = .always_inline }, makeCall, .{ name, CurrSelfType, Return, ImplT, call_type, self_ptr, .{} }); + return @call(.always_inline, makeCall, .{ name, CurrSelfType, Return, ImplT, call_type, self_ptr, .{} }); } }.impl, 2 => struct { - fn impl(self_ptr: CurrSelfType, arg: args[1].arg_type.?) callconv(our_cc) Return { - return @call(.{ .modifier = .always_inline }, makeCall, .{ name, CurrSelfType, Return, ImplT, call_type, self_ptr, .{arg} }); + fn impl(self_ptr: CurrSelfType, arg: args[1].type.?) callconv(our_cc) Return { + return @call(.always_inline, makeCall, .{ name, CurrSelfType, Return, ImplT, call_type, self_ptr, .{arg} }); } }.impl, 3 => struct { - fn impl(self_ptr: CurrSelfType, arg1: args[1].arg_type.?, arg2: args[2].arg_type.?) callconv(our_cc) Return { - return @call(.{ .modifier = .always_inline }, makeCall, .{ name, CurrSelfType, Return, ImplT, call_type, self_ptr, .{ arg1, arg2 } }); + fn impl(self_ptr: CurrSelfType, arg1: args[1].type.?, arg2: args[2].type.?) callconv(our_cc) Return { + return @call(.always_inline, makeCall, .{ name, CurrSelfType, Return, ImplT, call_type, self_ptr, .{ arg1, arg2 } }); } }.impl, 4 => struct { - fn impl(self_ptr: CurrSelfType, arg1: args[1].arg_type.?, arg2: args[2].arg_type.?, arg3: args[3].arg_type.?) callconv(our_cc) Return { - return @call(.{ .modifier = .always_inline }, makeCall, .{ name, CurrSelfType, Return, ImplT, call_type, self_ptr, .{ arg1, arg2, arg3 } }); + fn impl(self_ptr: CurrSelfType, arg1: args[1].type.?, arg2: args[2].type.?, arg3: args[3].type.?) callconv(our_cc) Return { + return @call(.always_inline, makeCall, .{ name, CurrSelfType, Return, ImplT, call_type, self_ptr, .{ arg1, arg2, arg3 } }); } }.impl, 5 => struct { - fn impl(self_ptr: CurrSelfType, arg1: args[1].arg_type.?, arg2: args[2].arg_type.?, arg3: args[3].arg_type.?, arg4: args[4].arg_type.?) callconv(our_cc) Return { - return @call(.{ .modifier = .always_inline }, makeCall, .{ name, CurrSelfType, Return, ImplT, call_type, self_ptr, .{ arg1, arg2, arg3, arg4 } }); + fn impl(self_ptr: CurrSelfType, arg1: args[1].type.?, arg2: args[2].type.?, arg3: args[3].type.?, arg4: args[4].type.?) callconv(our_cc) Return { + return @call(.always_inline, makeCall, .{ name, CurrSelfType, Return, ImplT, call_type, self_ptr, .{ arg1, arg2, arg3, arg4 } }); } }.impl, 6 => struct { - fn impl(self_ptr: CurrSelfType, arg1: args[1].arg_type.?, arg2: args[2].arg_type.?, arg3: args[3].arg_type.?, arg4: args[4].arg_type.?, arg5: args[5].arg_type.?) callconv(our_cc) Return { - return @call(.{ .modifier = .always_inline }, makeCall, .{ name, CurrSelfType, Return, ImplT, call_type, self_ptr, .{ arg1, arg2, arg3, arg4, arg5 } }); + fn impl(self_ptr: CurrSelfType, arg1: args[1].type.?, arg2: args[2].type.?, arg3: args[3].type.?, arg4: args[4].type.?, arg5: args[5].type.?) callconv(our_cc) Return { + return @call(.always_inline, makeCall, .{ name, CurrSelfType, Return, ImplT, call_type, self_ptr, .{ arg1, arg2, arg3, arg4, arg5 } }); } }.impl, else => @compileError("Unsupported number of arguments, please provide a manually written vtable."), @@ -343,19 +345,26 @@ fn makeVTable(comptime VTableT: type, comptime ImplT: type) VTableT { var vtable: VTableT = undefined; for (std.meta.fields(VTableT)) |field| { - var fn_type = field.field_type; + var fn_type = field.type; const is_optional = trait.is(.Optional)(fn_type); if (is_optional) { fn_type = std.meta.Child(fn_type); } + // Erase the function pointer type + fn_type = std.meta.Child(fn_type); + const candidate = comptime getFunctionFromImpl(field.name, fn_type, ImplT); if (candidate == null and !is_optional) { @compileError("Type '" ++ @typeName(ImplT) ++ "' does not implement non optional function '" ++ field.name ++ "'."); } else if (!is_optional) { @field(vtable, field.name) = candidate.?; } else { - @field(vtable, field.name) = candidate; + if (candidate) |c| { + @field(vtable, field.name) = c; + } else { + @field(vtable, field.name) = null; + } } } @@ -375,12 +384,16 @@ fn checkVtableType(comptime VTableT: type) void { } for (std.meta.fields(VTableT)) |field| { - var field_type = field.field_type; + var field_type = field.type; if (trait.is(.Optional)(field_type)) { field_type = std.meta.Child(field_type); } + if (trait.is(.Pointer)(field_type)) { + field_type = std.meta.Child(field_type); + } + if (!trait.is(.Fn)(field_type)) { @compileError("VTable type defines non function field '" ++ field.name ++ "'."); } @@ -401,11 +414,11 @@ fn checkVtableType(comptime VTableT: type) void { fn vtableHasMethod(comptime VTableT: type, comptime name: []const u8, is_optional: *bool, is_async: *bool, is_method: *bool) bool { for (std.meta.fields(VTableT)) |field| { if (std.mem.eql(u8, name, field.name)) { - is_optional.* = trait.is(.Optional)(field.field_type); - const fn_typeinfo = @typeInfo(if (is_optional.*) std.meta.Child(field.field_type) else field.field_type).Fn; + is_optional.* = trait.is(.Optional)(field.type); + const fn_typeinfo = @typeInfo(std.meta.Child(if (is_optional.*) std.meta.Child(field.type) else field.type)).Fn; is_async.* = fn_typeinfo.calling_convention == .Async; - is_method.* = fn_typeinfo.args.len > 0 and blk: { - const first_arg_type = fn_typeinfo.args[0].arg_type.?; + is_method.* = fn_typeinfo.params.len > 0 and blk: { + const first_arg_type = fn_typeinfo.params[0].type.?; break :blk first_arg_type == *SelfType or first_arg_type == *const SelfType; }; return true; @@ -418,12 +431,12 @@ fn vtableHasMethod(comptime VTableT: type, comptime name: []const u8, is_optiona fn VTableReturnType(comptime VTableT: type, comptime name: []const u8) type { for (std.meta.fields(VTableT)) |field| { if (std.mem.eql(u8, name, field.name)) { - const is_optional = trait.is(.Optional)(field.field_type); + const is_optional = trait.is(.Optional)(field.type); var fn_ret_type = (if (is_optional) - @typeInfo(std.meta.Child(field.field_type)).Fn.return_type + @typeInfo(std.meta.Child(std.meta.Child(field.type))).Fn.return_type else - @typeInfo(field.field_type).Fn.return_type) orelse noreturn; + @typeInfo(std.meta.Child(field.type)).Fn.return_type) orelse noreturn; if (is_optional) { return ?fn_ret_type; @@ -478,14 +491,14 @@ pub fn Interface(comptime VTableT: type, comptime StorageT: type) type { const new_args = .{self_ptr}; if (!is_async) { - return @call(.{}, fn_ptr, new_args ++ args); + return @call(.auto, fn_ptr, new_args ++ args); } else { var stack_frame: [stack_size]u8 align(std.Target.stack_align) = undefined; return await @asyncCall(&stack_frame, {}, fn_ptr, new_args ++ args); } } else { if (!is_async) { - return @call(.{}, fn_ptr, args); + return @call(.auto, fn_ptr, args); } else { var stack_frame: [stack_size]u8 align(std.Target.stack_align) = undefined; return await @asyncCall(&stack_frame, {}, fn_ptr, args); From 08db064d77dcd0aef2456f17fadd7906db79a92b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20=22xq=22=20Quei=C3=9Fner?= Date: Fri, 24 Mar 2023 08:00:43 +0100 Subject: [PATCH 5/7] Adds build.zig for packaging --- build.zig | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 build.zig diff --git a/build.zig b/build.zig new file mode 100644 index 0000000..6f7d459 --- /dev/null +++ b/build.zig @@ -0,0 +1,7 @@ +const std = @import("std"); + +pub fn build(b: *std.Build) void { + _ = b.addModule("interface.zig", .{ + .source_file = .{ .path = "interface.zig" }, + }); +} From 6b58b8a45ee4a7409f169806bb50a71dcee57110 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20=22xq=22=20Quei=C3=9Fner?= Date: Sun, 9 Jul 2023 18:56:28 +0200 Subject: [PATCH 6/7] Update to 0.11.0-dev.3777+64f0059cd --- .gitignore | 3 ++- build.zig | 17 +++++++++++++++-- examples.zig => src/examples.zig | 2 +- interface.zig => src/interface.zig | 19 +++++++++++++------ 4 files changed, 31 insertions(+), 10 deletions(-) rename examples.zig => src/examples.zig (99%) rename interface.zig => src/interface.zig (96%) diff --git a/.gitignore b/.gitignore index 2040c29..e73c965 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -zig-cache +zig-cache/ +zig-out/ diff --git a/build.zig b/build.zig index 6f7d459..b50dee7 100644 --- a/build.zig +++ b/build.zig @@ -1,7 +1,20 @@ const std = @import("std"); pub fn build(b: *std.Build) void { - _ = b.addModule("interface.zig", .{ - .source_file = .{ .path = "interface.zig" }, + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + + const interface_mod = b.addModule("interface.zig", .{ + .source_file = .{ .path = "src/interface.zig" }, + }); + + const exe = b.addTest(.{ + .root_source_file = .{ .path = "src/examples.zig" }, + .target = target, + .optimize = optimize, }); + + exe.addModule("interface", interface_mod); + + b.getInstallStep().dependOn(&b.addRunArtifact(exe).step); } diff --git a/examples.zig b/src/examples.zig similarity index 99% rename from examples.zig rename to src/examples.zig index 411860e..966a9d5 100644 --- a/examples.zig +++ b/src/examples.zig @@ -1,4 +1,4 @@ -const interface = @import("interface.zig"); +const interface = @import("interface"); const Interface = interface.Interface; const SelfType = interface.SelfType; diff --git a/interface.zig b/src/interface.zig similarity index 96% rename from interface.zig rename to src/interface.zig index 6b8d981..ced10b4 100644 --- a/interface.zig +++ b/src/interface.zig @@ -98,23 +98,30 @@ pub const Storage = struct { pub const Owning = struct { allocator: mem.Allocator, mem: []u8, + alignment_log2: u8, fn makeInit(comptime TInterface: type) type { return struct { - fn init(obj: anytype, allocator: std.mem.Allocator) !TInterface { + fn init(obj: anytype, allocator: std.mem.Allocator) error{OutOfMemory}!TInterface { const AllocT = @TypeOf(obj); - const base = try allocator.alignedAlloc(u8, @alignOf(AllocT), @sizeOf(AllocT)); - errdefer allocator.free(base); + const t_align = @alignOf(AllocT); + const t_align_log2 = std.math.log2(t_align); - var ptr = @ptrCast(*AllocT, base.ptr); + const base = allocator.rawAlloc(@sizeOf(AllocT), t_align_log2, @returnAddress()) orelse return error.OutOfMemory; + + const slice = base[0..@sizeOf(AllocT)]; + errdefer allocator.rawFree(slice, t_align_log2, @returnAddress()); + + var ptr = @ptrCast(*AllocT, @alignCast(t_align, base)); ptr.* = obj; return TInterface{ .vtable_ptr = &comptime makeVTable(TInterface.VTable, PtrChildOrSelf(AllocT)), .storage = Owning{ .allocator = allocator, - .mem = base, + .mem = slice, + .alignment_log2 = t_align_log2, }, }; } @@ -126,7 +133,7 @@ pub const Storage = struct { } pub fn deinit(self: Owning) void { - self.allocator.free(self.mem); + self.allocator.rawFree(self.mem, self.alignment_log2, @returnAddress()); } }; From a9fcc958e5e0387d3cc6212858cda3d34b933e56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20=22xq=22=20Quei=C3=9Fner?= Date: Sun, 9 Jul 2023 18:59:11 +0200 Subject: [PATCH 7/7] Update to 0.11.0-dev.3947+89396ff02 --- src/interface.zig | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/interface.zig b/src/interface.zig index ced10b4..54cb884 100644 --- a/src/interface.zig +++ b/src/interface.zig @@ -16,7 +16,7 @@ fn makeSelfPtr(ptr: anytype) *SelfType { const T = std.meta.Child(@TypeOf(ptr)); if (@sizeOf(T) > 0) { - return @ptrCast(*SelfType, ptr); + return @ptrCast(ptr); } else { return undefined; } @@ -24,7 +24,7 @@ fn makeSelfPtr(ptr: anytype) *SelfType { fn selfPtrAs(self: *SelfType, comptime T: type) *T { if (@sizeOf(T) > 0) { - return @alignCast(@alignOf(T), @ptrCast(*align(1) T, self)); + return @alignCast(@ptrCast(self)); } else { return undefined; } @@ -32,7 +32,7 @@ fn selfPtrAs(self: *SelfType, comptime T: type) *T { fn constSelfPtrAs(self: *const SelfType, comptime T: type) *const T { if (@sizeOf(T) > 0) { - return @alignCast(@alignOf(T), @ptrCast(*align(1) const T, self)); + return @alignCast(@ptrCast(self)); } else { return undefined; } @@ -113,7 +113,7 @@ pub const Storage = struct { const slice = base[0..@sizeOf(AllocT)]; errdefer allocator.rawFree(slice, t_align_log2, @returnAddress()); - var ptr = @ptrCast(*AllocT, @alignCast(t_align, base)); + var ptr: *AllocT = @ptrCast(@alignCast(base)); ptr.* = obj; return TInterface{ @@ -156,7 +156,7 @@ pub const Storage = struct { .mem = undefined, }; if (ImplSize > 0) { - std.mem.copy(u8, self.mem[0..], @ptrCast([*]const u8, &value)[0..ImplSize]); + std.mem.copy(u8, self.mem[0..], @as([*]const u8, @ptrCast(&value))[0..ImplSize]); } return TInterface{