Compare commits
2 Commits
685e09412b
...
cea0a4e0ed
Author | SHA1 | Date | |
---|---|---|---|
cea0a4e0ed | |||
37b2586eaa |
138
source/app.cpp
138
source/app.cpp
@ -11,90 +11,92 @@ import coral.math;
|
|||||||
|
|
||||||
import oar;
|
import oar;
|
||||||
|
|
||||||
struct file_reader : public coral::file_reader {
|
namespace app {
|
||||||
enum class [[nodiscard]] close_result {
|
struct file_reader : public coral::file_reader {
|
||||||
ok,
|
enum class [[nodiscard]] close_result {
|
||||||
io_unavailable,
|
ok,
|
||||||
};
|
io_unavailable,
|
||||||
|
};
|
||||||
|
|
||||||
enum class [[nodiscard]] open_result {
|
enum class [[nodiscard]] open_result {
|
||||||
ok,
|
ok,
|
||||||
io_unavailable,
|
io_unavailable,
|
||||||
access_denied,
|
access_denied,
|
||||||
not_found,
|
not_found,
|
||||||
};
|
};
|
||||||
|
|
||||||
file_reader(coral::fs * fs) : rw_ops{nullptr} {
|
file_reader(coral::fs * fs) : rw_ops{nullptr} {
|
||||||
this->fs = fs;
|
this->fs = fs;
|
||||||
}
|
|
||||||
|
|
||||||
close_result close() {
|
|
||||||
if (::SDL_RWclose(this->rw_ops) != 0) return close_result::io_unavailable;
|
|
||||||
|
|
||||||
this->rw_ops = nullptr;
|
|
||||||
|
|
||||||
return close_result::ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_open() const {
|
|
||||||
return this->rw_ops != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
open_result open(coral::path const & file_path) {
|
|
||||||
if (this->is_open()) switch (this->close()) {
|
|
||||||
case close_result::ok: break;
|
|
||||||
case close_result::io_unavailable: return open_result::io_unavailable;
|
|
||||||
default: coral::unreachable();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this->rw_ops = ::SDL_RWFromFile(reinterpret_cast<char const *>(this->path_buffer), "r");
|
close_result close() {
|
||||||
|
if (::SDL_RWclose(this->rw_ops) != 0) return close_result::io_unavailable;
|
||||||
|
|
||||||
if (this->rw_ops == nullptr) return open_result::not_found;
|
this->rw_ops = nullptr;
|
||||||
|
|
||||||
return open_result::ok;
|
return close_result::ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
coral::expected<coral::usize, coral::io_error> read(coral::slice<coral::u8> const & buffer) override {
|
bool is_open() const {
|
||||||
if (!this->is_open()) return coral::io_error::unavailable;
|
return this->rw_ops != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
coral::usize const bytes_read{::SDL_RWread(this->rw_ops, buffer.pointer, sizeof(uint8_t), buffer.length)};
|
open_result open(coral::path const & file_path) {
|
||||||
|
if (this->is_open()) switch (this->close()) {
|
||||||
|
case close_result::ok: break;
|
||||||
|
case close_result::io_unavailable: return open_result::io_unavailable;
|
||||||
|
default: coral::unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
if ((bytes_read == 0) && (::SDL_GetError() != nullptr)) return coral::io_error::unavailable;
|
this->rw_ops = ::SDL_RWFromFile(reinterpret_cast<char const *>(this->path_buffer), "r");
|
||||||
|
|
||||||
return bytes_read;
|
if (this->rw_ops == nullptr) return open_result::not_found;
|
||||||
}
|
|
||||||
|
|
||||||
coral::expected<coral::u64, coral::io_error> seek(coral::u64 offset) override {
|
return open_result::ok;
|
||||||
if (!this->is_open()) return coral::io_error::unavailable;
|
}
|
||||||
|
|
||||||
// TODO: Fix cast.
|
coral::expected<coral::usize, coral::io_error> read(coral::slice<coral::u8> const & buffer) override {
|
||||||
coral::i64 const byte_position{
|
if (!this->is_open()) return coral::io_error::unavailable;
|
||||||
::SDL_RWseek(this->rw_ops, static_cast<coral::i64>(offset), RW_SEEK_SET)};
|
|
||||||
|
|
||||||
if (byte_position == -1) return coral::io_error::unavailable;
|
coral::usize const bytes_read{::SDL_RWread(this->rw_ops, buffer.pointer, sizeof(uint8_t), buffer.length)};
|
||||||
|
|
||||||
return static_cast<coral::u64>(byte_position);
|
if ((bytes_read == 0) && (::SDL_GetError() != nullptr)) return coral::io_error::unavailable;
|
||||||
}
|
|
||||||
|
|
||||||
coral::expected<coral::u64, coral::io_error> tell() override {
|
return bytes_read;
|
||||||
if (!this->is_open()) return coral::io_error::unavailable;
|
}
|
||||||
|
|
||||||
coral::i64 const byte_position{::SDL_RWseek(this->rw_ops, 0, RW_SEEK_SET)};
|
coral::expected<coral::u64, coral::io_error> seek(coral::u64 offset) override {
|
||||||
|
if (!this->is_open()) return coral::io_error::unavailable;
|
||||||
|
|
||||||
if (byte_position == -1) return coral::io_error::unavailable;
|
// TODO: Fix cast.
|
||||||
|
coral::i64 const byte_position{
|
||||||
|
::SDL_RWseek(this->rw_ops, static_cast<coral::i64>(offset), RW_SEEK_SET)};
|
||||||
|
|
||||||
return static_cast<coral::u64>(byte_position);
|
if (byte_position == -1) return coral::io_error::unavailable;
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
return static_cast<coral::u64>(byte_position);
|
||||||
static constexpr coral::usize path_max{4096};
|
}
|
||||||
|
|
||||||
coral::u8 path_buffer[path_max];
|
coral::expected<coral::u64, coral::io_error> tell() override {
|
||||||
|
if (!this->is_open()) return coral::io_error::unavailable;
|
||||||
|
|
||||||
coral::fs * fs;
|
coral::i64 const byte_position{::SDL_RWseek(this->rw_ops, 0, RW_SEEK_SET)};
|
||||||
|
|
||||||
::SDL_RWops * rw_ops;
|
if (byte_position == -1) return coral::io_error::unavailable;
|
||||||
};
|
|
||||||
|
return static_cast<coral::u64>(byte_position);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static constexpr coral::usize path_max{4096};
|
||||||
|
|
||||||
|
coral::u8 path_buffer[path_max];
|
||||||
|
|
||||||
|
coral::fs * fs;
|
||||||
|
|
||||||
|
::SDL_RWops * rw_ops;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
struct base_directory : public coral::fs {
|
struct base_directory : public coral::fs {
|
||||||
base_directory() : directory_path{} {
|
base_directory() : directory_path{} {
|
||||||
@ -122,13 +124,13 @@ struct base_directory : public coral::fs {
|
|||||||
void read_file(coral::path const & file_path, coral::callable<void(coral::file_reader &)> const & then) override {
|
void read_file(coral::path const & file_path, coral::callable<void(coral::file_reader &)> const & then) override {
|
||||||
if (this->directory_path.length == 0) return;
|
if (this->directory_path.length == 0) return;
|
||||||
|
|
||||||
file_reader reader{this};
|
app::file_reader reader{this};
|
||||||
|
|
||||||
if (reader.open(file_path) != file_reader::open_result::ok) return;
|
if (reader.open(file_path) != app::file_reader::open_result::ok) return;
|
||||||
|
|
||||||
then(reader);
|
then(reader);
|
||||||
|
|
||||||
if (reader.close() != file_reader::close_result::ok) return;
|
if (reader.close() != app::file_reader::close_result::ok) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_file(coral::path const & file_path, coral::callable<void(coral::file_writer &)> const & then) override {
|
void write_file(coral::path const & file_path, coral::callable<void(coral::file_writer &)> const & then) override {
|
||||||
@ -165,13 +167,13 @@ struct user_directory : public coral::fs {
|
|||||||
void read_file(coral::path const & file_path, coral::callable<void(coral::file_reader &)> const & then) override {
|
void read_file(coral::path const & file_path, coral::callable<void(coral::file_reader &)> const & then) override {
|
||||||
if (this->directory_path.length == 0) return;
|
if (this->directory_path.length == 0) return;
|
||||||
|
|
||||||
file_reader reader{this};
|
app::file_reader reader{this};
|
||||||
|
|
||||||
if (reader.open(file_path) != file_reader::open_result::ok) return;
|
if (reader.open(file_path) != app::file_reader::open_result::ok) return;
|
||||||
|
|
||||||
then(reader);
|
then(reader);
|
||||||
|
|
||||||
if (reader.close() != file_reader::close_result::ok) return;
|
if (reader.close() != app::file_reader::close_result::ok) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_file(coral::path const & file_path, coral::callable<void(coral::file_writer &)> const & then) override {
|
void write_file(coral::path const & file_path, coral::callable<void(coral::file_writer &)> const & then) override {
|
||||||
|
115
source/coral.cpp
115
source/coral.cpp
@ -452,12 +452,34 @@ export namespace coral {
|
|||||||
unavailable,
|
unavailable,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Readable resource interface.
|
||||||
|
*/
|
||||||
struct reader {
|
struct reader {
|
||||||
virtual expected<usize, io_error> read(slice<u8> const & buffer) = 0;
|
virtual ~reader() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to fill `data` with whatever data the reader has to offer, returning the number
|
||||||
|
* of bytes actually read.
|
||||||
|
*
|
||||||
|
* Should the read operation fail for any reason, a [io_error] is returned instead.
|
||||||
|
*/
|
||||||
|
virtual expected<usize, io_error> read(slice<u8> const & data) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writable resource interface.
|
||||||
|
*/
|
||||||
struct writer {
|
struct writer {
|
||||||
virtual expected<usize, io_error> write(slice<u8 const> const & buffer) = 0;
|
virtual ~writer() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to write `data` out to the writer, returning the number of bytes actually
|
||||||
|
* written.
|
||||||
|
*
|
||||||
|
* Should the write operation fail for any reason, a [io_error] is returned instead.
|
||||||
|
*/
|
||||||
|
virtual expected<usize, io_error> write(slice<u8 const> const & data) = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -617,4 +639,93 @@ export namespace coral {
|
|||||||
|
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multiplexing byte buffer of `capacity` size that may be used for memory-backed I/O
|
||||||
|
* operations and lightweight data construction.
|
||||||
|
*/
|
||||||
|
template<usize capacity> struct ring_buffer : public writer, public reader {
|
||||||
|
ring_buffer(coral::u8 fill_value) : data{fill_value} {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the base pointer of the buffer data.
|
||||||
|
*/
|
||||||
|
u8 * begin() {
|
||||||
|
return this->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the base pointer of the buffer data.
|
||||||
|
*/
|
||||||
|
u8 const * begin() const {
|
||||||
|
return this->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the tail pointer of the buffer data.
|
||||||
|
*/
|
||||||
|
u8 * end() {
|
||||||
|
return this->data + this->cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the tail pointer of the buffer data.
|
||||||
|
*/
|
||||||
|
u8 const * end() const {
|
||||||
|
return this->data + this->cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns `true` if the buffer has been completely filled with data.
|
||||||
|
*/
|
||||||
|
bool is_full() const {
|
||||||
|
return this->filled == capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads whatever data is in the buffer into `data`, returning the number of bytes read
|
||||||
|
* from the buffer.
|
||||||
|
*/
|
||||||
|
expected<usize, io_error> read(slice<u8> const & data) override {
|
||||||
|
slice const readable_data{this->data, min(this->filled, data.length)};
|
||||||
|
|
||||||
|
this->filled -= readable_data.length;
|
||||||
|
|
||||||
|
for (usize index = 0; index < readable_data.length; index += 1) {
|
||||||
|
data[index] = this->data[this->read_index];
|
||||||
|
this->read_index = (this->read_index + 1) % capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
return readable_data.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to write `data` to the buffer, returning the number of bytes written or
|
||||||
|
* [io_error::unavailable] if it has been completely filled and no more bytes can be
|
||||||
|
* written.
|
||||||
|
*/
|
||||||
|
expected<usize, io_error> write(slice<u8 const> const & data) override {
|
||||||
|
if (this->is_full()) return io_error::unavailable;
|
||||||
|
|
||||||
|
slice const writable_data{data.sliced(0, min(data.length, this->filled))};
|
||||||
|
|
||||||
|
this->filled += writable_data.length;
|
||||||
|
|
||||||
|
for (usize index = 0; index < writable_data.length; index += 1) {
|
||||||
|
this->data[this->write_index] = data[index];
|
||||||
|
this->write_index = (this->write_index + 1) % capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
return writable_data.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
usize filled = 0;
|
||||||
|
|
||||||
|
usize read_index = 0;
|
||||||
|
|
||||||
|
usize write_index = 0;
|
||||||
|
|
||||||
|
u8 data[capacity];
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user