191 lines
5.8 KiB
C++
191 lines
5.8 KiB
C++
/*
|
|
* 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 auto wrapCast(auto 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.get())));
|
|
return ox::Result<ox::UniquePtr<Wrap>>(std::move(dst));
|
|
}
|
|
|
|
ox::Result<ox::UniquePtr<Wrap>> convertBuffToPtr(keel::Context *ctx, const ox::Buffer &srcBuff) const noexcept final {
|
|
oxRequireM(src, readAsset<SrcType>(srcBuff));
|
|
auto dst = makeWrap<DstType>();
|
|
oxReturnError(convert(ctx, &src, wrapCast<DstType>(dst.get())));
|
|
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.get()));
|
|
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.get()), 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 {};
|
|
};
|
|
|
|
|
|
}
|