aboutsummaryrefslogtreecommitdiff
path: root/std/event/io.zig
blob: 29419a792e995435e3f6dc2539ac3597c3afc076 (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
const std = @import("../std.zig");
const builtin = @import("builtin");
const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
const mem = std.mem;

pub fn InStream(comptime ReadError: type) type {
    return struct {
        const Self = @This();
        pub const Error = ReadError;

        /// Return the number of bytes read. It may be less than buffer.len.
        /// If the number of bytes read is 0, it means end of stream.
        /// End of stream is not an error condition.
        readFn: async<*Allocator> fn (self: *Self, buffer: []u8) Error!usize,

        /// Return the number of bytes read. It may be less than buffer.len.
        /// If the number of bytes read is 0, it means end of stream.
        /// End of stream is not an error condition.
        pub async fn read(self: *Self, buffer: []u8) !usize {
            return await (async self.readFn(self, buffer) catch unreachable);
        }

        /// Return the number of bytes read. If it is less than buffer.len
        /// it means end of stream.
        pub async fn readFull(self: *Self, buffer: []u8) !usize {
            var index: usize = 0;
            while (index != buf.len) {
                const amt_read = try await (async self.read(buf[index..]) catch unreachable);
                if (amt_read == 0) return index;
                index += amt_read;
            }
            return index;
        }

        /// Same as `readFull` but end of stream returns `error.EndOfStream`.
        pub async fn readNoEof(self: *Self, buf: []u8) !void {
            const amt_read = try await (async self.readFull(buf[index..]) catch unreachable);
            if (amt_read < buf.len) return error.EndOfStream;
        }

        pub async fn readIntLittle(self: *Self, comptime T: type) !T {
            var bytes: [@sizeOf(T)]u8 = undefined;
            try await (async self.readNoEof(bytes[0..]) catch unreachable);
            return mem.readIntLittle(T, &bytes);
        }

        pub async fn readIntBe(self: *Self, comptime T: type) !T {
            var bytes: [@sizeOf(T)]u8 = undefined;
            try await (async self.readNoEof(bytes[0..]) catch unreachable);
            return mem.readIntBig(T, &bytes);
        }

        pub async fn readInt(self: *Self, comptime T: type, endian: builtin.Endian) !T {
            var bytes: [@sizeOf(T)]u8 = undefined;
            try await (async self.readNoEof(bytes[0..]) catch unreachable);
            return mem.readInt(T, &bytes, endian);
        }

        pub async fn readStruct(self: *Self, comptime T: type) !T {
            // Only extern and packed structs have defined in-memory layout.
            comptime assert(@typeInfo(T).Struct.layout != builtin.TypeInfo.ContainerLayout.Auto);
            var res: [1]T = undefined;
            try await (async self.readNoEof(@sliceToBytes(res[0..])) catch unreachable);
            return res[0];
        }
    };
}

pub fn OutStream(comptime WriteError: type) type {
    return struct {
        const Self = @This();
        pub const Error = WriteError;

        writeFn: async<*Allocator> fn (self: *Self, buffer: []u8) Error!void,
    };
}