1const std = @import("../std.zig");
2const mem = std.mem;
3const fs = std.fs;
4const File = std.fs.File;
5
6pub const BufferedAtomicFile = struct {
7    atomic_file: fs.AtomicFile,
8    file_writer: File.Writer,
9    buffered_writer: BufferedWriter,
10    allocator: mem.Allocator,
11
12    pub const buffer_size = 4096;
13    pub const BufferedWriter = std.io.BufferedWriter(buffer_size, File.Writer);
14    pub const Writer = std.io.Writer(*BufferedWriter, BufferedWriter.Error, BufferedWriter.write);
15
16    /// TODO when https://github.com/ziglang/zig/issues/2761 is solved
17    /// this API will not need an allocator
18    pub fn create(
19        allocator: mem.Allocator,
20        dir: fs.Dir,
21        dest_path: []const u8,
22        atomic_file_options: fs.Dir.AtomicFileOptions,
23    ) !*BufferedAtomicFile {
24        var self = try allocator.create(BufferedAtomicFile);
25        self.* = BufferedAtomicFile{
26            .atomic_file = undefined,
27            .file_writer = undefined,
28            .buffered_writer = undefined,
29            .allocator = allocator,
30        };
31        errdefer allocator.destroy(self);
32
33        self.atomic_file = try dir.atomicFile(dest_path, atomic_file_options);
34        errdefer self.atomic_file.deinit();
35
36        self.file_writer = self.atomic_file.file.writer();
37        self.buffered_writer = .{ .unbuffered_writer = self.file_writer };
38        return self;
39    }
40
41    /// always call destroy, even after successful finish()
42    pub fn destroy(self: *BufferedAtomicFile) void {
43        self.atomic_file.deinit();
44        self.allocator.destroy(self);
45    }
46
47    pub fn finish(self: *BufferedAtomicFile) !void {
48        try self.buffered_writer.flush();
49        try self.atomic_file.finish();
50    }
51
52    pub fn writer(self: *BufferedAtomicFile) Writer {
53        return .{ .context = &self.buffered_writer };
54    }
55};
56