[olympic] Move keel, turbine, and studio to olympic

This commit is contained in:
2023-12-11 22:48:08 -06:00
parent a60765b338
commit e2545a956b
96 changed files with 32 additions and 24 deletions

View File

@@ -0,0 +1,45 @@
/*
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include <ox/claw/claw.hpp>
#include <ox/fs/fs.hpp>
namespace keel {
constexpr auto K1HdrSz = 40;
ox::Result<ox::UUID> readUuidHeader(const ox::Buffer &buff) noexcept;
ox::Result<ox::UUID> readUuidHeader(const char *buff, std::size_t buffLen) noexcept;
ox::Error writeUuidHeader(ox::Writer_c auto &writer, const ox::UUID &uuid) noexcept {
oxReturnError(write(writer, "K1;"));
oxReturnError(uuid.toString(writer));
return writer.put(';');
}
template<typename T>
ox::Result<T> readAsset(const ox::Buffer &buff) noexcept {
std::size_t offset = 0;
const auto err = readUuidHeader(buff).error;
if (!err) {
offset = K1HdrSz; // the size of K1 headers
}
return ox::readClaw<T>(buff.data() + offset, buff.size() - offset);
}
ox::Result<ox::ModelObject> readAsset(ox::TypeStore *ts, const ox::Buffer &buff) noexcept;
struct AssetHdr {
ox::UUID uuid;
ox::ClawHeader clawHdr;
};
ox::Result<AssetHdr> readAssetHeader(const char *buff, std::size_t buffLen) noexcept;
ox::Result<AssetHdr> readAssetHeader(const ox::Buffer &buff) noexcept;
}

View File

@@ -0,0 +1,298 @@
/*
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include <ox/event/signal.hpp>
#include <ox/fs/fs.hpp>
#include <ox/model/typenamecatcher.hpp>
#include <ox/std/hashmap.hpp>
#include <ox/std/utility.hpp>
namespace keel {
class AssetManager;
template<typename T>
class AssetRef;
#ifndef OX_BARE_METAL
template<typename T>
class AssetContainer {
friend AssetManager;
friend AssetRef<T>;
protected:
ox::Signal<ox::Error()> updated;
private:
T m_obj;
mutable int m_references = 0;
public:
template<class... Args>
explicit constexpr AssetContainer(Args&&... args): m_obj(ox::forward<Args>(args)...) {
}
AssetContainer(AssetContainer const&) = delete;
AssetContainer(AssetContainer&&) = delete;
AssetContainer &operator=(AssetContainer const&) = delete;
AssetContainer &operator=(AssetContainer&&) = delete;
[[nodiscard]]
constexpr T *get() noexcept {
return &m_obj;
}
[[nodiscard]]
constexpr const T *get() const noexcept {
return &m_obj;
}
constexpr void set(T &&val) {
m_obj = std::move(val);
}
constexpr void set(T const&val) {
m_obj = val;
}
protected:
constexpr void incRefs() const noexcept {
++m_references;
}
constexpr void decRefs() const noexcept {
--m_references;
}
[[nodiscard]]
constexpr int references() const noexcept {
return m_references;
}
};
template<typename T>
class AssetRef: public ox::SignalHandler {
private:
const AssetContainer<T> *m_ctr = nullptr;
public:
ox::Signal<ox::Error()> updated;
explicit constexpr AssetRef(const AssetContainer<T> *c = nullptr) noexcept;
constexpr AssetRef(AssetRef const&h) noexcept;
constexpr AssetRef(AssetRef &&h) noexcept;
~AssetRef() noexcept override {
if (m_ctr) {
m_ctr->decRefs();
}
}
[[nodiscard]]
constexpr const T *get() const noexcept {
if (m_ctr) {
return m_ctr->get();
}
return nullptr;
}
constexpr const T &operator*() const noexcept {
return *m_ctr->get();
}
constexpr const T *operator->() const noexcept {
return m_ctr->get();
}
AssetRef &operator=(AssetRef const&h) noexcept {
if (this == &h) {
return *this;
}
if (m_ctr) {
m_ctr->decRefs();
oxIgnoreError(m_ctr->updated.disconnectObject(this));
}
m_ctr = h.m_ctr;
m_ctr->updated.connect(&updated, &ox::Signal<ox::Error()>::emitCheckError);
if (m_ctr) {
m_ctr->incRefs();
}
return *this;
}
AssetRef &operator=(AssetRef &&h) noexcept {
if (this == &h) {
return *this;
}
if (m_ctr) {
m_ctr->decRefs();
oxIgnoreError(m_ctr->updated.disconnectObject(this));
}
m_ctr = h.m_ctr;
m_ctr->updated.connect(this, &AssetRef::emitUpdated);
h.m_ctr = nullptr;
return *this;
}
explicit constexpr operator bool() const noexcept {
return m_ctr;
}
private:
constexpr ox::Error emitUpdated() const noexcept {
updated.emit();
return OxError(0);
}
};
template<typename T>
constexpr AssetRef<T>::AssetRef(const AssetContainer<T> *c) noexcept: m_ctr(c) {
if (c) {
c->updated.connect(this, &AssetRef::emitUpdated);
}
}
template<typename T>
constexpr AssetRef<T>::AssetRef(AssetRef const&h) noexcept {
m_ctr = h.m_ctr;
if (m_ctr) {
m_ctr->updated.connect(this, &AssetRef::emitUpdated);
m_ctr->incRefs();
}
}
template<typename T>
constexpr AssetRef<T>::AssetRef(AssetRef &&h) noexcept {
m_ctr = h.m_ctr;
m_ctr->updated.connect(this, &AssetRef::emitUpdated);
h.m_ctr = nullptr;
}
class AssetManager {
private:
class AssetTypeManagerBase {
public:
virtual ~AssetTypeManagerBase() = default;
virtual void gc() noexcept = 0;
};
template<typename T>
class AssetTypeManager: public AssetTypeManagerBase {
private:
ox::HashMap<ox::String, ox::UPtr<AssetContainer<T>>> m_cache;
public:
ox::Result<AssetRef<T>> getAsset(ox::StringView const&assetId) const noexcept {
auto out = m_cache.at(assetId);
oxReturnError(out);
return AssetRef<T>(out.value->get());
}
ox::Result<AssetRef<T>> setAsset(ox::StringView const&assetId, T const&obj) noexcept {
auto &p = m_cache[assetId];
if (!p) {
p = ox::make_unique<AssetContainer<T>>(obj);
} else {
p->set(obj);
p->updated.emit();
}
return AssetRef<T>(p.get());
}
ox::Result<AssetRef<T>> setAsset(ox::StringView const&assetId, T &&obj) noexcept {
auto &p = m_cache[assetId];
if (!p) {
p = ox::make_unique<AssetContainer<T>>(obj);
} else {
p->set(std::move(obj));
p->updated.emit();
}
return AssetRef<T>(p.get());
}
void gc() noexcept final {
for (const auto &ack : m_cache.keys()) {
auto &ac = m_cache[ack];
if (!ac->references()) {
m_cache.erase(ack);
}
}
}
};
ox::HashMap<ox::String, ox::UPtr<AssetTypeManagerBase>> m_assetTypeManagers;
template<typename T>
AssetTypeManager<T> *getTypeManager() noexcept {
constexpr auto typeName = ox::requireModelTypeName<T>();
static_assert(ox::StringView(typeName) != "", "Types must have TypeName to use AssetManager");
auto &am = m_assetTypeManagers[typeName];
if (!am) {
am = ox::make_unique<AssetTypeManager<T>>();
}
return dynamic_cast<AssetTypeManager<T>*>(am.get());
}
public:
template<typename T>
ox::Result<AssetRef<T>> getAsset(ox::CRStringView assetId) noexcept {
auto m = getTypeManager<T>();
return m->getAsset(assetId);
}
template<typename T>
ox::Result<AssetRef<T>> setAsset(ox::CRStringView assetId, const T &obj) noexcept {
auto m = getTypeManager<T>();
return m->setAsset(assetId, obj);
}
void gc() noexcept {
for (auto const&amk : m_assetTypeManagers.keys()) {
auto &am = m_assetTypeManagers[amk];
am->gc();
}
}
};
#else
template<typename T>
class AssetRef {
private:
const T *const m_obj = nullptr;
public:
constexpr AssetRef() noexcept = default;
explicit constexpr AssetRef(const T *obj) noexcept: m_obj(obj) {
}
constexpr const T *get() const noexcept {
return m_obj;
}
constexpr const T &operator*() const & noexcept {
return *m_obj;
}
constexpr const T &&operator*() const && noexcept {
return *m_obj;
}
constexpr const T *operator->() const noexcept {
return m_obj;
}
explicit constexpr operator bool() const noexcept {
return m_obj;
}
};
#endif
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include <ox/fs/fs.hpp>
#include <ox/std/memory.hpp>
#include "assetmanager.hpp"
namespace keel {
class Context;
using PackTransform = ox::Error(*)(Context&, ox::Buffer &clawData);
class Context {
public:
ox::UPtr<ox::FileSystem> rom;
ox::BasicString<32> appName{"Keel App"};
#ifndef OX_BARE_METAL
AssetManager assetManager;
ox::HashMap<ox::String, ox::UUID> pathToUuid;
ox::HashMap<ox::UUIDStr, ox::String> uuidToPath;
ox::Vector<const class BaseConverter*> converters;
ox::Vector<PackTransform> packTransforms;
#else
std::size_t preloadSectionOffset = 0;
#endif
constexpr Context() noexcept = default;
Context(Context const&) noexcept = delete;
Context(Context&&) noexcept = delete;
Context &operator=(Context const&) noexcept = delete;
Context &operator=(Context&&) noexcept = delete;
constexpr virtual ~Context() noexcept = default;
};
}

View File

@@ -0,0 +1,26 @@
/*
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include <ox/std/memory.hpp>
#include "context.hpp"
#include "media.hpp"
#include "module.hpp"
#include "pack.hpp"
#include "typestore.hpp"
namespace keel {
ox::Error init(
keel::Context &ctx,
ox::UPtr<ox::FileSystem> &&fs,
ox::CRStringView appName) noexcept;
ox::Result<ox::UPtr<Context>> init(
ox::UPtr<ox::FileSystem> &&fs,
ox::CRStringView appName) noexcept;
}

View File

@@ -0,0 +1,169 @@
/*
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include <ox/std/defines.hpp>
#include <ox/claw/claw.hpp>
#include <ox/fs/fs.hpp>
#include <ox/model/metadata.hpp>
#include "asset.hpp"
#include "context.hpp"
#include "typeconv.hpp"
namespace keel {
// Pointer to preloaded data that can be stored in FS in place of the actual
// data.
struct PreloadPtr {
static constexpr auto TypeName = "net.drinkingtea.keel.PreloadPtr";
static constexpr auto TypeVersion = 2;
uint64_t preloadAddr = 0;
};
oxModelBegin(PreloadPtr)
oxModelField(preloadAddr)
oxModelEnd()
ox::Result<std::size_t> getPreloadAddr(keel::Context &ctx, ox::FileAddress const&file) noexcept;
ox::Result<std::size_t> getPreloadAddr(keel::Context &ctx, ox::CRStringView file) noexcept;
#ifndef OX_BARE_METAL
template<typename T>
ox::Result<keel::AssetRef<T>> readObjFile(
keel::Context &ctx,
ox::StringView assetId,
bool forceLoad) noexcept {
constexpr auto readConvert = [](Context &ctx, const ox::Buffer &buff) -> ox::Result<T> {
auto [obj, err] = readAsset<T>(buff);
if (err) {
if (err != ox::Error_ClawTypeVersionMismatch && err != ox::Error_ClawTypeMismatch) {
return err;
}
oxReturnError(convert<T>(ctx, buff, &obj));
}
return std::move(obj);
};
ox::StringView path;
if (beginsWith(assetId, "uuid://")) {
assetId = substr(assetId, 7);
oxRequire(p, ctx.uuidToPath.at(assetId));
path = *p;
} else {
path = assetId;
}
if (forceLoad) {
oxRequire(buff, ctx.rom->read(path));
oxRequire(obj, readConvert(ctx, buff));
oxRequire(cached, ctx.assetManager.setAsset(assetId, obj));
return cached;
} else {
auto [cached, err] = ctx.assetManager.getAsset<T>(assetId);
if (err) {
oxRequire(buff, ctx.rom->read(path));
oxRequire(obj, readConvert(ctx, buff));
oxReturnError(ctx.assetManager.setAsset(assetId, obj).moveTo(&cached));
}
return cached;
}
}
#else
template<typename T>
ox::Result<keel::AssetRef<T>> readObjNoCache(
keel::Context &ctx,
ox::CRStringView assetId) noexcept {
if constexpr(ox::preloadable<T>::value) {
oxRequire(addr, getPreloadAddr(ctx, assetId));
return keel::AssetRef<T>(reinterpret_cast<const T*>(addr));
} else {
return OxError(1);
}
}
#endif
void createUuidMapping(Context &ctx, ox::StringView filePath, ox::UUID const&uuid) noexcept;
ox::Error buildUuidMap(Context &ctx) noexcept;
ox::Result<ox::String> uuidToPath(Context &ctx, ox::CRStringView uuid) noexcept;
ox::Result<ox::String> uuidToPath(Context &ctx, ox::UUID const&uuid) noexcept;
ox::Error performPackTransforms(Context &ctx, ox::Buffer &clawData) noexcept;
template<typename T>
ox::Result<AssetRef<T>> setAsset(keel::Context &ctx, ox::StringView assetId, T const&asset) noexcept {
#ifndef OX_BARE_METAL
if (assetId.len() == 0) {
return OxError(1, "Invalid asset ID");
}
ox::UUIDStr idStr;
if (assetId[0] == '/') {
const auto [id, err] = ctx.pathToUuid.at(assetId);
oxReturnError(err);
idStr = id->toString();
assetId = idStr;
}
return ctx.assetManager.setAsset(assetId, asset);
#else
return OxError(1, "Not supported on this platform");
#endif
}
template<typename T>
ox::Result<keel::AssetRef<T>> readObj(
keel::Context &ctx,
ox::CRStringView assetId,
[[maybe_unused]] bool forceLoad = false) noexcept {
#ifndef OX_BARE_METAL
return readObjFile<T>(ctx, assetId, forceLoad);
#else
return readObjNoCache<T>(ctx, assetId);
#endif
}
template<typename T>
ox::Result<keel::AssetRef<T>> readObj(
keel::Context &ctx,
ox::FileAddress const&file,
[[maybe_unused]] bool forceLoad = false) noexcept {
#ifndef OX_BARE_METAL
oxRequire(assetId, file.getPath());
return readObj<T>(ctx, ox::StringView(assetId), forceLoad);
#else
if constexpr(ox::preloadable<T>::value) {
oxRequire(addr, getPreloadAddr(ctx, file));
return keel::AssetRef<T>(reinterpret_cast<const T*>(addr));
} else {
return OxError(1);
}
#endif
}
template<typename T>
ox::Error writeObj(
keel::Context &ctx,
ox::FileAddress const&file,
T const&obj,
ox::ClawFormat fmt = ox::ClawFormat::Metal) noexcept {
oxRequire(objBuff, ox::writeClaw(obj, fmt));
return ctx.rom->write(file, objBuff.data(), objBuff.size());
}
ox::Error setRomFs(Context &ctx, ox::UPtr<ox::FileSystem> &&fs) noexcept;
ox::Result<ox::UniquePtr<ox::FileSystem>> loadRomFs(ox::CRStringView path) noexcept;
ox::Result<char*> loadRom(ox::CRStringView path = "") noexcept;
void unloadRom(char*) noexcept;
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include <ox/std/vector.hpp>
#include <ox/model/descwrite.hpp>
#include "typeconv.hpp"
namespace keel {
using TypeDescGenerator = ox::Error(*)(ox::TypeStore&);
template<typename T>
ox::Error generateTypeDesc(ox::TypeStore &ts) noexcept {
return ox::buildTypeDef<T>(&ts).error;
}
class Module {
public:
constexpr Module() noexcept = default;
Module(Module const&) noexcept = delete;
Module(Module&&) noexcept = delete;
Module &operator=(Module const&) noexcept = delete;
Module &operator=(Module&&) noexcept = delete;
constexpr virtual ~Module() noexcept = default;
[[nodiscard]]
virtual ox::String id() const noexcept = 0;
[[nodiscard]]
virtual ox::Vector<TypeDescGenerator> types() const noexcept;
[[nodiscard]]
virtual ox::Vector<const keel::BaseConverter*> converters() const noexcept;
[[nodiscard]]
virtual ox::Vector<PackTransform> packTransforms() const noexcept;
};
void registerModule(const Module *mod) noexcept;
[[nodiscard]]
ox::Vector<const keel::Module*> const&modules() noexcept;
}

View File

@@ -0,0 +1,166 @@
/*
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include <ox/fs/fs.hpp>
#include <ox/preloader/preloader.hpp>
#include "asset.hpp"
#include "media.hpp"
namespace keel {
class Context;
struct GbaPlatSpec {
using PtrType = uint32_t;
using size_t = uint32_t;
static constexpr PtrType RomStart = 0x08000000;
[[nodiscard]]
static constexpr std::size_t alignOf(const bool) noexcept {
return 1;
}
[[nodiscard]]
static constexpr std::size_t alignOf(const uint8_t) noexcept {
return 1;
}
[[nodiscard]]
static constexpr std::size_t alignOf(const uint16_t) noexcept {
return 2;
}
[[nodiscard]]
static constexpr std::size_t alignOf(const uint32_t) noexcept {
return 4;
}
[[nodiscard]]
static constexpr std::size_t alignOf(const uint64_t) noexcept {
return 8;
}
[[nodiscard]]
static constexpr std::size_t alignOf(const int8_t) noexcept {
return 1;
}
[[nodiscard]]
static constexpr std::size_t alignOf(const int16_t) noexcept {
return 2;
}
[[nodiscard]]
static constexpr std::size_t alignOf(const int32_t) noexcept {
return 4;
}
[[nodiscard]]
static constexpr std::size_t alignOf(const int64_t) noexcept {
return 8;
}
[[nodiscard]]
static constexpr std::size_t alignOf(const auto*) noexcept {
return 4;
}
[[nodiscard]]
static constexpr auto correctEndianness(auto v) noexcept {
return ox::toLittleEndian(v);
}
};
using GbaPreloader = ox::Preloader<GbaPlatSpec>;
namespace detail {
// transformations need to be done after the copy to the new FS is complete
template<typename PlatSpec>
ox::Error preloadObj(
ox::TypeStore &ts,
ox::FileSystem &romFs,
ox::Preloader<PlatSpec> &pl,
ox::CRStringView path) noexcept {
// load file
oxRequireM(buff, romFs.read(path));
oxRequireM(obj, keel::readAsset(&ts, buff));
if (obj.type()->preloadable) {
oxOutf("preloading {}\n", path);
// preload
oxRequire(a, pl.startAlloc(ox::sizeOf<GbaPlatSpec>(&obj)));
const auto err = ox::preload<GbaPlatSpec, decltype(obj)>(&pl, &obj);
oxReturnError(pl.endAlloc());
oxReturnError(err);
const keel::PreloadPtr p{.preloadAddr = static_cast<uint32_t>(a)};
oxReturnError(ox::writeMC(p).moveTo(&buff));
} else {
// strip the Claw header (it is not needed after preloading) and write back out to dest fs
oxReturnError(ox::writeMC(obj).moveTo(&buff));
}
oxReturnError(romFs.write(path, buff.data(), buff.size()));
return {};
}
// claw file transformations are broken out because path to inode
// transformations need to be done after the copy to the new FS is complete
template<typename PlatSpec>
ox::Error preloadDir(
ox::TypeStore &ts,
ox::FileSystem &romFs,
ox::Preloader<PlatSpec> &pl,
ox::CRStringView path) noexcept {
// copy
oxTracef("pack.preload", "path: {}", path);
oxRequire(fileList, romFs.ls(path));
for (const auto &name : fileList) {
const auto filePath = ox::sfmt("{}{}", path, name);
oxRequire(stat, romFs.stat(filePath));
if (stat.fileType == ox::FileType::Directory) {
const auto dir = ox::sfmt("{}{}/", path, name);
oxReturnError(preloadDir(ts, romFs, pl, dir));
} else {
oxReturnError(preloadObj(ts, romFs, pl, filePath));
}
}
return {};
}
}
template<typename PlatSpec>
ox::Error appendBinary(ox::Buffer &binBuff, ox::SpanView<char> const&fsBuff, ox::Preloader<PlatSpec> &pl) noexcept {
constexpr auto padbin = [](ox::BufferWriter &w, unsigned factor) noexcept -> ox::Error {
return w.write(nullptr, factor - w.buff().size() % factor);
};
constexpr ox::StringView mediaHdr = "KEEL_MEDIA_HEADER_______________";
constexpr ox::StringView preloadHdr = "KEEL_PRELOAD_HEADER_____________";
constexpr auto hdrSize = 32u;
static_assert(mediaHdr.bytes() == hdrSize);
static_assert(preloadHdr.bytes() == hdrSize);
ox::BufferWriter w(&binBuff);
oxReturnError(padbin(w, hdrSize));
oxReturnError(w.write(mediaHdr.data(), mediaHdr.bytes()));
oxReturnError(w.write(fsBuff.data(), fsBuff.size()));
oxReturnError(padbin(w, hdrSize));
oxReturnError(w.write(preloadHdr.data(), preloadHdr.bytes()));
oxReturnError(pl.offsetPtrs(binBuff.size()));
const auto &plBuff = pl.buff();
oxReturnError(w.write(plBuff.data(), plBuff.size()));
return {};
}
template<typename PlatSpec>
ox::Error preload(ox::TypeStore &ts, ox::FileSystem &src, ox::Preloader<PlatSpec> &pl) noexcept {
oxOut("Preloading\n");
return detail::preloadDir(ts, src, pl, "/");
}
ox::Error pack(keel::Context &ctx, ox::TypeStore &ts, ox::FileSystem &dest) noexcept;
}

View File

@@ -0,0 +1,192 @@
/*
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include <ox/std/def.hpp>
#include <ox/std/error.hpp>
#include <ox/std/string.hpp>
#include <ox/claw/read.hpp>
#include <ox/claw/write.hpp>
#include "asset.hpp"
#include "context.hpp"
namespace keel {
class Wrap {
public:
virtual ~Wrap() = default;
};
template<typename T>
class WrapIndirect: public Wrap {
private:
T *m_obj = nullptr;
public:
template<typename... Args>
constexpr explicit WrapIndirect(Args &&...args): m_obj(ox::forward<Args>(args)...) {
}
[[nodiscard]]
constexpr auto obj() const noexcept {
return &m_obj;
}
[[nodiscard]]
constexpr auto obj() noexcept {
return &m_obj;
}
};
template<typename T>
class WrapInline: public Wrap {
private:
T m_obj;
public:
constexpr WrapInline() = default;
template<typename... Args>
constexpr explicit WrapInline(Args &&...args): m_obj(ox::forward<Args>(args)...) {
}
[[nodiscard]]
constexpr auto obj() noexcept {
return &m_obj;
}
};
template<typename T, typename... Args>
constexpr auto makeWrap(Args &&...args) noexcept {
return ox::make_unique<WrapInline<T>>(ox::forward<Args>(args)...);
}
template<typename T>
constexpr T *wrapCast(Wrap &ptr) noexcept {
return static_cast<WrapInline<T>&>(ptr).obj();
}
class BaseConverter {
public:
virtual ~BaseConverter() noexcept = default;
[[nodiscard]]
virtual ox::StringView srcTypeName() const noexcept = 0;
[[nodiscard]]
virtual int srcTypeVersion() const noexcept = 0;
[[nodiscard]]
virtual bool srcMatches(ox::CRStringView pSrcTypeName, int pSrcTypeVersion) const noexcept = 0;
[[nodiscard]]
virtual bool dstMatches(ox::CRStringView dstTypeName, int dstTypeVersion) const noexcept = 0;
virtual ox::Result<ox::UniquePtr<Wrap>> convertPtrToPtr(keel::Context &ctx, Wrap &src) const noexcept = 0;
virtual ox::Result<ox::UniquePtr<Wrap>> convertBuffToPtr(keel::Context &ctx, const ox::Buffer &srcBuff) const noexcept = 0;
[[nodiscard]]
inline bool matches(
ox::CRStringView srcTypeName, int srcTypeVersion,
ox::CRStringView dstTypeName, int dstTypeVersion) const noexcept {
return srcMatches(srcTypeName, srcTypeVersion)
&& dstMatches(dstTypeName, dstTypeVersion);
}
};
template<typename SrcType, typename DstType>
class Converter: public BaseConverter {
public:
[[nodiscard]]
ox::StringView srcTypeName() const noexcept final {
return ox::requireModelTypeName<SrcType>();
}
[[nodiscard]]
int srcTypeVersion() const noexcept final {
return ox::requireModelTypeVersion<SrcType>();
}
[[nodiscard]]
bool srcMatches(ox::CRStringView pSrcTypeName, int pSrcTypeVersion) const noexcept final {
static const auto SrcTypeName = ox::requireModelTypeName<SrcType>();
static const auto SrcTypeVersion = ox::requireModelTypeVersion<SrcType>();
return pSrcTypeName == SrcTypeName
&& pSrcTypeVersion == SrcTypeVersion;
}
[[nodiscard]]
bool dstMatches(ox::CRStringView dstTypeName, int dstTypeVersion) const noexcept final {
static const auto DstTypeName = ox::StringView(ox::requireModelTypeName<DstType>());
static const auto DstTypeVersion = ox::requireModelTypeVersion<DstType>();
return dstTypeName == DstTypeName
&& dstTypeVersion == DstTypeVersion;
}
ox::Result<ox::UniquePtr<Wrap>> convertPtrToPtr(keel::Context &ctx, Wrap &src) const noexcept final {
auto dst = makeWrap<DstType>();
oxReturnError(convert(ctx, *wrapCast<SrcType>(src), *wrapCast<DstType>(*dst)));
return ox::Result<ox::UniquePtr<Wrap>>(std::move(dst));
}
ox::Result<ox::UniquePtr<Wrap>> convertBuffToPtr(keel::Context &ctx, ox::Buffer const&srcBuff) const noexcept final {
oxRequireM(src, readAsset<SrcType>(srcBuff));
auto dst = makeWrap<DstType>();
oxReturnError(convert(ctx, src, *wrapCast<DstType>(*dst)));
return ox::Result<ox::UniquePtr<Wrap>>(std::move(dst));
}
protected:
virtual ox::Error convert(keel::Context &ctx, SrcType&, DstType&) const noexcept = 0;
};
ox::Result<ox::UniquePtr<Wrap>> convert(
keel::Context &ctx, const ox::Buffer &srcBuffer,
ox::CRStringView dstTypeName, int dstTypeVersion) noexcept;
template<typename DstType>
ox::Result<DstType> convert(keel::Context &ctx, const ox::Buffer &srcBuffer) noexcept {
static constexpr auto DstTypeName = ox::requireModelTypeName<DstType>();
static constexpr auto DstTypeVersion = ox::requireModelTypeVersion<DstType>();
oxRequire(out, convert(ctx, srcBuffer, DstTypeName, DstTypeVersion));
return wrapCast<DstType>(out);
}
template<typename DstType>
ox::Error convert(keel::Context &ctx, const ox::Buffer &buff, DstType *outObj) noexcept {
static constexpr auto DstTypeName = ox::requireModelTypeName<DstType>();
static constexpr auto DstTypeVersion = ox::requireModelTypeVersion<DstType>();
oxRequire(outPtr, convert(ctx, buff, DstTypeName, DstTypeVersion));
*outObj = std::move(*wrapCast<DstType>(*outPtr));
return OxError(0);
}
template<typename DstType>
ox::Result<ox::Buffer> convertBuffToBuff(keel::Context &ctx, const ox::Buffer &srcBuffer, ox::ClawFormat fmt) noexcept {
static constexpr auto DstTypeName = ox::requireModelTypeName<DstType>();
static constexpr auto DstTypeVersion = ox::requireModelTypeVersion<DstType>();
oxRequire(out, convert(ctx, srcBuffer, DstTypeName, DstTypeVersion));
return ox::writeClaw<DstType>(*wrapCast<DstType>(*out), fmt);
}
template<typename From, typename To, ox::ClawFormat fmt = ox::ClawFormat::Metal>
auto transformRule(keel::Context &ctx, ox::Buffer &buff) noexcept -> ox::Error {
oxRequire(hdr, readAssetHeader(buff));
const auto typeId = ox::buildTypeId(
hdr.clawHdr.typeName, hdr.clawHdr.typeVersion, hdr.clawHdr.typeParams);
if (typeId == ox::buildTypeId<From>()) {
oxReturnError(keel::convertBuffToBuff<To>(ctx, buff, fmt).moveTo(&buff));
}
return {};
};
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include <ox/claw/claw.hpp>
#include <ox/fs/fs.hpp>
#include <ox/model/typestore.hpp>
namespace keel {
class TypeStore: public ox::TypeStore {
private:
ox::FileSystem &m_fs;
ox::String m_descPath;
public:
explicit TypeStore(ox::FileSystem &fs, ox::StringView descPath) noexcept;
protected:
ox::Result<ox::UniquePtr<ox::DescriptorType>> loadDescriptor(ox::CRStringView typeId) noexcept override;
};
}