const std = @import("std"); const iter = @This(); const IteratorError = error{ UnexpectedValue, }; pub fn Iterator(comptime T: type) type { return struct{ const Self = @This(); items: []const T, index: usize = 0, pub fn next(self: *Self) ?T { if (self.empty()) return null; defer self.index += 1; return self.items[self.index]; } pub fn peek(self: Self) ?T { if (self.empty()) return null else return self.items[self.index]; } pub inline fn empty(self: Self) bool { if (self.items.len < 1 or self.index >= self.items.len) return true else return false; } pub fn consume(self: *Self, expect: T) IteratorError!?T { if (std.meta.eql(self.peek().?, expect)) return self.next() else return IteratorError.UnexpectedValue; } }; } const t = std.testing; test "simple iterator" { var iterator = Iterator(u8){.items = "Hello World!"}; for ("Hello World!", 0..) |c,i| { try t.expect(c == iterator.peek().?); try t.expect(c == iterator.next().?); try t.expect(c == iterator.items[i]); } } test "consume pass" { var iterator = Iterator(u8){.items = "Hello World!"}; _=iterator.next(); _=iterator.next(); _=iterator.next(); try t.expect((try iterator.consume('l')).? == 'l'); try t.expect((try iterator.consume('o')).? == 'o'); try t.expect((try iterator.consume(' ')).? == ' '); } test "consume fail" { var iterator = Iterator(u8){.items = "Hello World!"}; _=iterator.next(); _=iterator.next(); _=iterator.next(); try t.expectError(IteratorError.UnexpectedValue, iterator.consume('e')); try t.expectError(IteratorError.UnexpectedValue, iterator.consume('o')); try t.expectError(IteratorError.UnexpectedValue, iterator.consume(' ')); }