ona/source/coral/files.cpp
kayomn bb9617994f
Some checks failed
continuous-integration/drone/push Build is failing
Replace coral::fs walker closure with coral::file_walker
2023-02-28 01:16:19 +00:00

194 lines
5.6 KiB
C++
Executable File

export module coral.files;
import coral;
export namespace coral {
/**
* Platform-generalized identifier for a resource in a [fs].
*/
struct path {
/**
* Maximum path length.
*/
static usize const max = u8_max;
/**
* Common path component separator.
*/
static char const seperator = '/';
constexpr path() {
this->buffer[max] = max;
}
template<usize text_size> constexpr path(char const(&text)[text_size]) {
static_assert(text_size <= max);
for (usize i = 0; i < text_size; i += 1) this->buffer[i] = text[i];
this->buffer[max] = max - text_size;
}
/**
* Returns a weak reference to the [path] as a [slice].
*/
constexpr slice<char const> as_slice() const {
return {this->buffer, this->byte_size()};
}
/**
* Returns the base pointer of the path name.
*
* *Note*: the returned buffer pointer is guaranteed to end with a zero terminator.
*/
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];
}
/**
* 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 coral::compare(this->as_slice().as_bytes(), that.as_slice().as_bytes());
}
/**
* Returns the tail pointer of the path name.
*/
char const * end() const {
return 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 coral::equals(this->as_slice().as_bytes(), that.as_slice().as_bytes());
}
/**
* Returns the path hash code.
*
* *Note:* the returned hash code is not guaranteed to be unique.
*/
constexpr u64 hash() const {
return coral::hash(this->as_slice().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.
*
* *Note:* should the new path exceed [max] bytes in size, an empty [path] is returned instead.
*/
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:
char buffer[max + 1]{0};
};
/**
* [reader] that has a known range of data and may attempt to traverse it freely.
*/
struct file_reader : public reader {
/**
* 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.
*/
virtual expected<u64, io_error> seek(u64 offset) = 0;
/**
* 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.
*/
virtual expected<u64, io_error> tell() = 0;
};
/**
* Enumerator a file tree recursively, returning the absolute path of each file within.
*/
struct file_walker {
virtual ~file_walker() {}
/**
* Returns `true` if there are paths pending enumeration, otherwise `false`.
*/
virtual bool has_next() = 0;
/**
* Attempts to enumerate over the next absolute [path] in the file tree, returning it or an [io_error] if the
* operation failed for whatever reason.
*/
virtual expected<path, io_error> next() = 0;
};
/**
* [writer] that has a known range of data and may attempt to traverse it freely.
*/
struct file_writer : public writer {
/**
* 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.
*/
virtual expected<u64, io_error> seek(u64 offset) = 0;
/**
* 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.
*/
virtual expected<u64, io_error> tell() = 0;
};
/**
* Platform-generalized file system interface.
*/
struct fs {
virtual ~fs() {};
/**
* Attempts to read the file in `target_path`, calling `then` if it was successfully opened for reading and
* passing the [file_reader] context along.
*
* See [file_reader] for more information on how to read from the file.
*/
virtual void read_file(path const & target_path, closure<void(file_reader &)> const & then) {}
/**
* Attempts to walk the file tree from `target_path`, calling `then` if it was successfully opened for walking
* and passing the [file_walker] context along.
*
* See [file_walker] for more information on how to traverse the file tree.
*/
virtual void walk_files(path const & target_path, closure<void(file_walker &)> const & then) {}
/**
* Attempts to write a file in the file system located at `target_path`, calling `then` if it was successfully
* created and / or opened for writing and passing the [file_writer] context along.
*
* See [file_writer] for more information on how to write to the file.
*
* *Note*: Any file already existing at `target_path` will be overwritten to create a new file for writing.
*/
virtual void write_file(path const & target_path, closure<void(file_writer &)> const & then) {}
};
}