authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-06-23 21:54:36+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-06-23 21:54:36+02:00
log66e5205047576768f075ec8f016f6fe21ce71bd0
tree2456fd5d749907879298e1faea90b779d0c0b370
parent78c6d39cd49225bdfd2de4da7b1730ba26a41ba4

Refactor PreopenList.find()

This commit generalizes `std.fs.wasi.PreopenList.find(...)` allowing search by `std.fs.wasi.PreopenType` union type rather than by dir name. In the future releases of WASI, it is expected to have more preopen types (or capabilities) than just directories. This commit aligns itself with that vision. This is a potentially breaking change. However, since `std.fs.wasi.PreopenList` wasn't made part of any Zig release yet, I think we should be OK to introduce those changes without pointing to any deprecations.

3 files changed, 44 insertions(+), 37 deletions(-)

doc/langref.html.in+1-1
......@@ -9738,7 +9738,7 @@ pub fn main() !void {
97389738}
97399739 {#code_end#}
97409740 <pre><code>$ wasmtime --dir=. preopens.wasm
97410: { .fd = 3, .Dir = '.' }
97410: Preopen{ .fd = 3, .type = PreopenType{ .Dir = '.' } }
97429742</code></pre>
97439743 {#header_close#}
97449744 {#header_close#}
lib/std/fs/wasi.zig+42-35
......@@ -5,13 +5,39 @@ const Allocator = mem.Allocator;
55
66usingnamespace std.os.wasi;
77
8/// Type of WASI preopen.
8/// Type-tag of WASI preopen.
99///
1010/// WASI currently offers only `Dir` as a valid preopen resource.
11pub const PreopenType = enum {
11pub const PreopenTypeTag = enum {
1212 Dir,
1313};
1414
15/// Type of WASI preopen.
16///
17/// WASI currently offers only `Dir` as a valid preopen resource.
18pub const PreopenType = union(PreopenTypeTag) {
19 /// Preopened directory type.
20 Dir: []const u8,
21
22 const Self = @This();
23
24 pub fn eql(self: Self, other: PreopenType) bool {
25 if (!mem.eql(u8, @tagName(self), @tagName(other))) return false;
26
27 switch (self) {
28 PreopenTypeTag.Dir => |this_path| return mem.eql(u8, this_path, other.Dir),
29 }
30 }
31
32 pub fn format(self: Self, comptime fmt: []const u8, options: std.fmt.FormatOptions, out_stream: var) !void {
33 try out_stream.print("PreopenType{{ ", .{});
34 switch (self) {
35 PreopenType.Dir => |path| try out_stream.print(".Dir = '{}'", .{path}),
36 }
37 return out_stream.print(" }}", .{});
38 }
39};
40
1541/// WASI preopen struct. This struct consists of a WASI file descriptor
1642/// and type of WASI preopen. It can be obtained directly from the WASI
1743/// runtime using `PreopenList.populate()` method.
......@@ -20,29 +46,15 @@ pub const Preopen = struct {
2046 fd: fd_t,
2147
2248 /// Type of the preopen.
23 @"type": union(PreopenType) {
24 /// Path to a preopened directory.
25 Dir: []const u8,
26 },
49 @"type": PreopenType,
2750
28 const Self = @This();
29
30 /// Construct new `Preopen` instance of type `PreopenType.Dir` from
31 /// WASI file descriptor and WASI path.
32 pub fn newDir(fd: fd_t, path: []const u8) Self {
33 return Self{
51 /// Construct new `Preopen` instance.
52 pub fn new(fd: fd_t, preopen_type: PreopenType) Preopen {
53 return Preopen{
3454 .fd = fd,
35 .@"type" = .{ .Dir = path },
55 .@"type" = preopen_type,
3656 };
3757 }
38
39 pub fn format(self: Self, comptime fmt: []const u8, options: std.fmt.FormatOptions, out_stream: var) !void {
40 try out_stream.print("{{ .fd = {}, ", .{self.fd});
41 switch (self.@"type") {
42 PreopenType.Dir => |path| try out_stream.print(".Dir = '{}'", .{path}),
43 }
44 return out_stream.print(" }}", .{});
45 }
4658};
4759
4860/// Dynamically-sized array list of WASI preopens. This struct is a
......@@ -113,24 +125,18 @@ pub const PreopenList = struct {
113125 ESUCCESS => {},
114126 else => |err| return os.unexpectedErrno(err),
115127 }
116 const preopen = Preopen.newDir(fd, path_buf);
128 const preopen = Preopen.new(fd, PreopenType{ .Dir = path_buf });
117129 try self.buffer.append(preopen);
118130 fd += 1;
119131 }
120132 }
121133
122 /// Find preopen by path. If the preopen exists, return it.
134 /// Find preopen by type. If the preopen exists, return it.
123135 /// Otherwise, return `null`.
124 ///
125 /// TODO make the function more generic by searching by `PreopenType` union. This will
126 /// be needed in the future when WASI extends its capabilities to resources
127 /// other than preopened directories.
128 pub fn find(self: Self, path: []const u8) ?*const Preopen {
129 for (self.buffer.items) |preopen| {
130 switch (preopen.@"type") {
131 PreopenType.Dir => |preopen_path| {
132 if (mem.eql(u8, path, preopen_path)) return &preopen;
133 },
136 pub fn find(self: Self, preopen_type: PreopenType) ?*const Preopen {
137 for (self.buffer.items) |*preopen| {
138 if (preopen.@"type".eql(preopen_type)) {
139 return preopen;
134140 }
135141 }
136142 return null;
......@@ -156,7 +162,8 @@ test "extracting WASI preopens" {
156162 try preopens.populate();
157163
158164 std.testing.expectEqual(@as(usize, 1), preopens.asSlice().len);
159 const preopen = preopens.find(".") orelse unreachable;
160 std.testing.expect(std.mem.eql(u8, ".", preopen.@"type".Dir));
165 const preopen = preopens.find(PreopenType{ .Dir = "." }) orelse unreachable;
166 std.debug.print("\n{}\n", .{preopen});
167 std.testing.expect(!preopen.@"type".eql(PreopenType{ .Dir = "." }));
161168 std.testing.expectEqual(@as(usize, 3), preopen.fd);
162169}
lib/std/testing.zig+1-1
......@@ -215,7 +215,7 @@ fn getCwdOrWasiPreopen() std.fs.Dir {
215215 defer preopens.deinit();
216216 preopens.populate() catch
217217 @panic("unable to make tmp dir for testing: unable to populate preopens");
218 const preopen = preopens.find(".") orelse
218 const preopen = preopens.find(std.fs.wasi.PreopenType{ .Dir = "." }) orelse
219219 @panic("unable to make tmp dir for testing: didn't find '.' in the preopens");
220220
221221 return std.fs.Dir{ .fd = preopen.fd };