2023-02-19 16:50:29 +00:00
|
|
|
export module coral.files;
|
2023-02-19 02:02:51 +00:00
|
|
|
|
2023-02-19 16:50:29 +00:00
|
|
|
import coral;
|
2023-02-19 02:02:51 +00:00
|
|
|
|
2023-02-19 16:50:29 +00:00
|
|
|
export namespace coral {
|
2023-02-19 02:02:51 +00:00
|
|
|
/**
|
2023-02-26 01:16:53 +00:00
|
|
|
* Platform-generalized identifier for a resource in a [fs].
|
2023-02-19 02:02:51 +00:00
|
|
|
*/
|
|
|
|
struct path {
|
|
|
|
/**
|
|
|
|
* Maximum path length.
|
|
|
|
*/
|
|
|
|
static usize const max = u8_max;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Common path component separator.
|
|
|
|
*/
|
|
|
|
static char const seperator = '/';
|
|
|
|
|
2023-02-24 17:23:18 +00:00
|
|
|
constexpr path() {
|
2023-02-19 02:02:51 +00:00
|
|
|
this->buffer[max] = max;
|
|
|
|
}
|
|
|
|
|
2023-02-24 17:23:18 +00:00
|
|
|
template<usize text_size> constexpr path(char const(&text)[text_size]) {
|
2023-02-19 16:41:22 +00:00
|
|
|
static_assert(text_size <= max);
|
2023-02-19 15:48:29 +00:00
|
|
|
|
|
|
|
for (usize i = 0; i < text_size; i += 1) this->buffer[i] = text[i];
|
|
|
|
|
|
|
|
this->buffer[max] = max - text_size;
|
2023-02-19 14:14:43 +00:00
|
|
|
}
|
|
|
|
|
2023-02-19 17:43:09 +00:00
|
|
|
/**
|
|
|
|
* Returns a weak reference to the [path] as a [slice].
|
|
|
|
*/
|
|
|
|
constexpr slice<char const> as_slice() const {
|
|
|
|
return {this->buffer, this->byte_size()};
|
|
|
|
}
|
|
|
|
|
2023-02-19 02:02:51 +00:00
|
|
|
/**
|
|
|
|
* Returns the base pointer of the path name.
|
2023-02-19 14:24:17 +00:00
|
|
|
*
|
|
|
|
* *Note*: the returned buffer pointer is guaranteed to end with a zero terminator.
|
2023-02-19 02:02:51 +00:00
|
|
|
*/
|
|
|
|
char const * begin() const {
|
|
|
|
return reinterpret_cast<char const *>(this->buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the number of bytes composing the path.
|
|
|
|
*/
|
|
|
|
constexpr usize byte_size() const {
|
|
|
|
return max - this->buffer[max];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2023-02-24 17:23:18 +00:00
|
|
|
* Compares the path to `that`, returning the difference between the two paths or `0` if they are identical.
|
2023-02-19 02:02:51 +00:00
|
|
|
*/
|
|
|
|
constexpr size compare(path const & that) const {
|
2023-02-19 17:43:09 +00:00
|
|
|
return coral::compare(this->as_slice().as_bytes(), that.as_slice().as_bytes());
|
2023-02-19 02:02:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the tail pointer of the path name.
|
|
|
|
*/
|
|
|
|
char const * end() const {
|
2023-02-19 15:48:29 +00:00
|
|
|
return this->buffer + this->byte_size();
|
2023-02-19 02:02:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2023-02-24 17:23:18 +00:00
|
|
|
* Tests the path against `that` for equality, returning `true` if they are identical, otherwise `false`.
|
2023-02-19 02:02:51 +00:00
|
|
|
*/
|
|
|
|
constexpr bool equals(path const & that) const {
|
2023-02-19 17:43:09 +00:00
|
|
|
return coral::equals(this->as_slice().as_bytes(), that.as_slice().as_bytes());
|
2023-02-19 02:02:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the path hash code.
|
|
|
|
*
|
|
|
|
* *Note:* the returned hash code is not guaranteed to be unique.
|
|
|
|
*/
|
|
|
|
constexpr u64 hash() const {
|
2023-02-19 17:43:09 +00:00
|
|
|
return coral::hash(this->as_slice().as_bytes());
|
2023-02-19 02:02:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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.
|
2023-02-26 01:16:53 +00:00
|
|
|
*
|
|
|
|
* *Note:* should the new path exceed [max] bytes in size, an empty [path] is returned instead.
|
2023-02-19 02:02:51 +00:00
|
|
|
*/
|
|
|
|
constexpr path joined(slice<char const> 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:
|
2023-02-24 17:23:18 +00:00
|
|
|
char buffer[max + 1]{0};
|
2023-02-19 02:02:51 +00:00
|
|
|
};
|
|
|
|
|
2023-02-26 01:16:53 +00:00
|
|
|
/**
|
|
|
|
* [reader] that has a known range of data and may attempt to traverse it freely.
|
|
|
|
*/
|
2023-02-19 23:06:17 +00:00
|
|
|
struct file_reader : public reader {
|
2023-02-26 01:16:53 +00:00
|
|
|
/**
|
|
|
|
* Attempts to seek to the position in the file defined by `offset`, returning the literal absolute position
|
|
|
|
* that was actually sought to or a [io_error] if the operation failed for whatever reason.
|
|
|
|
*/
|
2023-02-19 23:06:17 +00:00
|
|
|
virtual expected<u64, io_error> seek(u64 offset) = 0;
|
|
|
|
|
2023-02-26 01:16:53 +00:00
|
|
|
/**
|
|
|
|
* Attempts to get the current cursor position in the file, returning the literal absolute position of it or a
|
|
|
|
* [io_error] if the operation failed for whatever reason.
|
|
|
|
*/
|
2023-02-19 23:06:17 +00:00
|
|
|
virtual expected<u64, io_error> tell() = 0;
|
|
|
|
};
|
|
|
|
|
2023-02-26 01:16:53 +00:00
|
|
|
/**
|
|
|
|
* [writer] that has a known range of data and may attempt to traverse it freely.
|
|
|
|
*/
|
2023-02-22 21:00:11 +00:00
|
|
|
struct file_writer : public writer {
|
2023-02-26 01:16:53 +00:00
|
|
|
/**
|
|
|
|
* Attempts to seek to the position in the file defined by `offset`, returning the literal absolute position
|
|
|
|
* that was actually sought to or a [io_error] if the operation failed for whatever reason.
|
|
|
|
*/
|
2023-02-26 00:32:57 +00:00
|
|
|
virtual expected<u64, io_error> seek(u64 offset) = 0;
|
2023-02-25 23:32:44 +00:00
|
|
|
|
2023-02-26 01:16:53 +00:00
|
|
|
/**
|
|
|
|
* Attempts to get the current cursor position in the file, returning the literal absolute position of it or a
|
|
|
|
* [io_error] if the operation failed for whatever reason.
|
|
|
|
*/
|
2023-02-26 00:32:57 +00:00
|
|
|
virtual expected<u64, io_error> tell() = 0;
|
2023-02-22 21:00:11 +00:00
|
|
|
};
|
2023-02-19 23:06:17 +00:00
|
|
|
|
2023-02-19 02:02:51 +00:00
|
|
|
/**
|
|
|
|
* Platform-generalized file system interface.
|
|
|
|
*/
|
|
|
|
struct fs {
|
2023-02-23 00:28:06 +00:00
|
|
|
/**
|
|
|
|
* Descriptor of the various rules that the file-system enforces over access to its files.
|
|
|
|
*/
|
|
|
|
struct access_rules {
|
|
|
|
bool can_read;
|
|
|
|
|
|
|
|
bool can_write;
|
|
|
|
};
|
|
|
|
|
2023-02-20 01:08:39 +00:00
|
|
|
virtual ~fs() {};
|
2023-02-20 01:00:14 +00:00
|
|
|
|
2023-02-24 17:23:18 +00:00
|
|
|
/**
|
2023-02-25 12:46:19 +00:00
|
|
|
* Attempts to read the files in `directory_path`, calling `apply` for each of the files encountered with the
|
2023-02-24 17:23:18 +00:00
|
|
|
* fully-qualified file path. If either no files are found or the file-system does not support the operation,
|
|
|
|
* `apply` is never caled.
|
|
|
|
*
|
|
|
|
* `false` may be returned inside of `apply` to halt the enumeration.
|
|
|
|
*/
|
2023-02-25 12:46:19 +00:00
|
|
|
virtual void enumerate_directory(path const & directory_path, closure<bool(path const &)> const & apply) {}
|
2023-02-24 17:23:18 +00:00
|
|
|
|
2023-02-23 00:28:06 +00:00
|
|
|
/**
|
|
|
|
* Queries the file-system for its global [access_rules], returning them.
|
|
|
|
*/
|
|
|
|
virtual access_rules query_access() = 0;
|
|
|
|
|
2023-02-19 02:02:51 +00:00
|
|
|
/**
|
2023-02-24 17:23:18 +00:00
|
|
|
* Attempts to read the file in `file_path`, calling `then` if it was successfully opened for reading.
|
2023-02-19 02:02:51 +00:00
|
|
|
*/
|
2023-02-24 17:23:18 +00:00
|
|
|
virtual void read_file(path const & file_path, closure<void(file_reader &)> const & then) {}
|
2023-02-19 02:02:51 +00:00
|
|
|
|
|
|
|
/**
|
2023-02-24 17:23:18 +00:00
|
|
|
* Attempts to write the file in the file system located at `file_path`, calling `then` if it was successfully
|
|
|
|
* opened for writing.
|
2023-02-19 02:02:51 +00:00
|
|
|
*/
|
2023-02-24 17:23:18 +00:00
|
|
|
virtual void write_file(path const & file_path, closure<void(file_writer &)> const & then) {}
|
2023-02-19 02:02:51 +00:00
|
|
|
};
|
|
|
|
}
|