aboutsummaryrefslogtreecommitdiff
path: root/src/io.zig
blob: 886d7e79d531296e37eb7f8634a1c31a9a420380 (plain)
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
const std = @import("std");

pub fn Context(readerType: anytype, writerType: anytype) type {
    return struct {
        reader: readerType,
        writer: writerType,
        lastChar: ?i64 = null,
        allocator: std.mem.Allocator,
        const Self = @This();
        pub fn deinit(self: *Self) void {
            self.allocator.destroy(self);
        }
        pub fn init(allocator: std.mem.Allocator, reader: readerType, writer: writerType) !*Self {
            var c = try allocator.create(Self);
            c.allocator = allocator;
            c.reader = reader;
            c.writer = writer;
            return c;
        }
        pub fn characterInput(self: *Self) !i64 {
            if (self.lastChar) |c| {
                self.lastChar = null;
                return c;
            }
            var buffer = [_]u8{0};
            var n = try self.reader.read(buffer[0..]);
            if (n == 1) {
                return buffer[0];
            }
            return error.IOError;
        }
        test "characterInput" {
            var stdin = std.io.fixedBufferStream("ab0");
            var stdout = std.ArrayList(u8).init(std.testing.allocator);
            defer stdout.deinit();
            var ioContext = try context(std.testing.allocator, stdin, stdout);
            defer ioContext.deinit();
            try std.testing.expectEqual(try ioContext.characterInput(), 'a');
            try std.testing.expectEqual(try ioContext.characterInput(), 'b');
            try std.testing.expectEqual(try ioContext.characterInput(), '0');
            try std.testing.expectEqual(ioContext.characterInput(), error.IOError);
        }
        pub fn decimalInput(self: *Self) !i64 {
            var result: i64 = undefined;
            while (true) { // Fist we need to find the next numeric char
                const c = self.characterInput() catch return error.IOError;
                if (c >= '0' and c <= '9') {
                    result = c - '0';
                    break;
                }
            }
            while (true) { // then we read until we encounter a non numeric char
                const c = self.characterInput() catch break;
                if (c >= '0' and c <= '9') {
                    result = result * 10 + c - '0';
                } else {
                    self.lastChar = c;
                    break;
                }
            }
            return result;
        }
        test "decimalInput" {
            var stdin = std.io.fixedBufferStream("1 234abc5d6ef");
            var stdout = std.ArrayList(u8).init(std.testing.allocator);
            defer stdout.deinit();
            var ioContext = try context(std.testing.allocator, stdin, stdout);
            defer ioContext.deinit();
            try std.testing.expectEqual(try ioContext.decimalInput(), 1);
            try std.testing.expectEqual(try ioContext.decimalInput(), 234);
            try std.testing.expectEqual(try ioContext.decimalInput(), 5);
            try std.testing.expectEqual(try ioContext.decimalInput(), 6);
            try std.testing.expectEqual(ioContext.decimalInput(), error.IOError);
        }
        pub fn characterOutput(self: Self, v: i64) !void {
            try self.writer.print("{c}", .{@intCast(u8, v)});
            return;
        }
        pub fn decimalOutput(self: Self, v: i64) !void {
            try self.writer.print("{d}", .{v});
            return;
        }
    };
}

pub fn context(allocator: std.mem.Allocator, reader: anytype, writer: anytype) !*Context(@TypeOf(reader), @TypeOf(writer)) {
    return Context(@TypeOf(reader), @TypeOf(writer)).init(allocator, reader, writer);
}

test "all" {
    std.testing.refAllDecls(@This());
}