Skip to content

Instantly share code, notes, and snippets.

@guidoschmidt
Forked from ikskuh/closure.zig
Created November 2, 2023 22:19
Show Gist options
  • Save guidoschmidt/fd655eb119f5bfea395a6d5db0f73981 to your computer and use it in GitHub Desktop.
Save guidoschmidt/fd655eb119f5bfea395a6d5db0f73981 to your computer and use it in GitHub Desktop.

Revisions

  1. @ikskuh ikskuh revised this gist Jan 17, 2021. 1 changed file with 32 additions and 8 deletions.
    40 changes: 32 additions & 8 deletions closure.zig
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,14 @@
    const std = @import("std");

    pub fn main() void {
    std.log.info("mutable closure:",.{});
    runMutDemo();

    std.log.info("const closure:",.{});
    runConstDemo();
    }

    fn runMutDemo() void {
    var call_count: usize = 0;

    var closed = Closure(struct{fn C(state: *struct{i:u32=0, c:*usize}, increment: u32) u32 {
    @@ -11,15 +19,31 @@ pub fn main() void {
    .{ .c = &call_count },
    );

    std.log.info("invocation 1 => {}", .{ closed.invoke(.{ 1 }) });
    std.log.info("invocation 1 => {}", .{ closed.invoke(.{ 0 }) });
    std.log.info("invocation 1 => {}", .{ closed.invoke(.{ 2 }) });
    std.log.info("invocation 1 => {}", .{ closed.invoke(.{ 3 }) });
    std.log.info("invocation 1 => {}", .{ closed.invoke(.{ 0 }) });
    std.log.info(" invocation 1 => {}", .{ closed.invoke(.{ 1 }) });
    std.log.info(" invocation 2 => {}", .{ closed.invoke(.{ 0 }) });
    std.log.info(" invocation 3 => {}", .{ closed.invoke(.{ 2 }) });
    std.log.info(" invocation 4 => {}", .{ closed.invoke(.{ 3 }) });
    std.log.info(" invocation 5 => {}", .{ closed.invoke(.{ 0 }) });

    std.log.info(" invocation count: {}", .{ call_count });
    }

    fn runConstDemo() void {
    const closed = Closure(struct{fn C(state: struct{i:u32}, increment: u32) u32 {
    return state.i + increment;
    }}.C).init(
    .{ .i = 10 },
    );

    std.log.info("invocation count: {}", .{ call_count });
    std.log.info(" static invocation 1 => {}", .{ closed.invoke(.{ 1 }) });
    std.log.info(" static invocation 2 => {}", .{ closed.invoke(.{ 0 }) });
    std.log.info(" static invocation 3 => {}", .{ closed.invoke(.{ 2 }) });
    std.log.info(" static invocation 4 => {}", .{ closed.invoke(.{ 3 }) });
    std.log.info(" static invocation 5 => {}", .{ closed.invoke(.{ 0 }) });
    }

    /// Creates a closure type that will store and pass the first argument of the passed
    /// function
    fn Closure(comptime function: anytype) type {
    const F = @TypeOf(function);
    const A0 = @typeInfo(F).Fn.args[0].arg_type.?;
    @@ -40,8 +64,8 @@ fn Closure(comptime function: anytype) type {
    return Self { .state = state };
    }

    pub fn invoke(self: *Self, args: anytype) Result {
    return @call(.{}, function, .{&self.state} ++ args);
    pub fn invoke(self: if(is_mutable) *Self else Self, args: anytype) Result {
    return @call(.{}, function, .{ if(is_mutable) &self.state else self.state } ++ args);
    }
    };
    }
  2. @ikskuh ikskuh created this gist Jan 17, 2021.
    47 changes: 47 additions & 0 deletions closure.zig
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,47 @@
    const std = @import("std");

    pub fn main() void {
    var call_count: usize = 0;

    var closed = Closure(struct{fn C(state: *struct{i:u32=0, c:*usize}, increment: u32) u32 {
    defer state.i += increment;
    state.c.* += 1;
    return state.i;
    }}.C).init(
    .{ .c = &call_count },
    );

    std.log.info("invocation 1 => {}", .{ closed.invoke(.{ 1 }) });
    std.log.info("invocation 1 => {}", .{ closed.invoke(.{ 0 }) });
    std.log.info("invocation 1 => {}", .{ closed.invoke(.{ 2 }) });
    std.log.info("invocation 1 => {}", .{ closed.invoke(.{ 3 }) });
    std.log.info("invocation 1 => {}", .{ closed.invoke(.{ 0 }) });

    std.log.info("invocation count: {}", .{ call_count });
    }

    fn Closure(comptime function: anytype) type {
    const F = @TypeOf(function);
    const A0 = @typeInfo(F).Fn.args[0].arg_type.?;

    return struct {
    const Self = @This();

    pub const is_mutable = (@typeInfo(A0) == .Pointer);
    pub const State = if(is_mutable)
    std.meta.Child(A0)
    else
    A0;
    pub const Result = (@typeInfo(F).Fn.return_type.?);

    state: State,

    pub fn init(state: State) Self {
    return Self { .state = state };
    }

    pub fn invoke(self: *Self, args: anytype) Result {
    return @call(.{}, function, .{&self.state} ++ args);
    }
    };
    }