| ... | @@ -258,18 +258,6 @@ pub const ArgIteratorWasi = struct { | ... | @@ -258,18 +258,6 @@ pub const ArgIteratorWasi = struct { |
| 258 | } | 258 | } |
| 259 | }; | 259 | }; |
| 260 | | 260 | |
| 261 | test "process.ArgIteratorWasi" { | | |
| 262 | if (builtin.os.tag != .wasi) return error.SkipZigTest; | | |
| 263 | | | |
| 264 | var ga = std.testing.allocator; | | |
| 265 | var args_it = try ArgIteratorWasi.init(ga); | | |
| 266 | defer args_it.deinit(); | | |
| 267 | | | |
| 268 | testing.expectEqual(@as(usize, 1), args_it.args.len); | | |
| 269 | const prog_name = args_it.next() orelse unreachable; | | |
| 270 | testing.expect(mem.eql(u8, "test.wasm", prog_name)); | | |
| 271 | } | | |
| 272 | | | |
| 273 | pub const ArgIteratorWindows = struct { | 261 | pub const ArgIteratorWindows = struct { |
| 274 | index: usize, | 262 | index: usize, |
| 275 | cmd_line: [*]const u8, | 263 | cmd_line: [*]const u8, |
| ... | @@ -429,15 +417,9 @@ pub const ArgIterator = struct { | ... | @@ -429,15 +417,9 @@ pub const ArgIterator = struct { |
| 429 | inner: InnerType, | 417 | inner: InnerType, |
| 430 | | 418 | |
| 431 | /// Initialize the args iterator. | 419 | /// Initialize the args iterator. |
| 432 | /// | | |
| 433 | /// On WASI, will panic if the default Wasm page allocator runs out of memory | | |
| 434 | /// or there is an error fetching the args from the runtime. If you want to | | |
| 435 | /// use custom allocator and handle the errors yourself, call `initWasi()` instead. | | |
| 436 | /// You also must remember to free the buffer with `deinitWasi()` call. | | |
| 437 | pub fn init() ArgIterator { | 420 | pub fn init() ArgIterator { |
| 438 | if (builtin.os.tag == .wasi) { | 421 | if (builtin.os.tag == .wasi) { |
| 439 | const allocator = std.heap.page_allocator; | 422 | @compileError("In WASI, use initWithAllocator instead."); |
| 440 | return ArgIterator.initWasi(allocator) catch @panic("unexpected error occurred when initializing ArgIterator"); | | |
| 441 | } | 423 | } |
| 442 | | 424 | |
| 443 | return ArgIterator{ .inner = InnerType.init() }; | 425 | return ArgIterator{ .inner = InnerType.init() }; |
| ... | @@ -445,10 +427,13 @@ pub const ArgIterator = struct { | ... | @@ -445,10 +427,13 @@ pub const ArgIterator = struct { |
| 445 | | 427 | |
| 446 | pub const InitError = ArgIteratorWasi.InitError; | 428 | pub const InitError = ArgIteratorWasi.InitError; |
| 447 | | 429 | |
| 448 | /// If you are targeting WASI, you can call this to manually specify the allocator and | 430 | /// You must deinitialize iterator's internal buffers by calling `deinit` when done. |
| 449 | /// handle any errors. | 431 | pub fn initWithAllocator(allocator: *mem.Allocator) InitError!ArgIterator { |
| 450 | pub fn initWasi(allocator: *mem.Allocator) InitError!ArgIterator { | 432 | if (builtin.os.tag == .wasi) { |
| 451 | return ArgIterator{ .inner = try InnerType.init(allocator) }; | 433 | return ArgIterator{ .inner = try InnerType.init(allocator) }; |
| | 434 | } |
| | 435 | |
| | 436 | return ArgIterator{ .inner = InnerType.init() }; |
| 452 | } | 437 | } |
| 453 | | 438 | |
| 454 | pub const NextError = ArgIteratorWindows.NextError; | 439 | pub const NextError = ArgIteratorWindows.NextError; |
| ... | @@ -478,10 +463,13 @@ pub const ArgIterator = struct { | ... | @@ -478,10 +463,13 @@ pub const ArgIterator = struct { |
| 478 | return self.inner.skip(); | 463 | return self.inner.skip(); |
| 479 | } | 464 | } |
| 480 | | 465 | |
| 481 | /// If you are targeting WASI, call this to free the iterator's internal buffer | 466 | /// Call this to free the iterator's internal buffer if the iterator |
| 482 | /// after you are done with it. | 467 | /// was created with `initWithAllocator` function. |
| 483 | pub fn deinitWasi(self: *ArgIterator) void { | 468 | pub fn deinit(self: *ArgIterator) void { |
| 484 | self.inner.deinit(); | 469 | // Unless we're targeting WASI, this is a no-op. |
| | 470 | if (builtin.os.tag == .wasi) { |
| | 471 | self.inner.deinit(); |
| | 472 | } |
| 485 | } | 473 | } |
| 486 | }; | 474 | }; |
| 487 | | 475 | |
| ... | @@ -489,11 +477,33 @@ pub fn args() ArgIterator { | ... | @@ -489,11 +477,33 @@ pub fn args() ArgIterator { |
| 489 | return ArgIterator.init(); | 477 | return ArgIterator.init(); |
| 490 | } | 478 | } |
| 491 | | 479 | |
| | 480 | /// You must deinitialize iterator's internal buffers by calling `deinit` when done. |
| | 481 | pub fn argsWithAllocator(allocator: *mem.Allocator) ArgIterator.InitError!ArgIterator { |
| | 482 | return ArgIterator.initWithAllocator(allocator); |
| | 483 | } |
| | 484 | |
| | 485 | test "args iterator" { |
| | 486 | var ga = std.testing.allocator; |
| | 487 | var it = if (builtin.os.tag == .wasi) argsWithAllocator(ga) else args(); |
| | 488 | defer it.deinit(); // no-op unless WASI |
| | 489 | |
| | 490 | testing.expect(it.skip()); |
| | 491 | const prog_name = it.next(ga) orelse unreachable; |
| | 492 | defer ga.free(prog_name); |
| | 493 | |
| | 494 | const expected_bin_name = switch (builtin.os.tag) { |
| | 495 | .wasi => "test.wasm", |
| | 496 | .windows => "test.exe", |
| | 497 | else => "test", |
| | 498 | }; |
| | 499 | testing.expect(mem.eql(u8, expected_bin_name, prog_name)); |
| | 500 | } |
| | 501 | |
| 492 | /// Caller must call argsFree on result. | 502 | /// Caller must call argsFree on result. |
| 493 | pub fn argsAlloc(allocator: *mem.Allocator) ![][]u8 { | 503 | pub fn argsAlloc(allocator: *mem.Allocator) ![][]u8 { |
| 494 | // TODO refactor to only make 1 allocation. | 504 | // TODO refactor to only make 1 allocation. |
| 495 | var it = args(); | 505 | var it = if (builtin.os.tag == .wasi) argsWithAllocator(allocator) else args(); |
| 496 | defer if (builtin.os.tag == .wasi) it.deinitWasi(); | 506 | defer it.deinit(); |
| 497 | | 507 | |
| 498 | var contents = std.ArrayList(u8).init(allocator); | 508 | var contents = std.ArrayList(u8).init(allocator); |
| 499 | defer contents.deinit(); | 509 | defer contents.deinit(); |