omni/core/ITypeFactory.h

File members: omni/core/ITypeFactory.h

// Copyright (c) 2020-2023, NVIDIA CORPORATION. All rights reserved.
//
// NVIDIA CORPORATION and its licensors retain all intellectual property
// and proprietary rights in and to this software, related documentation
// and any modifications thereto. Any use, reproduction, disclosure or
// distribution of this software and related documentation without an express
// license agreement from NVIDIA CORPORATION is strictly prohibited.
//
#pragma once

#include "../../carb/Defines.h"
#include "IObject.h"
#include "ModuleExports.h"
#include "Omni.h"
#include "Result.h"

#include <cstdint>
#include <vector>

namespace omni
{
namespace core
{

OMNI_DECLARE_INTERFACE(ITypeFactory);

using InterfaceImplementationCreateFn = IObject*();

struct OMNI_ATTR("no_py") InterfaceImplementation
{
    const char* name;

    InterfaceImplementationCreateFn* createFn;

    uint32_t version;

    const char** interfacesImplemented;

    uint32_t interfacesImplementedCount;
};

using TypeFactoryLoadFlags OMNI_ATTR("flag, prefix=fTypeFactoryFlag") = uint32_t;

constexpr TypeFactoryLoadFlags fTypeFactoryFlagNone = 0x0;

class ITypeFactory_abi : public omni::core::Inherits<omni::core::IObject, OMNI_TYPE_ID("omni.core.ITypeFactory")>
{
protected:
    virtual IObject* OMNI_ATTR("no_py")
        createType_abi(TypeId id, OMNI_ATTR("c_str") const char* moduleName, uint32_t implVersion) noexcept = 0;

    virtual Result registerInterfaceImplementationsFromModule_abi(OMNI_ATTR("c_str, not_null") const char* moduleName,
                                                                  TypeFactoryLoadFlags flags) noexcept = 0;

    virtual Result unregisterInterfaceImplementationsFromModule_abi(OMNI_ATTR("c_str, not_null")
                                                                        const char* moduleName) noexcept = 0;

    virtual OMNI_ATTR("no_py") void registerInterfaceImplementations_abi(
        OMNI_ATTR("in, count=implementationsCount, not_null") const InterfaceImplementation* implementations,
        uint32_t implementationsCount,
        TypeFactoryLoadFlags flags) noexcept = 0;

    virtual const char* getTypeIdName_abi(TypeId id) noexcept = 0;

    virtual void setInterfaceDefaults_abi(TypeId interfaceId,
                                          TypeId implId,
                                          OMNI_ATTR("c_str") const char* moduleName,
                                          uint32_t implVersion) noexcept = 0;

    virtual OMNI_ATTR("no_py") Result
        getInterfaceDefaults_abi(TypeId interfaceId,
                                 OMNI_ATTR("out") TypeId* outImplId, // nullptr accepted
                                 OMNI_ATTR("out" /*count=*inOutModuleNameCount*/) char* outModuleName, // nullptr
                                                                                                       // accepted
                                 OMNI_ATTR("in, out, not_null") uint32_t* inOutModuleNameCount, // must not be null
                                 OMNI_ATTR("out") uint32_t* outImplVersion) noexcept = 0; // nullptr accepted
};

constexpr uint16_t kTypeFactoryArgsVersion = 1;

class TypeFactoryArgs
{
public:
    uint16_t version;

    uint16_t byteCount;

    uint8_t padding[4];

    omni::log::ILog* log;

    omni::structuredlog::IStructuredLog* structuredLog;

    void* reserved[13];

    TypeFactoryArgs()
    {
        std::memset(this, 0, sizeof(*this));
        version = kTypeFactoryArgsVersion;
        byteCount = sizeof(*this);
    }

    TypeFactoryArgs(omni::log::ILog* log_, omni::structuredlog::IStructuredLog* strucLog_) : TypeFactoryArgs()
    {
        log = log_;
        structuredLog = strucLog_;
    }
};

CARB_ASSERT_INTEROP_SAFE(TypeFactoryArgs);
static_assert((8 + 15 * sizeof(void*)) == sizeof(TypeFactoryArgs), "TypeFactoryArgs has an unexpected size");

} // namespace core
} // namespace omni

#include "ITypeFactory.gen.h"

#ifdef OMNI_COMPILE_AS_DYNAMIC_LIBRARY
OMNI_API omni::core::ITypeFactory* omniGetTypeFactoryWithoutAcquire();
#else
inline omni::core::ITypeFactory* omniGetTypeFactoryWithoutAcquire()
{
    return static_cast<omni::core::ITypeFactory*>(omniGetBuiltInWithoutAcquire(OmniBuiltIn::eITypeFactory));
}
#endif

OMNI_API omni::core::ITypeFactory* omniCreateTypeFactory(const omni::core::TypeFactoryArgs* args = nullptr);

// clang-format off
OMNI_DEFINE_INTERFACE_API(omni::core::ITypeFactory)
{
public:
    template <typename T>
    inline ObjectPtr<T> createType(const char* moduleName = nullptr, uint32_t version = 0) noexcept
    {
        return createType<T>(T::kTypeId, moduleName, version);
    }

    template <typename T = IObject>
    inline ObjectPtr<T> createType(TypeId id, const char* moduleName = nullptr, uint32_t version = 0) noexcept
    {
        auto ptr = steal(createType_abi(id, moduleName, version));
        return ptr.template as<T>();
    }
};
// clang-format on

namespace omni
{
namespace core
{

template <typename T>
inline ObjectPtr<T> createType(const char* moduleName = nullptr, uint32_t version = 0) throw()
{
    return omniGetTypeFactoryWithoutAcquire()->createType<T>(moduleName, version);
}

template <typename T = IObject>
inline ObjectPtr<T> createType(TypeId id, const char* moduleName = nullptr, uint32_t version = 0) CARB_NOEXCEPT
{
    return omniGetTypeFactoryWithoutAcquire()->createType<T>(id, moduleName, version);
}

inline Result registerInterfaceImplementationsFromModule(const char* moduleName, // e.g. omni.scripting-python.dll
                                                         TypeFactoryLoadFlags flags = 0) CARB_NOEXCEPT
{
    return omniGetTypeFactoryWithoutAcquire()->registerInterfaceImplementationsFromModule(moduleName, flags);
}

inline void registerInterfaceImplementations(const InterfaceImplementation* implementations,
                                             uint32_t implementationsCount,
                                             TypeFactoryLoadFlags flags = 0) CARB_NOEXCEPT
{
    return omniGetTypeFactoryWithoutAcquire()->registerInterfaceImplementations(
        implementations, implementationsCount, flags);
}

inline const char* getTypeIdName(TypeId id) CARB_NOEXCEPT
{
    return omniGetTypeFactoryWithoutAcquire()->getTypeIdName(id);
}

template <typename T>
inline void setInterfaceDefaults(TypeId implId, const char* moduleName, uint32_t implVersion)
{
    omniGetTypeFactoryWithoutAcquire()->setInterfaceDefaults(T::kTypeId, implId, moduleName, implVersion);
}

template <typename T>
inline Result getInterfaceDefaults(TypeId* implId, std::string* moduleName, uint32_t* implVersion)
{
    if (!moduleName)
    {
        uint32_t moduleNameCount = 0;
        Result result = omniGetTypeFactoryWithoutAcquire()->getInterfaceDefaults(
            T::kTypeId, implId, nullptr, &moduleNameCount, implVersion);
        return result;
    }
    else
    {
        // loop here in case the module name size changes between checking for the size and actually get the string.
        std::vector<char> buffer;
        for (unsigned i = 0; i < 4; ++i)
        {
            uint32_t moduleNameCount = uint32_t(buffer.size());
            Result result = omniGetTypeFactoryWithoutAcquire()->getInterfaceDefaults(
                T::kTypeId, implId, buffer.data(), &moduleNameCount, implVersion);
            if (kResultInsufficientBuffer != result)
            {
                *moduleName = buffer.data();
                return result;
            }
            else
            {
                buffer.resize(moduleNameCount);
            }
        }

        return kResultTryAgain;
    }
}

inline Result unregisterInterfaceImplementationsFromModule(const char* moduleName) CARB_NOEXCEPT
{
    return omniGetTypeFactoryWithoutAcquire()->unregisterInterfaceImplementationsFromModule(moduleName);
}

} // namespace core
} // namespace omni