commit 42bf945818946a95a481c92fb101235a2945396a
parent 208223b916c59db30ee10b33e5f9bef9374d2a3e
Author: mtmn <miro@haravara.org>
Date: Wed, 10 Jun 2026 01:30:46 +0200
feat: apply findings from zlint
Diffstat:
6 files changed, 98 insertions(+), 93 deletions(-)
diff --git a/src/cfg.zig b/src/cfg.zig
@@ -51,7 +51,7 @@ pub fn loadConfig(allocator: std.mem.Allocator) ?std.json.Parsed(Config) {
const path = std.fs.path.join(allocator, &.{ home, ".config", "magdalena", "config.json" }) catch return null;
defer allocator.free(path);
- const content = std.Io.Dir.cwd().readFileAlloc(io.rt, path, allocator, .unlimited) catch return null;
+ const content = std.Io.Dir.cwd().readFileAlloc(io.rt(), path, allocator, .unlimited) catch return null;
defer allocator.free(content);
return std.json.parseFromSlice(Config, allocator, content, .{
diff --git a/src/db.zig b/src/db.zig
@@ -42,20 +42,20 @@ pub const Db = struct {
.files_path = files_path,
};
- std.Io.Dir.cwd().createDirPath(io.rt, base_path) catch |err| {
+ std.Io.Dir.cwd().createDirPath(io.rt(), base_path) catch |err| {
if (err != error.PathAlreadyExists) return err;
};
for (&[_][]const u8{ dirs_path, files_path }) |p| {
- var f = std.Io.Dir.cwd().openFile(io.rt, p, .{ .mode = .read_write }) catch |err| {
+ var f = std.Io.Dir.cwd().openFile(io.rt(), p, .{ .mode = .read_write }) catch |err| {
if (err == error.FileNotFound) {
- const created = try std.Io.Dir.cwd().createFile(io.rt, p, .{ .truncate = false });
- created.close(io.rt);
+ const created = try std.Io.Dir.cwd().createFile(io.rt(), p, .{ .truncate = false });
+ created.close(io.rt());
continue;
}
return err;
};
- f.close(io.rt);
+ f.close(io.rt());
}
return res;
@@ -68,7 +68,7 @@ pub const Db = struct {
}
pub fn recentDirs(self: *Db) !zul.Managed([]DirectoryEntry) {
- const content = std.Io.Dir.cwd().readFileAlloc(io.rt, self.dirs_path, self.allocator, .limited(64 * 1024 * 1024)) catch |err| {
+ const content = std.Io.Dir.cwd().readFileAlloc(io.rt(), self.dirs_path, self.allocator, .limited(64 * 1024 * 1024)) catch |err| {
if (err == error.FileNotFound) return zul.Managed([]DirectoryEntry).fromJson(try std.json.parseFromSlice([]DirectoryEntry, self.allocator, "[]", .{}));
return err;
};
@@ -88,7 +88,7 @@ pub const Db = struct {
}
pub fn recentFiles(self: *Db) !zul.Managed([]FileEntry) {
- const content = std.Io.Dir.cwd().readFileAlloc(io.rt, self.files_path, self.allocator, .limited(64 * 1024 * 1024)) catch |err| {
+ const content = std.Io.Dir.cwd().readFileAlloc(io.rt(), self.files_path, self.allocator, .limited(64 * 1024 * 1024)) catch |err| {
if (err == error.FileNotFound) return zul.Managed([]FileEntry).fromJson(try std.json.parseFromSlice([]FileEntry, self.allocator, "[]", .{}));
return err;
};
@@ -153,7 +153,7 @@ pub const Db = struct {
}
fn resolvePath(self: *Db, path: []const u8) ![]const u8 {
- return std.Io.Dir.cwd().realPathFileAlloc(io.rt, path, self.allocator) catch {
+ return std.Io.Dir.cwd().realPathFileAlloc(io.rt(), path, self.allocator) catch {
return try std.fs.path.resolve(self.allocator, &[_][]const u8{path});
};
}
@@ -162,21 +162,21 @@ pub const Db = struct {
const abs_path = try self.resolvePath(dir_path);
defer self.allocator.free(abs_path);
- const file = std.Io.Dir.cwd().openFile(io.rt, self.dirs_path, .{ .mode = .write_only }) catch |err| switch (err) {
- error.FileNotFound => try std.Io.Dir.cwd().createFile(io.rt, self.dirs_path, .{ .truncate = false }),
+ const file = std.Io.Dir.cwd().openFile(io.rt(), self.dirs_path, .{ .mode = .write_only }) catch |err| switch (err) {
+ error.FileNotFound => try std.Io.Dir.cwd().createFile(io.rt(), self.dirs_path, .{ .truncate = false }),
else => return err,
};
- defer file.close(io.rt);
+ defer file.close(io.rt());
- const now = zul.DateTime.now(io.rt);
+ const now = zul.DateTime.now(io.rt());
var ts_buf: [64]u8 = undefined;
var ts_writer = std.Io.Writer.fixed(&ts_buf);
try now.format(&ts_writer);
const ts = ts_buf[0..ts_writer.end];
var fbuf: [4096]u8 = undefined;
- var fw = file.writer(io.rt, &fbuf);
- try fw.seekTo(try file.length(io.rt));
+ var fw = file.writer(io.rt(), &fbuf);
+ try fw.seekTo(try file.length(io.rt()));
try fw.interface.print("{s}|{s}\n", .{ ts, abs_path });
try fw.interface.flush();
}
@@ -185,21 +185,21 @@ pub const Db = struct {
const abs_path = try self.resolvePath(file_path);
defer self.allocator.free(abs_path);
- const file = std.Io.Dir.cwd().openFile(io.rt, self.files_path, .{ .mode = .write_only }) catch |err| switch (err) {
- error.FileNotFound => try std.Io.Dir.cwd().createFile(io.rt, self.files_path, .{ .truncate = false }),
+ const file = std.Io.Dir.cwd().openFile(io.rt(), self.files_path, .{ .mode = .write_only }) catch |err| switch (err) {
+ error.FileNotFound => try std.Io.Dir.cwd().createFile(io.rt(), self.files_path, .{ .truncate = false }),
else => return err,
};
- defer file.close(io.rt);
+ defer file.close(io.rt());
- const now = zul.DateTime.now(io.rt);
+ const now = zul.DateTime.now(io.rt());
var ts_buf: [64]u8 = undefined;
var ts_writer = std.Io.Writer.fixed(&ts_buf);
try now.format(&ts_writer);
const ts = ts_buf[0..ts_writer.end];
var fbuf: [4096]u8 = undefined;
- var fw = file.writer(io.rt, &fbuf);
- try fw.seekTo(try file.length(io.rt));
+ var fw = file.writer(io.rt(), &fbuf);
+ try fw.seekTo(try file.length(io.rt()));
try fw.interface.print("{s}|{s}|{s}|{s}\n", .{ ts, file_type, action, abs_path });
try fw.interface.flush();
}
@@ -212,7 +212,7 @@ pub const Db = struct {
fn cleanupFile(self: *Db, path: []const u8, path_col_idx: usize) !void {
io.warn("Cleaning up {s}...\n", .{path});
- const content = try std.Io.Dir.cwd().readFileAlloc(io.rt, path, self.allocator, .limited(64 * 1024 * 1024));
+ const content = try std.Io.Dir.cwd().readFileAlloc(io.rt(), path, self.allocator, .limited(64 * 1024 * 1024));
defer self.allocator.free(content);
var seen = std.StringHashMap(void).init(self.allocator);
@@ -243,7 +243,7 @@ pub const Db = struct {
if (seen.contains(p)) continue;
- std.Io.Dir.cwd().access(io.rt, p, .{}) catch |err| {
+ std.Io.Dir.cwd().access(io.rt(), p, .{}) catch |err| {
if (err == error.FileNotFound) {
missing_entries += 1;
continue;
@@ -258,11 +258,11 @@ pub const Db = struct {
const duplicates = total_entries - lines.items.len - missing_entries;
io.warn(" Entries: {d} total, {d} unique, {d} missing, {d} duplicates removed\n", .{ total_entries, lines.items.len, missing_entries, duplicates });
- const write_file = try std.Io.Dir.cwd().createFile(io.rt, path, .{ .truncate = true });
- defer write_file.close(io.rt);
+ const write_file = try std.Io.Dir.cwd().createFile(io.rt(), path, .{ .truncate = true });
+ defer write_file.close(io.rt());
var write_buf: [4096]u8 = undefined;
- var writer = write_file.writer(io.rt, &write_buf);
+ var writer = write_file.writer(io.rt(), &write_buf);
var i: usize = lines.items.len;
while (i > 0) {
diff --git a/src/fzf.zig b/src/fzf.zig
@@ -26,32 +26,31 @@ fn gotoFile(allocator: std.mem.Allocator, db: ?*hist.Db, file_path: []const u8,
d.logFile(file_path, ext, action) catch |err| io.warn("failed to log file: {}\n", .{err});
}
- if (std.Io.Dir.openFileAbsolute(io.rt, "/dev/tty", .{ .mode = .read_write })) |tty| {
+ if (std.Io.Dir.openFileAbsolute(io.rt(), "/dev/tty", .{ .mode = .read_write })) |tty| {
if (std.c.dup2(tty.handle, std.posix.STDIN_FILENO) < 0) io.warn("failed to redirect stdin to tty\n", .{});
if (std.c.dup2(tty.handle, std.posix.STDOUT_FILENO) < 0) io.warn("failed to redirect stdout to tty\n", .{});
- tty.close(io.rt);
+ tty.close(io.rt());
} else |err| {
io.warn("failed to open /dev/tty: {}\n", .{err});
}
if (command) |cmd| {
- return std.process.replace(io.rt, .{ .argv = &.{ cmd, file_path } });
+ return std.process.replace(io.rt(), .{ .argv = &.{ cmd, file_path } });
}
const editor = config.editor orelse (io.getenv("EDITOR") orelse return error.EditorNotSet);
if (line) |l| {
const line_arg = try std.fmt.allocPrint(allocator, "+{s}", .{l});
- return std.process.replace(io.rt, .{ .argv = &.{ editor, line_arg, file_path } });
+ return std.process.replace(io.rt(), .{ .argv = &.{ editor, line_arg, file_path } });
}
- return std.process.replace(io.rt, .{ .argv = &.{ editor, file_path } });
+ return std.process.replace(io.rt(), .{ .argv = &.{ editor, file_path } });
}
const StdIo = std.process.SpawnOptions.StdIo;
const Fzf = struct {
- child: std.process.Child = undefined,
argv: [][]const u8,
allocator: std.mem.Allocator,
stdin: StdIo = .pipe,
@@ -80,8 +79,8 @@ const Fzf = struct {
};
}
- pub fn spawn(self: *Fzf) !void {
- self.child = try std.process.spawn(io.rt, .{
+ pub fn spawn(self: *Fzf) !std.process.Child {
+ return std.process.spawn(io.rt(), .{
.argv = self.argv,
.stdin = self.stdin,
.stdout = self.stdout,
@@ -110,21 +109,20 @@ fn shouldSkip(path: []const u8, ignored_patterns: []const []const u8) bool {
fn runFzfPicker(allocator: std.mem.Allocator, fzf_opts: []const []const u8, items: []const []const u8) ![]u8 {
var fzf = try Fzf.init(allocator, fzf_opts, &[_][]const u8{});
defer fzf.deinit();
- try fzf.spawn();
- const child = &fzf.child;
+ var child = try fzf.spawn();
if (child.stdin) |stdin| {
for (items) |item| {
- stdin.writeStreamingAll(io.rt, item) catch |err| {
+ stdin.writeStreamingAll(io.rt(), item) catch |err| {
if (err == error.BrokenPipe) break;
return err;
};
- stdin.writeStreamingAll(io.rt, "\n") catch |err| {
+ stdin.writeStreamingAll(io.rt(), "\n") catch |err| {
if (err == error.BrokenPipe) break;
return err;
};
}
- stdin.close(io.rt);
+ stdin.close(io.rt());
child.stdin = null;
}
@@ -133,11 +131,11 @@ fn runFzfPicker(allocator: std.mem.Allocator, fzf_opts: []const []const u8, item
if (child.stdout) |stdout| {
var buffer: [4096]u8 = undefined;
- var sr = stdout.reader(io.rt, &buffer);
+ var sr = stdout.reader(io.rt(), &buffer);
stdout_data = try sr.interface.allocRemaining(allocator, .unlimited);
}
- const term = try child.wait(io.rt);
+ const term = try child.wait(io.rt());
if (term != .exited or term.exited != 0) return error.UserAbort;
const selected = std.mem.trim(u8, stdout_data orelse "", " \n\r\t");
if (selected.len == 0) return error.UserAbort;
@@ -166,7 +164,7 @@ pub fn recentDir(allocator: std.mem.Allocator, db: *hist.Db, config: *const cfg.
const selected = try runFzfPicker(allocator, config.fzf_opts, items.items);
defer allocator.free(selected);
- std.Io.Dir.accessAbsolute(io.rt, selected, .{}) catch |err| {
+ std.Io.Dir.accessAbsolute(io.rt(), selected, .{}) catch |err| {
io.warn("Selected directory no longer exists: {s} ({})\n", .{ selected, err });
return error.UserAbort;
};
@@ -198,8 +196,8 @@ pub fn favorites(allocator: std.mem.Allocator, db: *hist.Db, config: *const cfg.
defer allocator.free(selected);
const is_dir = blk: {
- var dir = std.Io.Dir.openDirAbsolute(io.rt, selected, .{}) catch break :blk false;
- dir.close(io.rt);
+ var dir = std.Io.Dir.openDirAbsolute(io.rt(), selected, .{}) catch break :blk false;
+ dir.close(io.rt());
break :blk true;
};
@@ -254,7 +252,7 @@ pub fn recentFile(allocator: std.mem.Allocator, db: *hist.Db, config: *const cfg
const selected = try runFzfPicker(allocator, config.fzf_opts, items.items);
defer allocator.free(selected);
- try std.Io.Dir.accessAbsolute(io.rt, selected, .{});
+ try std.Io.Dir.accessAbsolute(io.rt(), selected, .{});
try gotoFile(allocator, db, selected, null, config);
}
@@ -294,19 +292,18 @@ pub fn grep(allocator: std.mem.Allocator, db: *hist.Db, config: *const cfg.Confi
fzf.stdout = .pipe;
fzf.stderr = .inherit;
- try fzf.spawn();
- const child = &fzf.child;
+ var child = try fzf.spawn();
var stdout_data: ?[]u8 = null;
defer if (stdout_data) |d| allocator.free(d);
if (child.stdout) |stdout| {
var buffer: [4096]u8 = undefined;
- var sr = stdout.reader(io.rt, &buffer);
+ var sr = stdout.reader(io.rt(), &buffer);
stdout_data = try sr.interface.allocRemaining(allocator, .unlimited);
}
- const term = try child.wait(io.rt);
+ const term = try child.wait(io.rt());
if (term != .exited or term.exited != 0) return error.UserAbort;
const selected = std.mem.trim(u8, stdout_data orelse "", " \n\r\t");
if (selected.len == 0) return error.UserAbort;
@@ -334,12 +331,12 @@ const Entry = struct {
fn getMaxDirMtime(ignored_patterns: []const []const u8, max_depth: usize) !i128 {
var max_mtime: i128 = 0;
- if (std.Io.Dir.cwd().statFile(io.rt, ".", .{})) |stat| {
+ if (std.Io.Dir.cwd().statFile(io.rt(), ".", .{})) |stat| {
max_mtime = stat.mtime.nanoseconds;
} else |_| {}
- var root = try std.Io.Dir.cwd().openDir(io.rt, ".", .{ .iterate = true });
- defer root.close(io.rt);
+ var root = try std.Io.Dir.cwd().openDir(io.rt(), ".", .{ .iterate = true });
+ defer root.close(io.rt());
try scanMaxMtime(&root, 0, max_depth, ignored_patterns, &max_mtime);
return max_mtime;
@@ -349,7 +346,7 @@ fn getMaxDirMtime(ignored_patterns: []const []const u8, max_depth: usize) !i128
// once by its own `defer` as the recursion unwinds.
fn scanMaxMtime(dir: *std.Io.Dir, depth: usize, max_depth: usize, ignored_patterns: []const []const u8, max_mtime: *i128) !void {
var it = dir.iterate();
- while (try it.next(io.rt)) |entry| {
+ while (try it.next(io.rt())) |entry| {
var skip = false;
for (ignored_patterns) |pattern| {
if (std.mem.eql(u8, entry.name, pattern)) {
@@ -361,7 +358,7 @@ fn scanMaxMtime(dir: *std.Io.Dir, depth: usize, max_depth: usize, ignored_patter
const is_dir = entry.kind == .directory;
if (is_dir or entry.kind == .sym_link) {
- const stat = dir.statFile(io.rt, entry.name, .{}) catch |err| {
+ const stat = dir.statFile(io.rt(), entry.name, .{}) catch |err| {
if (err != error.FileNotFound and err != error.AccessDenied) {
io.warn("failed to stat {s}: {}\n", .{ entry.name, err });
}
@@ -371,11 +368,11 @@ fn scanMaxMtime(dir: *std.Io.Dir, depth: usize, max_depth: usize, ignored_patter
if (stat.mtime.nanoseconds > max_mtime.*) max_mtime.* = stat.mtime.nanoseconds;
if (is_dir and depth + 1 < max_depth) {
- var sub_dir = dir.openDir(io.rt, entry.name, .{ .iterate = true }) catch |err| {
+ var sub_dir = dir.openDir(io.rt(), entry.name, .{ .iterate = true }) catch |err| {
io.warn("failed to open directory {s}: {}\n", .{ entry.name, err });
continue;
};
- defer sub_dir.close(io.rt);
+ defer sub_dir.close(io.rt());
try scanMaxMtime(&sub_dir, depth + 1, max_depth, ignored_patterns, max_mtime);
}
}
@@ -396,7 +393,7 @@ fn collectEntries(
entries: *std.ArrayListUnmanaged(Entry),
) !void {
var it = dir.iterate();
- while (try it.next(io.rt)) |entry| {
+ while (try it.next(io.rt())) |entry| {
const entry_path = if (prefix) |p|
try std.fs.path.join(allocator, &.{ p, entry.name })
else
@@ -406,7 +403,7 @@ fn collectEntries(
if (shouldSkip(entry_path, ignored_patterns)) continue;
if (entry.kind == kind or entry.kind == .sym_link) {
- if (dir.statFile(io.rt, entry.name, .{})) |stat| {
+ if (dir.statFile(io.rt(), entry.name, .{})) |stat| {
if (stat.kind == kind) {
try entries.append(allocator, .{
.path = try allocator.dupe(u8, entry_path),
@@ -421,11 +418,11 @@ fn collectEntries(
}
if (entry.kind == .directory and depth + 1 < max_depth) {
- var sub_dir = dir.openDir(io.rt, entry.name, .{ .iterate = true }) catch |err| {
+ var sub_dir = dir.openDir(io.rt(), entry.name, .{ .iterate = true }) catch |err| {
io.warn("failed to open directory {s}: {}\n", .{ entry.name, err });
continue;
};
- defer sub_dir.close(io.rt);
+ defer sub_dir.close(io.rt());
try collectEntries(allocator, &sub_dir, entry_path, depth + 1, max_depth, kind, ignored_patterns, entries);
}
}
@@ -455,7 +452,7 @@ fn runFzfWithWalker(allocator: std.mem.Allocator, db: *hist.Db, kind: std.Io.Fil
var cache_hit = false;
if (mc) |*m| {
const cwd = blk: {
- break :blk std.process.currentPathAlloc(io.rt, allocator) catch |err| {
+ break :blk std.process.currentPathAlloc(io.rt(), allocator) catch |err| {
io.warn("failed to get cwd for cache: {}\n", .{err});
break :blk null;
};
@@ -488,8 +485,8 @@ fn runFzfWithWalker(allocator: std.mem.Allocator, db: *hist.Db, kind: std.Io.Fil
}
if (!cache_hit) {
- var root = try std.Io.Dir.cwd().openDir(io.rt, ".", .{ .iterate = true });
- defer root.close(io.rt);
+ var root = try std.Io.Dir.cwd().openDir(io.rt(), ".", .{ .iterate = true });
+ defer root.close(io.rt());
try collectEntries(allocator, &root, null, 0, max_depth, kind, config.ignored_patterns, &entries);
if (mc) |*m| {
@@ -519,7 +516,7 @@ fn runFzfWithWalker(allocator: std.mem.Allocator, db: *hist.Db, kind: std.Io.Fil
const clean_path = if (std.mem.startsWith(u8, selected, "./")) selected[2..] else selected;
if (clean_path.len > 0) {
- std.Io.Dir.cwd().access(io.rt, clean_path, .{}) catch |err| {
+ std.Io.Dir.cwd().access(io.rt(), clean_path, .{}) catch |err| {
io.warn("Selected item no longer exists or is inaccessible: {s} ({})\n", .{ clean_path, err });
return error.UserAbort;
};
diff --git a/src/io.zig b/src/io.zig
@@ -1,13 +1,24 @@
const std = @import("std");
-// Process-wide handles, set once from `std.process.Init` in `main`. The app is
-// a short-lived single-threaded CLI, so threading these through every call site
-// would be pure noise; a couple of globals keep the IO surface small.
-pub var rt: std.Io = undefined;
-pub var env: *std.process.Environ.Map = undefined;
+// Process-wide handles, populated once from `std.process.Init` in `main`. The
+// app is a short-lived single-threaded CLI, so threading these through every
+// call site would be pure noise; ambient state keeps the IO surface small.
+// They are optionals (not `undefined`) so that any use before `init` is a
+// checked unwrap panic rather than undefined behavior.
+var rt_handle: ?std.Io = null;
+var env_map: ?*std.process.Environ.Map = null;
+
+pub fn init(io_handle: std.Io, environ: *std.process.Environ.Map) void {
+ rt_handle = io_handle;
+ env_map = environ;
+}
+
+pub fn rt() std.Io {
+ return rt_handle.?;
+}
pub fn getenv(key: []const u8) ?[]const u8 {
- return env.get(key);
+ return env_map.?.get(key);
}
pub const Writer = struct {
@@ -38,12 +49,12 @@ pub const Writer = struct {
};
pub fn getStdout(buf: []u8) Writer {
- return .{ .inner = std.Io.File.stdout().writerStreaming(rt, buf) };
+ return .{ .inner = std.Io.File.stdout().writerStreaming(rt(), buf) };
}
pub fn warn(comptime fmt: []const u8, args: anytype) void {
var buf: [4096]u8 = undefined;
- var writer = std.Io.File.stderr().writerStreaming(rt, &buf);
+ var writer = std.Io.File.stderr().writerStreaming(rt(), &buf);
writer.interface.print(fmt, args) catch |err| {
std.log.warn("failed to write to stderr: {}", .{err});
};
diff --git a/src/main.zig b/src/main.zig
@@ -13,8 +13,7 @@ test {
}
pub fn main(init: std.process.Init) void {
- io.rt = init.io;
- io.env = init.environ_map;
+ io.init(init.io, init.environ_map);
const allocator = init.gpa;
const args = cli.parseArgs(allocator, init.minimal.args) catch |err| {
@@ -36,7 +35,7 @@ pub fn main(init: std.process.Init) void {
var cwd_buf: [std.fs.max_path_bytes]u8 = undefined;
const cwd = blk: {
- const n = std.process.currentPath(io.rt, &cwd_buf) catch |err| {
+ const n = std.process.currentPath(io.rt(), &cwd_buf) catch |err| {
io.warn("failed to get cwd for folder overrides: {}\n", .{err});
break :blk "";
};
diff --git a/src/memcached.zig b/src/memcached.zig
@@ -4,15 +4,17 @@ const io = @import("io.zig");
pub const Memcached = struct {
allocator: std.mem.Allocator,
stream: std.Io.net.Stream,
- read_buf: [65536]u8 = undefined,
- write_buf: [4096]u8 = undefined,
- reader: std.Io.net.Stream.Reader = undefined,
- writer: std.Io.net.Stream.Writer = undefined,
- started: bool = false,
+ read_buf: [65536]u8 = @splat(0),
+ write_buf: [4096]u8 = @splat(0),
+ // `null` until first use; the Stream's buffered Reader/Writer hold pointers
+ // into this struct's own buffers, so they can only be created once the
+ // struct sits at its final address (i.e. after `init` returns by value).
+ reader: ?std.Io.net.Stream.Reader = null,
+ writer: ?std.Io.net.Stream.Writer = null,
pub fn init(allocator: std.mem.Allocator, host: []const u8, port: u16) !Memcached {
const address = try std.Io.net.IpAddress.parseIp4(host, port);
- const stream = try address.connect(io.rt, .{ .mode = .stream });
+ const stream = try address.connect(io.rt(), .{ .mode = .stream });
return .{
.allocator = allocator,
.stream = stream,
@@ -20,32 +22,28 @@ pub const Memcached = struct {
}
pub fn deinit(self: *Memcached) void {
- if (self.started) {
- self.writer.interface.flush() catch |err| {
+ if (self.writer) |*writer| {
+ writer.interface.flush() catch |err| {
io.warn("failed to flush memcached on deinit: {}\n", .{err});
};
}
- self.stream.close(io.rt);
+ self.stream.close(io.rt());
}
- // The Stream's buffered Reader/Writer hold pointers into this struct's own
- // buffers, so they must be initialized only once the struct sits at its
- // final address (i.e. after `init` returns by value).
fn ensureStarted(self: *Memcached) void {
- if (self.started) return;
- self.reader = self.stream.reader(io.rt, &self.read_buf);
- self.writer = self.stream.writer(io.rt, &self.write_buf);
- self.started = true;
+ if (self.reader != null) return;
+ self.reader = self.stream.reader(io.rt(), &self.read_buf);
+ self.writer = self.stream.writer(io.rt(), &self.write_buf);
}
fn r(self: *Memcached) *std.Io.Reader {
self.ensureStarted();
- return &self.reader.interface;
+ return &self.reader.?.interface;
}
fn w(self: *Memcached) *std.Io.Writer {
self.ensureStarted();
- return &self.writer.interface;
+ return &self.writer.?.interface;
}
fn flushWrite(self: *Memcached) !void {