|
1 | 1 | const std = @import("std"); |
2 | 2 |
|
3 | | -pub const Ctx = @import("std/http/Client.zig").Ctx; |
4 | | -pub const Cbk = @import("std/http/Client.zig").Cbk; |
5 | | - |
6 | | -pub const Blocking = struct { |
7 | | - pub fn connect( |
8 | | - _: *Blocking, |
9 | | - comptime ctxT: type, |
10 | | - ctx: *ctxT, |
11 | | - comptime cbk: Cbk, |
12 | | - socket: std.posix.socket_t, |
13 | | - address: std.net.Address, |
14 | | - ) void { |
15 | | - std.posix.connect(socket, &address.any, address.getOsSockLen()) catch |err| { |
16 | | - std.posix.close(socket); |
17 | | - cbk(ctx, err) catch |e| { |
18 | | - ctx.setErr(e); |
19 | | - }; |
20 | | - }; |
21 | | - cbk(ctx, {}) catch |e| ctx.setErr(e); |
| 3 | +// IO is a type defined via a root declaration. |
| 4 | +// It must implements the following methods: |
| 5 | +// - connect, onConnect |
| 6 | +// - send, onSend |
| 7 | +// - recv, onRecv |
| 8 | +// It must also define the following types: |
| 9 | +// - Completion |
| 10 | +// - ConnectError |
| 11 | +// - SendError |
| 12 | +// - RecvError |
| 13 | +// see Blocking.io for an implementation example. |
| 14 | +pub const IO = blk: { |
| 15 | + const root = @import("root"); |
| 16 | + if (@hasDecl(root, "IO")) { |
| 17 | + break :blk root.IO; |
22 | 18 | } |
| 19 | + @compileError("no IO API defined at root"); |
| 20 | +}; |
| 21 | + |
| 22 | +// Wrapper for a base IO API. |
| 23 | +pub fn Wrapper(IO_T: type) type { |
| 24 | + return struct { |
| 25 | + io: *IO_T, |
| 26 | + completion: IO_T.Completion, |
| 27 | + |
| 28 | + const Self = @This(); |
| 29 | + |
| 30 | + pub fn init(io: *IO_T) Self { |
| 31 | + return .{ .io = io, .completion = undefined }; |
| 32 | + } |
| 33 | + |
| 34 | + // NOTE: Business methods connect, send, recv expect a Ctx |
| 35 | + // who should reference the base IO API in Ctx.io field |
| 36 | + |
| 37 | + // NOTE: Ctx is already known (ie. @import("std/http/Client.zig").Ctx) |
| 38 | + // but we require to provide its type (comptime) as argument |
| 39 | + // to avoid dependency loop |
| 40 | + // ie. Wrapper requiring Ctx and Ctx requiring Wrapper |
| 41 | + |
| 42 | + fn Cbk(comptime Ctx: type) type { |
| 43 | + return *const fn (ctx: *Ctx, res: anyerror!void) anyerror!void; |
| 44 | + } |
23 | 45 |
|
24 | | - pub fn send( |
25 | | - _: *Blocking, |
26 | | - comptime ctxT: type, |
27 | | - ctx: *ctxT, |
28 | | - comptime cbk: Cbk, |
29 | | - socket: std.posix.socket_t, |
30 | | - buf: []const u8, |
31 | | - ) void { |
32 | | - const len = std.posix.write(socket, buf) catch |err| { |
33 | | - cbk(ctx, err) catch |e| { |
34 | | - return ctx.setErr(e); |
| 46 | + pub fn connect( |
| 47 | + self: *Self, |
| 48 | + comptime Ctx: type, |
| 49 | + ctx: *Ctx, |
| 50 | + comptime cbk: Cbk(Ctx), |
| 51 | + socket: std.posix.socket_t, |
| 52 | + address: std.net.Address, |
| 53 | + ) void { |
| 54 | + self.io.connect(Ctx, ctx, &self.completion, onConnect(Ctx, cbk), socket, address); |
| 55 | + } |
| 56 | + |
| 57 | + fn onConnectFn(comptime Ctx: type) type { |
| 58 | + return fn ( |
| 59 | + ctx: *Ctx, |
| 60 | + _: *IO_T.Completion, |
| 61 | + result: IO_T.ConnectError!void, |
| 62 | + ) void; |
| 63 | + } |
| 64 | + fn onConnect(comptime Ctx: type, comptime cbk: Cbk(Ctx)) onConnectFn(Ctx) { |
| 65 | + const s = struct { |
| 66 | + fn on( |
| 67 | + ctx: *Ctx, |
| 68 | + _: *IO_T.Completion, |
| 69 | + result: IO_T.ConnectError!void, |
| 70 | + ) void { |
| 71 | + ctx.io.io.onConnect(result); // base IO callback |
| 72 | + _ = result catch |err| return ctx.setErr(err); |
| 73 | + cbk(ctx, {}) catch |err| return ctx.setErr(err); |
| 74 | + } |
35 | 75 | }; |
36 | | - return ctx.setErr(err); |
37 | | - }; |
38 | | - ctx.setLen(len); |
39 | | - cbk(ctx, {}) catch |e| ctx.setErr(e); |
40 | | - } |
| 76 | + return s.on; |
| 77 | + } |
41 | 78 |
|
42 | | - pub fn recv( |
43 | | - _: *Blocking, |
44 | | - comptime ctxT: type, |
45 | | - ctx: *ctxT, |
46 | | - comptime cbk: Cbk, |
47 | | - socket: std.posix.socket_t, |
48 | | - buf: []u8, |
49 | | - ) void { |
50 | | - const len = std.posix.read(socket, buf) catch |err| { |
51 | | - cbk(ctx, err) catch |e| { |
52 | | - return ctx.setErr(e); |
| 79 | + pub fn send( |
| 80 | + self: *Self, |
| 81 | + comptime Ctx: type, |
| 82 | + ctx: *Ctx, |
| 83 | + comptime cbk: Cbk(Ctx), |
| 84 | + socket: std.posix.socket_t, |
| 85 | + buf: []const u8, |
| 86 | + ) void { |
| 87 | + self.io.send(Ctx, ctx, &self.completion, onSend(Ctx, cbk), socket, buf); |
| 88 | + } |
| 89 | + |
| 90 | + fn onSendFn(comptime Ctx: type) type { |
| 91 | + return fn ( |
| 92 | + ctx: *Ctx, |
| 93 | + _: *IO_T.Completion, |
| 94 | + result: IO_T.SendError!usize, |
| 95 | + ) void; |
| 96 | + } |
| 97 | + fn onSend(comptime Ctx: type, comptime cbk: Cbk(Ctx)) onSendFn(Ctx) { |
| 98 | + const s = struct { |
| 99 | + fn on( |
| 100 | + ctx: *Ctx, |
| 101 | + _: *IO_T.Completion, |
| 102 | + result: IO_T.SendError!usize, |
| 103 | + ) void { |
| 104 | + ctx.io.io.onSend(result); // base IO callback |
| 105 | + const len = result catch |err| return ctx.setErr(err); |
| 106 | + ctx.setLen(len); |
| 107 | + cbk(ctx, {}) catch |e| ctx.setErr(e); |
| 108 | + } |
53 | 109 | }; |
54 | | - return ctx.setErr(err); |
55 | | - }; |
56 | | - ctx.setLen(len); |
57 | | - cbk(ctx, {}) catch |e| ctx.setErr(e); |
58 | | - } |
59 | | -}; |
| 110 | + return s.on; |
| 111 | + } |
| 112 | + |
| 113 | + pub fn recv( |
| 114 | + self: *Self, |
| 115 | + comptime Ctx: type, |
| 116 | + ctx: *Ctx, |
| 117 | + comptime cbk: Cbk(Ctx), |
| 118 | + socket: std.posix.socket_t, |
| 119 | + buf: []u8, |
| 120 | + ) void { |
| 121 | + self.io.recv(Ctx, ctx, &self.completion, onRecv(Ctx, cbk), socket, buf); |
| 122 | + } |
| 123 | + |
| 124 | + fn onRecvFn(comptime Ctx: type) type { |
| 125 | + return fn ( |
| 126 | + ctx: *Ctx, |
| 127 | + _: *IO_T.Completion, |
| 128 | + result: IO_T.RecvError!usize, |
| 129 | + ) void; |
| 130 | + } |
| 131 | + fn onRecv(comptime Ctx: type, comptime cbk: Cbk(Ctx)) onRecvFn(Ctx) { |
| 132 | + const s = struct { |
| 133 | + fn do( |
| 134 | + ctx: *Ctx, |
| 135 | + _: *IO_T.Completion, |
| 136 | + result: IO_T.RecvError!usize, |
| 137 | + ) void { |
| 138 | + ctx.io.io.onRecv(result); // base IO callback |
| 139 | + const len = result catch |err| return ctx.setErr(err); |
| 140 | + ctx.setLen(len); |
| 141 | + cbk(ctx, {}) catch |err| return ctx.setErr(err); |
| 142 | + } |
| 143 | + }; |
| 144 | + return s.do; |
| 145 | + } |
| 146 | + }; |
| 147 | +} |
0 commit comments