/* * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. */ #pragma once #include #include #include #include #include #include "asset.hpp" #include "context.hpp" namespace keel { class Wrap { public: virtual ~Wrap() = default; }; template class WrapIndirect: public Wrap { private: T *m_obj = nullptr; public: template constexpr explicit WrapIndirect(Args &&...args): m_obj(ox::forward(args)...) { } [[nodiscard]] constexpr auto obj() const noexcept { return &m_obj; } [[nodiscard]] constexpr auto obj() noexcept { return &m_obj; } }; template class WrapInline: public Wrap { private: T m_obj; public: constexpr WrapInline() = default; template constexpr explicit WrapInline(Args &&...args): m_obj(ox::forward(args)...) { } [[nodiscard]] constexpr auto obj() noexcept { return &m_obj; } }; template constexpr auto makeWrap(Args &&...args) noexcept { return ox::make_unique>(ox::forward(args)...); } template constexpr auto wrapCast(auto ptr) noexcept { return static_cast*>(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> convertPtrToPtr(keel::Context *ctx, Wrap *src) const noexcept = 0; virtual ox::Result> 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 class Converter: public BaseConverter { public: [[nodiscard]] ox::StringView srcTypeName() const noexcept final { return ox::requireModelTypeName(); } [[nodiscard]] int srcTypeVersion() const noexcept final { return ox::requireModelTypeVersion(); } [[nodiscard]] bool srcMatches(ox::CRStringView pSrcTypeName, int pSrcTypeVersion) const noexcept final { static const auto SrcTypeName = ox::requireModelTypeName(); static const auto SrcTypeVersion = ox::requireModelTypeVersion(); return pSrcTypeName == SrcTypeName && pSrcTypeVersion == SrcTypeVersion; } [[nodiscard]] bool dstMatches(ox::CRStringView dstTypeName, int dstTypeVersion) const noexcept final { static const auto DstTypeName = ox::StringView(ox::requireModelTypeName()); static const auto DstTypeVersion = ox::requireModelTypeVersion(); return dstTypeName == DstTypeName && dstTypeVersion == DstTypeVersion; } ox::Result> convertPtrToPtr(keel::Context *ctx, Wrap *src) const noexcept final { auto dst = makeWrap(); oxReturnError(convert(ctx, wrapCast(src), wrapCast(dst.get()))); return ox::Result>(std::move(dst)); } ox::Result> convertBuffToPtr(keel::Context *ctx, const ox::Buffer &srcBuff) const noexcept final { oxRequireM(src, readAsset(srcBuff)); auto dst = makeWrap(); oxReturnError(convert(ctx, &src, wrapCast(dst.get()))); return ox::Result>(std::move(dst)); } protected: virtual ox::Error convert(keel::Context *ctx, SrcType*, DstType*) const noexcept = 0; }; ox::Result> convert(keel::Context *ctx, const ox::Buffer &srcBuffer, ox::CRStringView dstTypeName, int dstTypeVersion) noexcept; template ox::Result convert(keel::Context *ctx, const ox::Buffer &srcBuffer) noexcept { static constexpr auto DstTypeName = ox::requireModelTypeName(); static constexpr auto DstTypeVersion = ox::requireModelTypeVersion(); oxRequire(out, convert(ctx, srcBuffer, DstTypeName, DstTypeVersion)); return wrapCast(out); } template ox::Error convert(keel::Context *ctx, const ox::Buffer &buff, DstType *outObj) noexcept { static constexpr auto DstTypeName = ox::requireModelTypeName(); static constexpr auto DstTypeVersion = ox::requireModelTypeVersion(); oxRequire(outPtr, convert(ctx, buff, DstTypeName, DstTypeVersion)); *outObj = std::move(*wrapCast(outPtr.get())); return OxError(0); } template ox::Result convertBuffToBuff(keel::Context *ctx, const ox::Buffer &srcBuffer, ox::ClawFormat fmt) noexcept { static constexpr auto DstTypeName = ox::requireModelTypeName(); static constexpr auto DstTypeVersion = ox::requireModelTypeVersion(); oxRequire(out, convert(ctx, srcBuffer, DstTypeName, DstTypeVersion)); return ox::writeClaw(wrapCast(out.get()), fmt); } template 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()) { oxReturnError(keel::convertBuffToBuff(ctx, *buff, fmt).moveTo(buff)); } return {}; }; }