aboutsummaryrefslogtreecommitdiffstats
path: root/nihil.posix/write_file.ccm
diff options
context:
space:
mode:
authorLexi Winter <lexi@le-fay.org>2025-06-29 19:19:23 +0100
committerLexi Winter <lexi@le-fay.org>2025-06-29 19:19:23 +0100
commita8b0ea58e60bb0326b7f7c8f3c736d89ce9ef1df (patch)
tree6dafcf2674780649dcdc2649855722357837a68e /nihil.posix/write_file.ccm
parent4fa6821e0645ff61a9380cd090abff472205c630 (diff)
downloadnihil-a8b0ea58e60bb0326b7f7c8f3c736d89ce9ef1df.tar.gz
nihil-a8b0ea58e60bb0326b7f7c8f3c736d89ce9ef1df.tar.bz2
wip macOS port
Diffstat (limited to 'nihil.posix/write_file.ccm')
-rw-r--r--nihil.posix/write_file.ccm82
1 files changed, 82 insertions, 0 deletions
diff --git a/nihil.posix/write_file.ccm b/nihil.posix/write_file.ccm
new file mode 100644
index 0000000..867e0db
--- /dev/null
+++ b/nihil.posix/write_file.ccm
@@ -0,0 +1,82 @@
+/*
+ * This source code is released into the public domain.
+ */
+
+module;
+
+#include <coroutine>
+#include <expected>
+#include <filesystem>
+#include <ranges>
+#include <system_error>
+#include <vector>
+
+#include <fcntl.h>
+#include <unistd.h>
+
+export module nihil.posix:write_file;
+
+import nihil.error;
+import nihil.guard;
+import nihil.monad;
+import :fd;
+import :open;
+import :rename;
+
+namespace nihil {
+
+/*
+ * Write the contents of a range to a file. Returns the number of bytes
+ * written.
+ */
+export [[nodiscard]]
+auto write_file(std::filesystem::path const &filename,
+ std::ranges::contiguous_range auto &&range,
+ int mode = 0777)
+ -> std::expected<std::size_t, error>
+{
+ auto file = co_await open(filename, O_CREAT|O_WRONLY, mode);
+ auto nbytes = co_await write(file, range);
+ co_return nbytes;
+}
+
+/*
+ * Utility wrapper for non-contiguous ranges.
+ */
+export [[nodiscard]]
+auto write_file(std::filesystem::path const &filename,
+ std::ranges::range auto &&range)
+ -> std::expected<std::size_t, error>
+requires(!std::ranges::contiguous_range<decltype(range)>)
+{
+ return write_file(filename, std::vector(std::from_range, range));
+}
+
+/*
+ * Write the contents of a range to a file safely. The data will be written
+ * to "<filename>.tmp", and if the write succeeds, the temporary file will be
+ * renamed to the target filename. If an error occurs, the target file will
+ * not be modified.
+ */
+export [[nodiscard]]
+auto safe_write_file(std::filesystem::path const &filename,
+ std::ranges::range auto &&range)
+ -> std::expected<void, error>
+{
+ auto tmpfile = filename;
+ tmpfile.remove_filename();
+ tmpfile /= (filename.filename().native() + ".tmp");
+
+ auto tmpfile_guard = guard([&tmpfile] {
+ ::unlink(tmpfile.c_str());
+ });
+
+ co_await write_file(tmpfile, range);
+ co_await nihil::rename(tmpfile, filename);
+
+ tmpfile_guard.release();
+ co_return {};
+}
+
+
+} // namespace nihil