aboutsummaryrefslogtreecommitdiff
path: root/src/peek.zig
blob: 58911e934a7d86291e797e41ec8b148fc98781f4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
pub fn peekable(iterator: anytype) Peekable(@TypeOf(iterator)) {
    return .{ .iterator = iterator };
}

pub fn Peekable(Iterator: type) type {
    const ActualIterator = switch (@typeInfo(Iterator)) {
        .pointer => |p| p.child,
        else => Iterator,
    };
    const Next = @typeInfo(@TypeOf(ActualIterator.next)).@"fn";
    const Item = switch (@typeInfo(Next.return_type.?)) {
        .optional => |o| o.child,
        else => |i| i,
    };
    return struct {
        iterator: Iterator,
        peeked: ?Item = null,

        pub fn peek(self: *Self) ?Item {
            if (self.peeked) |peeked| return peeked;
            const item = self.iterator.next();
            self.peeked = item;
            return item;
        }

        pub fn next(self: *Self) ?Item {
            const item = if (self.peeked) |peeked| peeked else self.iterator.next();
            self.peeked = null;
            return item;
        }

        const Self = @This();
    };
}

test peekable {
    const expect = std.testing.expect;
    // std.meta.de

    var it = std.mem.window(u8, &[_]u8{ 1, 2, 3 }, 1, 1);
    var peek = peekable(&it);
    try expect(peek.next().?[0] == 1);
    try expect(peek.peek().?[0] == 2);
    try expect(peek.peek().?[0] == 2);
    try expect(peek.next().?[0] == 2);
    try expect(peek.next().?[0] == 3);
    try expect(peek.peek() == null);
    try expect(peek.next() == null);
}

const std = @import("std");