Compare commits

..

No commits in common. "168d5375a44cb5a156b327670a6aee790ad18938" and "c45a270a0b01d9887992e31c644a641f96eba1a8" have entirely different histories.

7 changed files with 186 additions and 421 deletions

View File

@ -11,178 +11,89 @@ import coral.math;
import oar; import oar;
struct file_reader : public coral::file_reader {
enum class [[nodiscard]] close_result {
ok,
io_unavailable,
};
enum class [[nodiscard]] open_result {
ok,
io_unavailable,
access_denied,
not_found,
};
file_reader(coral::fs * fs) : rw_ops{nullptr} {
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");
if (this->rw_ops == nullptr) return open_result::not_found;
return open_result::ok;
}
coral::expected<coral::usize, coral::io_error> read(coral::slice<coral::u8> const & buffer) override {
if (!this->is_open()) return coral::io_error::unavailable;
coral::usize const bytes_read{::SDL_RWread(this->rw_ops, buffer.pointer, sizeof(uint8_t), buffer.length)};
if ((bytes_read == 0) && (::SDL_GetError() != nullptr)) return coral::io_error::unavailable;
return bytes_read;
}
coral::expected<coral::u64, coral::io_error> seek(coral::u64 offset) override {
if (!this->is_open()) 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)};
if (byte_position == -1) return coral::io_error::unavailable;
return static_cast<coral::u64>(byte_position);
}
coral::expected<coral::u64, coral::io_error> tell() override {
if (!this->is_open()) return coral::io_error::unavailable;
coral::i64 const byte_position{::SDL_RWseek(this->rw_ops, 0, RW_SEEK_SET)};
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 {
base_directory() : directory_path{} {
char * const path{::SDL_GetBasePath()};
if (path == nullptr) return;
coral::usize path_length{0};
while (path[path_length] != 0) path_length += 1;
if (path_length == 0) {
::SDL_free(path);
return;
}
this->directory_path = {path, path_length};
}
~base_directory() override {
::SDL_free(this->directory_path.begin());
}
void read_file(coral::path const & file_path, coral::callable<void(coral::file_reader &)> const & then) override {
if (this->directory_path.length == 0) return;
file_reader reader{this};
if (reader.open(file_path) != file_reader::open_result::ok) return;
then(reader);
if (reader.close() != file_reader::close_result::ok) return;
}
void write_file(coral::path const & file_path, coral::callable<void(coral::file_writer &)> const & then) override {
// Directory is read-only.
}
protected:
coral::slice<char> directory_path;
};
struct user_directory : public coral::fs {
user_directory(coral::path const & title) : directory_path{} {
char * const path{::SDL_GetPrefPath("ona", title.begin())};
if (path == nullptr) return;
coral::usize path_length{0};
while (path[path_length] != 0) path_length += 1;
if (path_length == 0) {
::SDL_free(path);
return;
}
this->directory_path = {path, path_length};
}
~user_directory() override {
::SDL_free(this->directory_path.begin());
}
void read_file(coral::path const & file_path, coral::callable<void(coral::file_reader &)> const & then) override {
if (this->directory_path.length == 0) return;
file_reader reader{this};
if (reader.open(file_path) != file_reader::open_result::ok) return;
then(reader);
if (reader.close() != file_reader::close_result::ok) return;
}
void write_file(coral::path const & file_path, coral::callable<void(coral::file_writer &)> const & then) override {
// Directory is read-only.
}
protected:
coral::slice<char> directory_path;
};
export namespace app { export namespace app {
struct directory : public coral::fs {
struct rules {
bool can_read;
bool can_write;
};
directory() : path_buffer{0} {}
void read_file(coral::path const & file_path,
coral::callable<void(coral::readable const &)> const & then) {
if (this->prefix_length == 0) return;
if (!this->access_rules.can_read) return;
::SDL_RWops * rw_ops{this->open_rw(file_path, {.can_read = true})};
if (rw_ops == nullptr) return;
then([rw_ops](coral::slice<uint8_t> const & buffer) -> size_t {
return ::SDL_RWread(rw_ops, buffer.pointer, sizeof(uint8_t), buffer.length);
});
::SDL_RWclose(rw_ops);
}
void target(coral::slice<char const> const & directory_path, rules const & access_rules) {
this->access_rules = access_rules;
this->prefix_length = coral::min(directory_path.length, path_max - 1);
{
coral::slice const path_buffer_slice{this->path_buffer};
coral::copy(path_buffer_slice.sliced(0, this->prefix_length),
directory_path.sliced(0, this->prefix_length).as_bytes());
coral::zero(path_buffer_slice.sliced(this->prefix_length, path_max - this->prefix_length));
}
}
void write_file(coral::path const & file_path,
coral::callable<void(coral::writable const &)> const & then) {
if (this->prefix_length == 0) return;
if (!this->access_rules.can_write) return;
::SDL_RWops * rw_ops{this->open_rw(file_path, {.can_write = true})};
if (rw_ops == nullptr) return;
then([rw_ops](coral::slice<uint8_t const> const & buffer) -> size_t {
return ::SDL_RWwrite(rw_ops, buffer.pointer, sizeof(uint8_t), buffer.length);
});
::SDL_RWclose(rw_ops);
}
private:
static constexpr coral::usize path_max = 4096;
rules access_rules;
coral::usize prefix_length;
coral::u8 path_buffer[path_max];
::SDL_RWops * open_rw(coral::path const & file_path, rules const & file_rules) {
coral::u8 * const path_begin{this->path_buffer + this->prefix_length};
coral::slice const path_remaining =
{path_begin, path_begin + (path_max - this->prefix_length) - 1};
if (path_remaining.length < file_path.byte_size()) return nullptr;
coral::copy(path_remaining, file_path.as_slice().as_bytes());
return ::SDL_RWFromFile(reinterpret_cast<char const *>(this->path_buffer), "r");
}
};
enum class log_level { enum class log_level {
notice, notice,
warning, warning,
@ -190,10 +101,48 @@ export namespace app {
}; };
struct system { struct system {
system(coral::path const & title) : res{&base, "base_directory.oar"}, user{title} {} system(coral::path const & title) : res_archive{} {
constexpr directory::rules read_only_rules = {.can_read = true};
coral::fs & base_fs() { {
return this->base; char * const path{::SDL_GetBasePath()};
if (path == nullptr) {
this->cwd_directory.target("./", read_only_rules);
} else {
coral::usize path_length{0};
while (path[path_length] != 0) path_length += 1;
if (path_length == 0) {
this->cwd_directory.target("./", read_only_rules);
} else {
this->cwd_directory.target({path, path_length}, read_only_rules);
}
}
::SDL_free(path);
}
{
char * const path{::SDL_GetPrefPath("ona", title.begin())};
if (path != nullptr) {
coral::usize path_length{0};
while (path[path_length] != 0) path_length += 1;
if (path_length != 0) this->cwd_directory.target({path, path_length}, {
.can_read = true,
});
}
::SDL_free(path);
}
}
coral::fs & cwd_fs() {
return this->cwd_directory;
} }
bool poll() { bool poll() {
@ -207,7 +156,7 @@ export namespace app {
} }
coral::fs & res_fs() { coral::fs & res_fs() {
return this->res; return this->res_archive;
} }
void log(app::log_level level, coral::slice<char const> const & message) { void log(app::log_level level, coral::slice<char const> const & message) {
@ -223,7 +172,7 @@ export namespace app {
} }
coral::fs & user_fs() { coral::fs & user_fs() {
return this->user; return this->user_directory;
} }
private: private:
@ -239,11 +188,11 @@ export namespace app {
} }
} allocator; } allocator;
base_directory base; oar::archive res_archive;
user_directory user; directory cwd_directory;
oar::archive res; directory user_directory;
}; };
struct graphics { struct graphics {

View File

@ -38,13 +38,13 @@ export namespace coral {
using u32 = uint32_t; using u32 = uint32_t;
using i32 = int32_t; using i32 = uint32_t;
usize const i32_max = 0xffffffff; usize const i32_max = 0xffffffff;
using u64 = uint64_t; using u64 = uint32_t;
using i64 = int64_t; using i64 = uint32_t;
using f32 = float; using f32 = float;
@ -450,13 +450,9 @@ export namespace coral {
unavailable, unavailable,
}; };
struct reader { using readable = callable<expected<usize, io_error>(slice<u8> const &)>;
virtual expected<usize, io_error> read(slice<u8> const & buffer) = 0;
};
struct writer { using writable = callable<expected<usize, io_error>(slice<u8 const> const &)>;
virtual expected<usize, io_error> write(slice<u8 const> const & buffer) = 0;
};
} }
// Input/output operations. // Input/output operations.
@ -537,28 +533,30 @@ export namespace coral {
* *Note*: if `buffer` has a length of `0`, no data will be streamed as there is nowhere to * *Note*: if `buffer` has a length of `0`, no data will be streamed as there is nowhere to
* temporarily place data during streaming. * temporarily place data during streaming.
*/ */
expected<usize, io_error> stream(writer & output, reader & input, slice<u8> const & buffer) { expected<usize, io_error> stream(writable const & output,
usize total_bytes_written = 0; readable const & input, slice<u8> const & buffer) {
expected bytes_read = input.read(buffer);
if (!bytes_read.is_ok()) return bytes_read.error(); usize written = 0;
expected maybe_read = input(buffer);
usize read = bytes_read.value(); if (!maybe_read.is_ok()) return maybe_read.error();
usize read = maybe_read.value();
while (read != 0) { while (read != 0) {
expected const bytes_written = output.write(buffer.sliced(0, read)); expected const maybe_written = output(buffer.sliced(0, read));
if (!bytes_written.is_ok()) return bytes_read.error(); if (!maybe_written.is_ok()) return maybe_read.error();
total_bytes_written += bytes_written.value(); written += maybe_written.value();
bytes_read = input.read(buffer); maybe_read = input(buffer);
if (!bytes_read.is_ok()) return bytes_read.error(); if (!maybe_read.is_ok()) return maybe_read.error();
read = bytes_read.value(); read = maybe_read.value();
} }
return total_bytes_written; return written;
} }
/** /**
@ -567,8 +565,8 @@ export namespace coral {
* The returned [expected] can be used to introspect if `output` encountered any issues during * The returned [expected] can be used to introspect if `output` encountered any issues during
* printing, otherwise it will contain the number of characters used to print `value` as text. * printing, otherwise it will contain the number of characters used to print `value` as text.
*/ */
expected<usize, io_error> print_unsigned(writer & output, u64 value) { expected<usize, io_error> print_unsigned(writable const & output, u64 value) {
if (value == 0) return output.write(slice{"0"}.as_bytes()); if (value == 0) return output(slice{"0"}.as_bytes());
u8 buffer[20]{0}; u8 buffer[20]{0};
usize buffer_count{0}; usize buffer_count{0};
@ -586,7 +584,7 @@ export namespace coral {
for (usize i = 0; i < half_buffer_count; i += 1) for (usize i = 0; i < half_buffer_count; i += 1)
swap(buffer[i], buffer[buffer_count - i - 1]); swap(buffer[i], buffer[buffer_count - i - 1]);
return output.write(slice{buffer, buffer_count}); return output(slice{buffer, buffer_count});
} }
/** /**

View File

@ -106,27 +106,18 @@ export namespace coral {
char buffer[max + 1]; char buffer[max + 1];
}; };
struct file_reader : public reader {
virtual expected<u64, io_error> seek(u64 offset) = 0;
virtual expected<u64, io_error> tell() = 0;
};
struct file_writer : public writer {};
/** /**
* Platform-generalized file system interface. * Platform-generalized file system interface.
*/ */
struct fs { struct fs {
virtual ~fs() {};
/** /**
* Attempts to read the file in the file system located at `file_path` relative, calling * Attempts to read the file in the file system located at `file_path` relative, calling
* `then` if it was successfully opened for reading. * `then` if it was successfully opened for reading.
* *
* Once `then` returns, access to the file is closed automatically. * Once `then` returns, access to the file is closed automatically.
*/ */
virtual void read_file(path const & file_path, callable<void(file_reader &)> const & then) = 0; virtual void read_file(path const & file_path,
callable<void(readable const &)> const & then) = 0;
/** /**
* Attempts to write the file in the file system located at `file_path` relative, calling * Attempts to write the file in the file system located at `file_path` relative, calling
@ -134,6 +125,7 @@ export namespace coral {
* *
* Once `then` returns, access to the file is closed automatically. * Once `then` returns, access to the file is closed automatically.
*/ */
virtual void write_file(path const & file_path, callable<void(file_writer &)> const & then) = 0; virtual void write_file(path const & file_path,
callable<void(writable const &)> const & then) = 0;
}; };
} }

View File

@ -200,20 +200,14 @@ export namespace coral {
/** /**
* Writable type for appending data to a [sequence] containing [u8] values. * Writable type for appending data to a [sequence] containing [u8] values.
*/ */
struct sequence_writer : public writer { struct sequence_writer : public writable {
sequence_writer(sequence<u8> * output_sequence) { sequence_writer(sequence<u8> * output_sequence) : writable{
this->output_sequence = output_sequence; [output_sequence](slice<u8 const> const & buffer) -> expected<usize, io_error> {
} switch (output_sequence->append(buffer)) {
case append_result::ok: return buffer.length;
expected<usize, io_error> write(slice<u8 const> const & buffer) { case append_result::out_of_memory: return io_error::unavailable;
switch (output_sequence->append(buffer)) { default: unreachable();
case append_result::ok: return buffer.length; }
case append_result::out_of_memory: return io_error::unavailable; }} {}
default: unreachable();
}
}
private:
sequence<u8> * output_sequence;
}; };
} }

View File

@ -69,8 +69,8 @@ export namespace kym {
return nil; return nil;
} }
coral::expected<coral::usize, coral::io_error> default_stringify(vm & owning_vm, void * userdata, coral::writer & output) { coral::expected<coral::usize, coral::io_error> default_stringify(vm & owning_vm, void * userdata, coral::writable const & output) {
return output.write(coral::slice{"[object]"}.as_bytes()); return output(coral::slice{"[object]"}.as_bytes());
} }
struct bound_object { struct bound_object {
@ -81,7 +81,7 @@ export namespace kym {
value(*call)(vm &, void *, coral::slice<value const> const &); value(*call)(vm &, void *, coral::slice<value const> const &);
coral::expected<coral::usize, coral::io_error>(*stringify)(vm &, void *, coral::writer &); coral::expected<coral::usize, coral::io_error>(*stringify)(vm &, void *, coral::writable const &);
} behavior; } behavior;
bound_object(vm * owning_vm) : userdata{nullptr}, owning_vm{owning_vm}, behavior{ bound_object(vm * owning_vm) : userdata{nullptr}, owning_vm{owning_vm}, behavior{
@ -98,7 +98,7 @@ export namespace kym {
return this->behavior.call(*this->owning_vm, this->userdata, arguments); return this->behavior.call(*this->owning_vm, this->userdata, arguments);
} }
coral::expected<coral::usize, coral::io_error> stringify(coral::writer & output) { coral::expected<coral::usize, coral::io_error> stringify(coral::writable const & output) {
return this->behavior.stringify(*this->owning_vm, this->userdata, output); return this->behavior.stringify(*this->owning_vm, this->userdata, output);
} }

View File

@ -3,200 +3,36 @@ export module oar;
import coral; import coral;
import coral.files; import coral.files;
constexpr coral::usize signature_length{4};
constexpr coral::usize signature_version_length{1};
constexpr coral::usize signature_identifier_length{signature_length - signature_version_length};
constexpr coral::u8 signature_magic[signature_length]{'o', 'a', 'r', 0};
struct header {
coral::u8 signature_magic[signature_length];
coral::u32 entry_count;
coral::u8 padding[504];
};
static_assert(sizeof(header) == 512);
struct entry {
coral::path path;
coral::u64 data_offset;
coral::u64 data_length;
coral::u8 padding[240];
};
static_assert(sizeof(entry) == 512);
export namespace oar { export namespace oar {
struct archive_file_reader : public coral::file_reader { constexpr coral::usize signature_length{4};
enum class [[nodiscard]] close_result {
ok,
};
enum class [[nodiscard]] open_result { constexpr coral::u8 signature_magic[signature_length]{'o', 'a', 'r', 0};
ok,
io_unavailable,
archive_invalid,
archive_unsupported,
not_found,
};
archive_file_reader(coral::file_reader * archive_reader) { struct entry {
this->archive_reader = archive_reader; coral::u8 signature_magic[signature_length];
this->data_offset = 0;
this->data_length = 0;
this->data_cursor = 0;
}
close_result close() { coral::path path;
return close_result::ok;
}
bool is_open() const {
return this->data_offset >= sizeof(header);
}
open_result open(coral::path const & file_path) {
if (this->is_open()) switch (this->close()) {
case close_result::ok: break;
default: coral::unreachable();
}
if (!this->archive_reader->seek(0).is_ok()) return open_result::io_unavailable;
constexpr coral::usize header_size = sizeof(header);
coral::u8 archive_header_buffer[header_size]{0};
{
coral::expected const read_bytes{archive_reader->read(archive_header_buffer)};
if ((!read_bytes.is_ok()) || (read_bytes.value() != header_size))
return open_result::archive_invalid;
}
header const * const archive_header{reinterpret_cast<header const *>(archive_header_buffer)};
if (!coral::equals(coral::slice{archive_header->signature_magic,
signature_identifier_length}, coral::slice{signature_magic,
signature_identifier_length})) return open_result::archive_invalid;
if (archive_header->signature_magic[signature_identifier_length] !=
signature_magic[signature_identifier_length]) return open_result::archive_unsupported;
// Read file table.
coral::u64 head{0};
coral::u64 tail{archive_header->entry_count - 1};
constexpr coral::usize entry_size{sizeof(entry)};
coral::u8 file_entry_buffer[entry_size]{0};
while (head <= tail) {
coral::u64 const midpoint{head + ((tail - head) / 2)};
if (!archive_reader->seek(header_size + (entry_size * midpoint)).is_ok())
return open_result::archive_invalid;
{
coral::expected const read_bytes{archive_reader->read(file_entry_buffer)};
if ((!read_bytes.is_ok()) || (read_bytes.value() != header_size))
return open_result::archive_invalid;
}
entry const * const archive_entry{reinterpret_cast<entry const *>(file_entry_buffer)};
coral::size const comparison{file_path.compare(archive_entry->path)};
if (comparison == 0) {
this->data_offset = archive_entry->data_offset;
this->data_length = archive_entry->data_length;
this->data_cursor = archive_entry->data_offset;
return open_result::ok;
}
if (comparison > 0) {
head = (midpoint + 1);
} else {
tail = (midpoint - 1);
}
}
return open_result::not_found;
}
coral::expected<coral::usize, coral::io_error> read(coral::slice<coral::u8> const & buffer) override {
if (!this->is_open()) return coral::io_error::unavailable;
if (this->archive_reader->seek(this->data_offset + this->data_cursor).is_ok())
return coral::io_error::unavailable;
coral::expected const bytes_read{this->archive_reader->read(buffer.sliced(0,
coral::min(buffer.length, static_cast<coral::usize>((
this->data_offset + this->data_length) - this->data_cursor))))};
if (!bytes_read.is_ok()) this->data_cursor += bytes_read.value();
return bytes_read;
}
coral::expected<coral::u64, coral::io_error> seek(coral::u64 offset) override {
if (!this->is_open()) return coral::io_error::unavailable;
return coral::io_error::unavailable;
}
coral::expected<coral::u64, coral::io_error> tell() override {
if (!this->is_open()) return coral::io_error::unavailable;
return this->data_cursor;
}
private:
coral::file_reader * archive_reader;
coral::u64 data_offset; coral::u64 data_offset;
coral::u64 data_length; coral::u64 data_length;
coral::u64 data_cursor; coral::u8 padding[244];
}; };
struct archive : public coral::fs { struct archive : public coral::fs {
archive(coral::fs * backing_fs, coral::path const & archive_path) { archive() {
this->backing_fs = backing_fs;
this->archive_path = archive_path;
} }
void read_file(coral::path const & file_path, void read_file(coral::path const & file_path,
coral::callable<void(coral::file_reader &)> const & then) override { coral::callable<void(coral::readable const &)> const & then) override {
if ((this->backing_fs == nullptr) || (this->archive_path.byte_size() == 0)) return;
this->backing_fs->read_file(this->archive_path, [&](coral::file_reader & archive_reader) {
archive_file_reader file_reader{&archive_reader};
if (file_reader.open(file_path) != archive_file_reader::open_result::ok) return;
then(file_reader);
if (file_reader.close() != archive_file_reader::close_result::ok) return;
});
} }
void write_file(coral::path const & file_path, void write_file(coral::path const & file_path,
coral::callable<void(coral::file_writer &)> const & then) override { coral::callable<void(coral::writable const &)> const & then) override {
// Read-only file system.
} }
private:
coral::fs * backing_fs;
coral::path archive_path;
}; };
} }
static_assert(sizeof(oar::entry) == 512);

View File

@ -15,7 +15,7 @@ extern "C" int main(int argc, char const * const * argv) {
constexpr coral::path config_path{"config.kym"}; constexpr coral::path config_path{"config.kym"};
bool is_config_loaded{false}; bool is_config_loaded{false};
system.res_fs().read_file(config_path, [&](coral::reader & file) { system.res_fs().read_file(config_path, [&](coral::readable const & file) {
coral::allocator * const allocator{&system.thread_safe_allocator()}; coral::allocator * const allocator{&system.thread_safe_allocator()};
kym::vm vm{allocator, [&system](coral::slice<char const> const & error_message) { kym::vm vm{allocator, [&system](coral::slice<char const> const & error_message) {
@ -29,13 +29,10 @@ extern "C" int main(int argc, char const * const * argv) {
} }
coral::stack<coral::u8> script_source{allocator}; coral::stack<coral::u8> script_source{allocator};
coral::u8 stream_buffer[1024]{0};
{ if (!coral::stream(coral::sequence_writer{&script_source}, file, stream_buffer).is_ok())
coral::u8 stream_buffer[1024]{0}; return;
coral::sequence_writer script_writer{&script_source};
if (!coral::stream(script_writer, file, stream_buffer).is_ok()) return;
}
vm.with_object(vm.compile(coral::slice{script_source.begin(), script_source.end()}.as_chars()), [&](kym::bound_object & script) { vm.with_object(vm.compile(coral::slice{script_source.begin(), script_source.end()}.as_chars()), [&](kym::bound_object & script) {
vm.with_object(script.call({}), [&](kym::bound_object & config) { vm.with_object(script.call({}), [&](kym::bound_object & config) {
@ -54,9 +51,8 @@ extern "C" int main(int argc, char const * const * argv) {
vm.with_object(config.get_field("title"), [&](kym::bound_object & title) { vm.with_object(config.get_field("title"), [&](kym::bound_object & title) {
coral::stack<coral::u8, 128> title_buffer{&system.thread_safe_allocator()}; coral::stack<coral::u8, 128> title_buffer{&system.thread_safe_allocator()};
coral::sequence_writer title_writer{&title_buffer};
if (!title.stringify(title_writer).is_ok()) { if (!title.stringify(coral::sequence_writer{&title_buffer}).is_ok()) {
system.log(app::log_level::error, system.log(app::log_level::error,
"failed to decode `title` property of config"); "failed to decode `title` property of config");
@ -75,10 +71,10 @@ extern "C" int main(int argc, char const * const * argv) {
{ {
coral::sequence_writer error_writer{&error_message}; coral::sequence_writer error_writer{&error_message};
if (!error_writer.write(coral::slice{"failed to load "}.as_bytes()).is_ok()) if (!error_writer(coral::slice{"failed to load "}.as_bytes()).is_ok())
return coral::u8_max; return coral::u8_max;
if (!error_writer.write(config_path.as_slice().as_bytes()).is_ok()) if (!error_writer(config_path.as_slice().as_bytes()).is_ok())
return coral::u8_max; return coral::u8_max;
} }