From 23aab8414b31f1a644f8f838efcb2d04e01678c2 Mon Sep 17 00:00:00 2001 From: falsycat Date: Mon, 5 May 2025 11:38:03 +0900 Subject: [PATCH] add new command impl, Sequence --- src/hncore/command/Interface.zig | 11 ++-- src/hncore/command/generic.zig | 88 ++++++++++++++++++++++++++++++++ src/hncore/command/root.zig | 3 +- 3 files changed, 97 insertions(+), 5 deletions(-) create mode 100644 src/hncore/command/generic.zig diff --git a/src/hncore/command/Interface.zig b/src/hncore/command/Interface.zig index e1b230c..358007a 100644 --- a/src/hncore/command/Interface.zig +++ b/src/hncore/command/Interface.zig @@ -34,6 +34,12 @@ pub const Mock = struct { target : ?*i32 = null, destroyed: ?*bool = null, + pub fn init(alloc: std.mem.Allocator, target: ?*i32, destroyed: ?*bool) !Self { + return make(alloc, Mock { + .target = target, + .destroyed = destroyed, + }); + } pub fn deinit(self: *@This(), _: anytype) void { if (self.destroyed) |ptr| { ptr.* = true; @@ -117,10 +123,7 @@ test { var value: i32 = 0; var destroyed = false; { - const cmd = try Self.make(std.testing.allocator, Mock { - .target = &value, - .destroyed = &destroyed, - }); + const cmd = try Mock.init(std.testing.allocator, &value, &destroyed); defer cmd.deinit(); try cmd.apply(); diff --git a/src/hncore/command/generic.zig b/src/hncore/command/generic.zig new file mode 100644 index 0000000..e34d184 --- /dev/null +++ b/src/hncore/command/generic.zig @@ -0,0 +1,88 @@ +const std = @import("std"); + +const Interface = @import("./Interface.zig"); + +/// +const Sequence = struct { + /// + const Self = @This(); + + /// + commands: []Interface, + + /// + pub fn init(alloc: std.mem.Allocator, commands: []const Interface) !Interface { + const list = try alloc.dupe(Interface, commands); + errdefer alloc.free(list); + return try Interface.make(alloc, Self { + .commands = list, + }); + } + + /// + pub fn deinit(self: *Self, alloc: std.mem.Allocator) void { + for (self.commands) |command| { + command.deinit(); + } + alloc.free(self.commands); + } + + /// + pub fn apply(self: *Self, _: std.mem.Allocator) Interface.Error!void { + for (self.commands) |command| { + try command.apply(); + } + } + + /// + pub fn revert(self: *Self, _: std.mem.Allocator) Interface.Error!void { + var i = self.commands.len; + while (i > 0) { + i -= 1; + try self.commands[i].revert(); + } + } +}; + +test { + var value1: i32 = 0; + var value2: i32 = 0; + var value3: i32 = 0; + + var finished1 = false; + var finished2 = false; + var finished3 = false; + + { + var seq = blk: { + const alloc = std.testing.allocator; + + var cmd1 = try Interface.Mock.init(alloc, &value1, &finished1); + errdefer cmd1.deinit(); + + var cmd2 = try Interface.Mock.init(alloc, &value2, &finished2); + errdefer cmd2.deinit(); + + var cmd3 = try Interface.Mock.init(alloc, &value3, &finished3); + errdefer cmd3.deinit(); + + break :blk try Sequence.init(std.testing.allocator, &[_]Interface { + cmd1, cmd2, cmd3, + }); + }; + defer seq.deinit(); + + try seq.apply(); + try std.testing.expectEqual(1, value1); + try std.testing.expectEqual(1, value2); + try std.testing.expectEqual(1, value3); + + try seq.revert(); + try std.testing.expectEqual(0, value1); + try std.testing.expectEqual(0, value2); + try std.testing.expectEqual(0, value3); + } + try std.testing.expect(finished1); + try std.testing.expect(finished2); + try std.testing.expect(finished3); +} diff --git a/src/hncore/command/root.zig b/src/hncore/command/root.zig index e8889de..3f71a90 100644 --- a/src/hncore/command/root.zig +++ b/src/hncore/command/root.zig @@ -1,6 +1,7 @@ pub const Interface = @import("./Interface.zig"); -pub const task = @import("./task.zig"); +pub const generic = @import("./generic.zig"); +pub const task = @import("./task.zig"); test { @import("std").testing.refAllDecls(@This());