From eb4a758251f15f0b165bd7c13d8b5271c59556f0 Mon Sep 17 00:00:00 2001 From: kayomn Date: Wed, 2 Nov 2022 11:27:10 +0000 Subject: [PATCH] Make Function closures only accept a pointer context --- src/core/io.zig | 10 ++++++---- src/core/meta.zig | 31 +++++++++++++++---------------- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/core/io.zig b/src/core/io.zig index 5490c0f..be0c92b 100644 --- a/src/core/io.zig +++ b/src/core/io.zig @@ -69,7 +69,7 @@ pub const Allocator = union (enum) { /// Closure that captures a reference to readable resources like block devices, memory buffers, /// network sockets, and more. /// -pub const Reader = meta.Function(@sizeOf(usize), []u8, usize); +pub const Reader = meta.Function([]u8, usize); /// /// Returns a state machine for lazily computing all `Element` components of a given source input @@ -187,7 +187,7 @@ test "Spliterator of string literals" { /// Closure that captures a reference to writable resources like block devices, memory buffers, /// network sockets, and more. /// -pub const Writer = meta.Function(@sizeOf(usize), []const u8, usize); +pub const Writer = meta.Function([]const u8, usize); /// /// Returns a sliced reference of the raw bytes in `pointer`. @@ -383,8 +383,10 @@ test "Data swapping" { /// sent somewhere for whatever reason. /// pub fn nullWriter() Writer { - return Writer.capture(@as(usize, 0), struct { - fn write(_: usize, buffer: []const u8) usize { + var dummy: usize = 0; + + return Writer.capture(&dummy, struct { + fn write(_: *usize, buffer: []const u8) usize { return buffer.len; } }.write); diff --git a/src/core/meta.zig b/src/core/meta.zig index e7be22d..e176c1b 100644 --- a/src/core/meta.zig +++ b/src/core/meta.zig @@ -13,10 +13,10 @@ pub fn FnReturn(comptime Fn: type) type { /// Returns a single-input single-output closure type where `In` represents the input type, `Out` /// represents the output type, and `captures_size` represents the size of the closure context. /// -pub fn Function(comptime captures_size: usize, comptime In: type, comptime Out: type) type { +pub fn Function(comptime In: type, comptime Out: type) type { return struct { callErased: fn (*anyopaque, In) Out, - context: [captures_size]u8, + context: *anyopaque, /// /// Function type. @@ -27,37 +27,36 @@ pub fn Function(comptime captures_size: usize, comptime In: type, comptime Out: /// Invokes `self` with `input`, producing a result according to the current context data. /// pub fn call(self: *Self, input: In) Out { - return self.callErased(&self.context, input); + return self.callErased(self.context, input); } /// - /// Creates a new [Self] by capturing the `captures` value as the context and `invoke` as - /// the as the behavior executed when [call] or [callErased] is called. + /// Creates a new [Self] by capturing the `context` value as the capture context and + /// `invoke` as the behavior executed when [call] or [callErased] is called. /// /// The newly created [Self] is returned. /// - pub fn capture(captures: anytype, comptime invoke: fn (@TypeOf(captures), In) Out) Self { - const Captures = @TypeOf(captures); + pub fn capture(context: anytype, comptime invoke: fn (@TypeOf(context), In) Out) Self { + const Context = @TypeOf(context); - if (@sizeOf(Captures) > captures_size) - @compileError("`captures` exceeds the size limit of the capture context"); + switch (@typeInfo(Context)) { + .Pointer => |info| if (info.size == .Slice) + @compileError("`context` cannot be a slice"), - const captures_align = @alignOf(Captures); + else => @compileError("`context` must be a pointer"), + } var function = Self{ - .context = undefined, + .context = @ptrCast(*anyopaque, context), .callErased = struct { fn callErased(erased: *anyopaque, input: In) Out { - return invoke(if (Captures == void) {} else @ptrCast(*Captures, - @alignCast(@alignOf(Captures), erased)).*, input); + return invoke(@ptrCast(*Context, @alignCast( + @alignOf(Context), erased)).*, input); } }.callErased, }; - if (Captures != void) - @ptrCast(*Captures, @alignCast(captures_align, &function.context)).* = captures; - return function; } };