io.zig (2069B)
1 const std = @import("std"); 2 3 // Process-wide handles, populated once from `std.process.Init` in `main`. The 4 // app is a short-lived single-threaded CLI, so threading these through every 5 // call site would be pure noise; ambient state keeps the IO surface small. 6 // They are optionals (not `undefined`) so that any use before `init` is a 7 // checked unwrap panic rather than undefined behavior. 8 var rt_handle: ?std.Io = null; 9 var env_map: ?*std.process.Environ.Map = null; 10 11 pub fn init(io_handle: std.Io, environ: *std.process.Environ.Map) void { 12 rt_handle = io_handle; 13 env_map = environ; 14 } 15 16 pub fn rt() std.Io { 17 return rt_handle.?; 18 } 19 20 pub fn getenv(key: []const u8) ?[]const u8 { 21 return env_map.?.get(key); 22 } 23 24 pub const Writer = struct { 25 inner: std.Io.File.Writer, 26 failed: bool = false, 27 28 pub fn print(self: *Writer, comptime fmt: []const u8, args: anytype) !void { 29 if (self.failed) return; 30 self.inner.interface.print(fmt, args) catch |err| { 31 if (err == error.WriteFailed) { 32 self.failed = true; 33 return; 34 } 35 return err; 36 }; 37 } 38 39 pub fn end(self: *Writer) !void { 40 if (self.failed) return; 41 self.inner.interface.flush() catch |err| { 42 if (err == error.WriteFailed) { 43 self.failed = true; 44 return; 45 } 46 return err; 47 }; 48 } 49 }; 50 51 pub fn getStdout(buf: []u8) Writer { 52 return .{ .inner = std.Io.File.stdout().writerStreaming(rt(), buf) }; 53 } 54 55 pub fn warn(comptime fmt: []const u8, args: anytype) void { 56 var buf: [4096]u8 = undefined; 57 var writer = std.Io.File.stderr().writerStreaming(rt(), &buf); 58 writer.interface.print(fmt, args) catch |err| { 59 std.log.warn("failed to write to stderr: {}", .{err}); 60 }; 61 writer.interface.flush() catch |err| { 62 std.log.warn("failed to flush stderr writer: {}", .{err}); 63 }; 64 } 65 66 pub fn fatal(comptime fmt: []const u8, args: anytype) noreturn { 67 warn(fmt ++ "\n", args); 68 std.process.exit(1); 69 }