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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
|
const std = @import("std");
pub const ReadError = error {
EndOfBuffer
};
pub fn Cursor(comptime T: type) type {
return struct {
const Self = @This();
buffer: []const T,
index: usize,
touched_index: usize,
pub fn init(buffer: []const T) Self {
return .{
.buffer = buffer,
.index = 0,
.touched_index = 0,
};
}
pub fn peek(self: Self, amount: usize) ReadError![]const T {
if (self.index + amount > self.buffer.len) {
return ReadError.EndOfBuffer;
}
return self.buffer[self.index..self.index + amount];
}
pub fn consume(self: *Self, amount: usize) ReadError![]const T {
const slice = try self.peek(amount);
self.index += amount;
self.touched_index = self.index;
return slice;
}
pub fn snapshot(self: Self) usize {
return self.index;
}
pub fn rollback(self: *Self, index: usize) void {
self.index = index;
}
pub fn touched_slice(self: Self) []const T {
return self.buffer[0..self.touched_index];
}
};
}
test "peek" {
const buffer = "1234";
const cursor = Cursor(u8).init(buffer);
try std.testing.expectEqualSlices(u8, "1", try cursor.peek(1));
try std.testing.expectEqualSlices(u8, "12", try cursor.peek(2));
try std.testing.expectEqualSlices(u8, "123", try cursor.peek(3));
try std.testing.expectEqualSlices(u8, "1234", try cursor.peek(4));
try std.testing.expectError(ReadError.EndOfBuffer, cursor.peek(5));
}
test "consume" {
const buffer = "12345678";
var cursor = Cursor(u8).init(buffer);
try std.testing.expectEqualSlices(u8, "1", try cursor.consume(1));
try std.testing.expectEqualSlices(u8, "23", try cursor.consume(2));
try std.testing.expectEqualSlices(u8, "456", try cursor.consume(3));
try std.testing.expectError(ReadError.EndOfBuffer, cursor.consume(4));
}
|