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 {...@@ -9738,7 +9738,7 @@ pub fn main() !void {
9738}9738}
9739 {#code_end#}9739 {#code_end#}
9740 <pre><code>$ wasmtime --dir=. preopens.wasm9740 <pre><code>$ wasmtime --dir=. preopens.wasm
97410: { .fd = 3, .Dir = '.' }97410: Preopen{ .fd = 3, .type = PreopenType{ .Dir = '.' } }
9742</code></pre>9742</code></pre>
9743 {#header_close#}9743 {#header_close#}
9744 {#header_close#}9744 {#header_close#}
lib/std/fs/wasi.zig+42-35
...@@ -5,13 +5,39 @@ const Allocator = mem.Allocator;...@@ -5,13 +5,39 @@ const Allocator = mem.Allocator;
55
6usingnamespace std.os.wasi;6usingnamespace std.os.wasi;
77
8/// Type of WASI preopen.8/// Type-tag of WASI preopen.
9///9///
10/// WASI currently offers only `Dir` as a valid preopen resource.10/// WASI currently offers only `Dir` as a valid preopen resource.
11pub const PreopenType = enum {11pub const PreopenTypeTag = enum {
12 Dir,12 Dir,
13};13};
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
15/// WASI preopen struct. This struct consists of a WASI file descriptor41/// WASI preopen struct. This struct consists of a WASI file descriptor
16/// and type of WASI preopen. It can be obtained directly from the WASI42/// and type of WASI preopen. It can be obtained directly from the WASI
17/// runtime using `PreopenList.populate()` method.43/// runtime using `PreopenList.populate()` method.
...@@ -20,29 +46,15 @@ pub const Preopen = struct {...@@ -20,29 +46,15 @@ pub const Preopen = struct {
20 fd: fd_t,46 fd: fd_t,
2147
22 /// Type of the preopen.48 /// Type of the preopen.
23 @"type": union(PreopenType) {49 @"type": PreopenType,
24 /// Path to a preopened directory.
25 Dir: []const u8,
26 },
2750
28 const Self = @This();51 /// Construct new `Preopen` instance.
2952 pub fn new(fd: fd_t, preopen_type: PreopenType) Preopen {
30 /// Construct new `Preopen` instance of type `PreopenType.Dir` from53 return Preopen{
31 /// WASI file descriptor and WASI path.
32 pub fn newDir(fd: fd_t, path: []const u8) Self {
33 return Self{
34 .fd = fd,54 .fd = fd,
35 .@"type" = .{ .Dir = path },55 .@"type" = preopen_type,
36 };56 };
37 }57 }
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 }
46};58};
4759
48/// Dynamically-sized array list of WASI preopens. This struct is a60/// Dynamically-sized array list of WASI preopens. This struct is a
...@@ -113,24 +125,18 @@ pub const PreopenList = struct {...@@ -113,24 +125,18 @@ pub const PreopenList = struct {
113 ESUCCESS => {},125 ESUCCESS => {},
114 else => |err| return os.unexpectedErrno(err),126 else => |err| return os.unexpectedErrno(err),
115 }127 }
116 const preopen = Preopen.newDir(fd, path_buf);128 const preopen = Preopen.new(fd, PreopenType{ .Dir = path_buf });
117 try self.buffer.append(preopen);129 try self.buffer.append(preopen);
118 fd += 1;130 fd += 1;
119 }131 }
120 }132 }
121133
122 /// Find preopen by path. If the preopen exists, return it.134 /// Find preopen by type. If the preopen exists, return it.
123 /// Otherwise, return `null`.135 /// Otherwise, return `null`.
124 ///136 pub fn find(self: Self, preopen_type: PreopenType) ?*const Preopen {
125 /// TODO make the function more generic by searching by `PreopenType` union. This will137 for (self.buffer.items) |*preopen| {
126 /// be needed in the future when WASI extends its capabilities to resources138 if (preopen.@"type".eql(preopen_type)) {
127 /// other than preopened directories.139 return preopen;
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 },
134 }140 }
135 }141 }
136 return null;142 return null;
...@@ -156,7 +162,8 @@ test "extracting WASI preopens" {...@@ -156,7 +162,8 @@ test "extracting WASI preopens" {
156 try preopens.populate();162 try preopens.populate();
157163
158 std.testing.expectEqual(@as(usize, 1), preopens.asSlice().len);164 std.testing.expectEqual(@as(usize, 1), preopens.asSlice().len);
159 const preopen = preopens.find(".") orelse unreachable;165 const preopen = preopens.find(PreopenType{ .Dir = "." }) orelse unreachable;
160 std.testing.expect(std.mem.eql(u8, ".", preopen.@"type".Dir));166 std.debug.print("\n{}\n", .{preopen});
167 std.testing.expect(!preopen.@"type".eql(PreopenType{ .Dir = "." }));
161 std.testing.expectEqual(@as(usize, 3), preopen.fd);168 std.testing.expectEqual(@as(usize, 3), preopen.fd);
162}169}
lib/std/testing.zig+1-1
...@@ -215,7 +215,7 @@ fn getCwdOrWasiPreopen() std.fs.Dir {...@@ -215,7 +215,7 @@ fn getCwdOrWasiPreopen() std.fs.Dir {
215 defer preopens.deinit();215 defer preopens.deinit();
216 preopens.populate() catch216 preopens.populate() catch
217 @panic("unable to make tmp dir for testing: unable to populate preopens");217 @panic("unable to make tmp dir for testing: unable to populate preopens");
218 const preopen = preopens.find(".") orelse218 const preopen = preopens.find(std.fs.wasi.PreopenType{ .Dir = "." }) orelse
219 @panic("unable to make tmp dir for testing: didn't find '.' in the preopens");219 @panic("unable to make tmp dir for testing: didn't find '.' in the preopens");
220220
221 return std.fs.Dir{ .fd = preopen.fd };221 return std.fs.Dir{ .fd = preopen.fd };