diff options
| author | Nic Gaffney <gaffney_nic@protonmail.com> | 2025-10-20 01:59:56 -0500 |
|---|---|---|
| committer | Nic Gaffney <gaffney_nic@protonmail.com> | 2025-10-20 02:02:15 -0500 |
| commit | 78d191cbf396d2ea32d920282934aa44f8ade4be (patch) | |
| tree | 825d57cf191a761fa4ef40d543b525d87d9f6141 | |
| parent | 7093b84120dc899a08508b7da2472c5e3edcc008 (diff) | |
| download | funcz-78d191cbf396d2ea32d920282934aa44f8ade4be.tar.gz | |
inital commit
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | build.zig | 34 | ||||
| -rw-r--r-- | build.zig.zon | 6 | ||||
| -rw-r--r-- | src/lib.zig | 73 | ||||
| -rw-r--r-- | src/main.zig | 33 |
5 files changed, 148 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dca1103 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +zig-out/ +.zig-cache/ diff --git a/build.zig b/build.zig new file mode 100644 index 0000000..99b3ef9 --- /dev/null +++ b/build.zig @@ -0,0 +1,34 @@ +const std = @import("std"); + +pub fn build(b: *std.Build) !void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{.preferred_optimize_mode = .ReleaseSmall }); + + const lib = b.addLibrary(.{ + .name = "funcz", + .root_module = b.createModule(.{ + .root_source_file = b.path("src/lib.zig"), + .target = target, + .optimize = optimize, + }), + }); + b.installArtifact(lib); + + const exe = b.addExecutable(.{ + .name = "funczExample", + .root_module = b.createModule(.{ + .root_source_file = b.path("src/main.zig"), + .imports = &.{ .{.name = "funcz", .module = lib.root_module} }, + .target = target, + .optimize = optimize, + }) + }); + b.installArtifact(exe); + + const run_cmd = b.addRunArtifact(exe); + run_cmd.step.dependOn(b.getInstallStep()); + if (b.args) |args| run_cmd.addArgs(args); + const run_step = b.step("run", "Run the app"); + run_step.dependOn(&run_cmd.step); + +} diff --git a/build.zig.zon b/build.zig.zon new file mode 100644 index 0000000..ae01ad9 --- /dev/null +++ b/build.zig.zon @@ -0,0 +1,6 @@ +.{ + .name = .funcz, + .fingerprint = 0x30f8633228105f1a, + .version = "0.0.1", + .paths = .{ "src" }, +} diff --git a/src/lib.zig b/src/lib.zig new file mode 100644 index 0000000..8e99ad3 --- /dev/null +++ b/src/lib.zig @@ -0,0 +1,73 @@ +const std = @import("std"); + +/// Compose two single argument functions +pub fn compose( + comptime outerFunc: anytype, + comptime innerFunc: anytype +) blk:{ + const outerFuncType = @TypeOf(outerFunc); + const outerFuncTypeInfo = @typeInfo(outerFuncType); + if(outerFuncTypeInfo != .@"fn") + @compileError("Expected function, found " ++ @typeName(outerFuncType)); + const innerFuncType = @TypeOf(innerFunc); + const innerFuncTypeInfo = @typeInfo(innerFuncType); + if(innerFuncTypeInfo != .@"fn") + @compileError("Expected function, found " ++ @typeName(innerFuncType)); + const out = @typeInfo(@TypeOf(outerFunc)).@"fn".return_type.?; + const in = @typeInfo(@TypeOf(innerFunc)).@"fn".params[0].type.?; + break :blk fn(in) out; +} { + const out = @typeInfo(@TypeOf(outerFunc)).@"fn".return_type.?; + const in = @typeInfo(@TypeOf(innerFunc)).@"fn".params[0].type.?; + return struct { + fn func(input: in) out { + return outerFunc(innerFunc(input)); + } + }.func; +} + +pub fn mapAlloc( + allocator: std.mem.Allocator, + func: anytype, + items: anytype, +) error{OutOfMemory}!blk:{ + const itemsType = @TypeOf(items); + const itemsTypeInfo = @typeInfo(itemsType); + const funcType = @TypeOf(func); + const funcTypeInfo = @typeInfo(funcType); + if(funcTypeInfo != .@"fn") + @compileError("Expected function, found " ++ @typeName(funcType)); + if(itemsTypeInfo != .array and itemsTypeInfo != .pointer) { + @compileError("Expected array or slice, found " ++ @typeName(itemsType)); + } + + break :blk []funcTypeInfo.@"fn".return_type.?; +} { + const funcType = @TypeOf(func); + const funcTypeInfo = @typeInfo(funcType); + var result = try allocator.alloc(funcTypeInfo.@"fn".return_type.?, items.len); + for(items, 0..) |item, i| + result[i] = func(item); + return result; +} + +pub fn map( + func: anytype, + items: anytype, + buffer: anytype, +) void { + const funcType = @TypeOf(func); + const bufferType = @TypeOf(buffer); + const itemsType = @TypeOf(items); + const funcTypeInfo = @typeInfo(funcType); + const bufferTypeInfo = @typeInfo(bufferType); + const itemsTypeInfo = @typeInfo(itemsType); + if(funcTypeInfo != .@"fn") + @compileError("Expected function, found " ++ @typeName(funcType)); + if(itemsTypeInfo != .array and itemsTypeInfo != .pointer) + @compileError("Expected array, found " ++ @typeName(itemsType)); + if(bufferTypeInfo != .array and bufferTypeInfo != .pointer) + @compileError("Expected array, found " ++ @typeName(bufferType)); + for (items, 0..) |item, i| + buffer.*[i] = func(item); +} diff --git a/src/main.zig b/src/main.zig new file mode 100644 index 0000000..949c368 --- /dev/null +++ b/src/main.zig @@ -0,0 +1,33 @@ +const std = @import("std"); +const func = @import("funcz"); + +fn iter(n: i32) i32 { + return n + 1; +} + +fn mul2(n: i32) i32 { + return n * 2; +} + +pub fn main() !void { + var gpa = std.heap.DebugAllocator(.{}){}; + const allocator = gpa.allocator(); + const iterThenMul2 = func.compose(mul2, iter); + var items = [_]i32{ 0, 1, 2, 3, 4 }; + const itemsSlice: []i32 = items[0..items.len]; + const newItems = try func.mapAlloc(allocator, iterThenMul2, itemsSlice); + defer allocator.free(newItems); + var buffer: [128]i32 = undefined; + func.map(iterThenMul2, itemsSlice, &buffer); + std.debug.print("compose(mul2, iter)(5) = {d}\n", .{ iterThenMul2(5) }); + std.debug.print("mapAlloc(allocator, compose(mul2, iter), []i32{{ 0, 1, 2, 3, 4 }}) = {{ ", .{}); + for(newItems) |item| { + std.debug.print("{d}, ", .{item}); + } + std.debug.print("}}\n", .{}); + std.debug.print("map(compose(mul2, iter), []i32{{ 0, 1, 2, 3, 4 }}, &buffer) = {{ ", .{}); + for(buffer[0..items.len]) |item| { + std.debug.print("{d}, ", .{item}); + } + std.debug.print("}}\n", .{}); +} |
