From 51b73aa823cb8c4fefaa8200fdfa27ee9b72725a Mon Sep 17 00:00:00 2001 From: kayomn Date: Sun, 19 Feb 2023 02:02:51 +0000 Subject: [PATCH] Add file system interfacing to core library --- source/core/files.cpp | 137 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 source/core/files.cpp diff --git a/source/core/files.cpp b/source/core/files.cpp new file mode 100644 index 0000000..c014fec --- /dev/null +++ b/source/core/files.cpp @@ -0,0 +1,137 @@ +export module core.files; + +import core; + +export namespace core { + /** + * Platform-generalized identifier for a resource in a [file_store]. + */ + struct path { + /** + * Maximum path length. + */ + static usize const max = u8_max; + + /** + * Common path component separator. + */ + static char const seperator = '/'; + + constexpr path() : buffer{0} { + this->buffer[max] = max; + } + + /** + * Returns the base pointer of the path name. + */ + char const * begin() const { + return reinterpret_cast(this->buffer); + } + + /** + * Returns the number of bytes composing the path. + */ + constexpr usize byte_size() const { + return max - this->buffer[max]; + } + + /** + * Compares the path to `that`, returning the difference between the two paths or `0` if + * they are identical. + */ + constexpr size compare(path const & that) const { + return core::compare(slice{this->begin(), this->end()}.as_bytes(), + slice{that.begin(), that.end()}.as_bytes()); + } + + /** + * Returns the tail pointer of the path name. + */ + char const * end() const { + return reinterpret_cast(this->buffer) + this->byte_size(); + } + + /** + * Tests the path against `that` for equality, returning `true` if they are identical, + * otherwise `false`. + */ + constexpr bool equals(path const & that) const { + return core::equals(slice{this->begin(), this->end()}.as_bytes(), + slice{that.begin(), that.end()}.as_bytes()); + } + + /** + * Returns the path hash code. + * + * *Note:* the returned hash code is not guaranteed to be unique. + */ + constexpr u64 hash() const { + return core::hash(slice{this->begin(), this->end()}.as_bytes()); + } + + /** + * Returns a new [path] composed of the current path joined with `text`. + * + * *Note:* should the new path exceed [max] bytes in size, an empty [path] is returned instead. + */ + constexpr path joined(slice const & text) const { + if (text.length > this->buffer[max]) return path{}; + + path joined_path = *this; + + for (char const c : text) { + joined_path.buffer[joined_path.byte_size()] = c; + joined_path.buffer[max] -= 1; + } + + return joined_path; + } + + private: + u8 buffer[max + 1]; + }; + + /** + * Platform-generalized file system interface. + */ + struct fs { + /** + * The result from a file access operation. + * + * [file_result::ok] indicates a successful file access operation. + * + * [file_result::not_found] signals that the file was not found. + * + * [file_result::access_denied] warns that the file was found but cannot be opened through + * the file system interface. The most common scenario for this error is a lack of required + * file permissions. + */ + enum class [[nodiscard]] access_result { + ok, + not_found, + access_denied, + }; + + /** + * Attempts to read the file in the file system located at `file_path` relative, calling + * `then` if it was successfully opened for reading. + * + * The returned [access_result] indicates whether the operation was successful or not. + * + * Once `then` returns, access to the file is closed automatically. + */ + virtual access_result read_file(path const & file_path, + callable const & then) = 0; + + /** + * Attempts to write the file in the file system located at `file_path` relative, calling + * `then` if it was successfully opened for writing. + * + * The returned [access_result] indicates whether the operation was successful or not. + * + * Once `then` returns, access to the file is closed automatically. + */ + virtual access_result write_file(path const & file_path, + callable const & then) = 0; + }; +}