carb/Framework.h
File members: carb/Framework.h
// Copyright (c) 2018-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 "Defines.h"
#include "Memory.h"
#include "Types.h"
#include <cstddef>
#include <cstdint>
// free() can be #define'd which can interfere below, so handle that here
#ifdef free
#    define CARB_FREE_UNDEFINED
#    pragma push_macro("free")
#    undef free
#endif
namespace carb
{
#define CARBONITE_MAJOR 0
#define CARBONITE_MINOR 6
constexpr struct Version kFrameworkVersion = { CARBONITE_MAJOR, CARBONITE_MINOR };
constexpr FourCC kCarb_FourCC = CARB_MAKE_FOURCC('C', 'A', 'R', 'B');
struct PluginRegistrationDesc
{
    OnPluginRegisterFn onPluginRegisterFn;
    OnPluginStartupFn onPluginStartupFn;
    OnPluginShutdownFn onPluginShutdownFn;
    GetPluginDepsFn getPluginDepsFn;
    OnReloadDependencyFn onReloadDependencyFn;
    OnPluginPreStartupFn onPluginPreStartupFn;
    OnPluginPostShutdownFn onPluginPostShutdownFn;
    OnPluginRegisterExFn onPluginRegisterExFn;
    OnPluginStartupExFn onPluginStartupExFn = nullptr;
    OnPluginRegisterEx2Fn onPluginRegisterEx2Fn = nullptr;
    FourCC const checkValue{ kCarb_FourCC };
    size_t const sizeofThis{ sizeof(PluginRegistrationDesc) };
    OnPluginQuickShutdownFn onPluginQuickShutdownFn = nullptr;
    Version frameworkVersion{ kFrameworkVersion };
};
struct PluginLoadingDesc
{
    const char* const* searchPaths;
    size_t searchPathCount;
    bool searchRecursive;
    const char* const* loadedFileWildcards;
    size_t loadedFileWildcardCount;
    const char* const* reloadableFileWildcards;
    size_t reloadableFileWildcardCount;
    bool unloadPlugins;
    const char* const* excludedFileWildcards;
    size_t excludedFileWildcardCount;
    static PluginLoadingDesc getDefault()
    {
        static constexpr const char* defaultSearchPath = "";
        static constexpr const char* defaultLoadedFileWildcard = "*.plugin";
        return { &defaultSearchPath, 1, false, &defaultLoadedFileWildcard, 1, nullptr, 0, false, nullptr, 0 };
    }
};
enum AcquireInterfaceFlags : uint64_t
{
    eAIFDefaultType = 0,
    eAIFFromInterfaceType,
    eAIFFromLibraryType,
    eAIFNumTypes,
    fAIFTypeMask = 0xf,
    fAIFOptional = (1 << 4),
    fAIFNoInitialize = (1 << 5),
};
static_assert(eAIFNumTypes <= fAIFTypeMask, "Too many types for mask");
struct AcquireInterfaceOptions
{
    size_t sizeofThis;
    const char* clientName;
    InterfaceDesc desc;
    AcquireInterfaceFlags flags;
    const void* typeParam;
};
CARB_ASSERT_INTEROP_SAFE(AcquireInterfaceOptions);
enum class LoadPluginResult : int32_t
{
    eForbiddenPath = -3,
    eInvalidArg = -2,
    eFailed = -1,
    eSucceeded = 0,
    eSucceededAsOmniverseNativeInterface = 1,
    eAlreadyLoaded = 2,
};
using ReleaseHookFn = void (*)(void* iface, void* userData);
using LoadHookFn = void (*)(const PluginDesc& plugin, void* userData);
CARB_DYNAMICLINK carb::Framework* acquireFramework(const char* appName, Version frameworkVersion = kFrameworkVersion);
CARB_DYNAMICLINK bool isFrameworkValid();
CARB_DYNAMICLINK const char* carbGetSdkVersion();
#define CARB_IS_SAME_SDK_VERSION(version) (strcmp(version, carbGetSdkVersion()) == 0)
CARB_DYNAMICLINK void releaseFramework();
CARB_DYNAMICLINK void quickReleaseFrameworkAndTerminate [[noreturn]] (int exitCode);
#if CARB_PLATFORM_WINDOWS
CARB_DYNAMICLINK void carbSignalHandler(int signal);
#endif
struct Framework
{
    void loadPlugins(const PluginLoadingDesc& desc = PluginLoadingDesc::getDefault());
    void(CARB_ABI* loadPluginsEx)(const PluginLoadingDesc& desc);
    void(CARB_ABI* unloadAllPlugins)();
    template <typename T>
    T* acquireInterface(const char* pluginName = nullptr);
    template <typename T>
    T* tryAcquireInterface(const char* pluginName = nullptr);
    template <typename T>
    T* acquireInterface(const void* pluginInterface);
    template <typename T>
    T* tryAcquireInterface(const void* pluginInterface);
    template <typename T>
    T* acquireInterfaceFromLibrary(const char* libraryPath);
    template <typename T>
    T* tryAcquireInterfaceFromLibrary(const char* libraryPath);
    template <typename T>
    T* tryAcquireExistingInterface(const char* pluginName = nullptr);
    template <typename T>
    uint32_t getInterfacesCount();
    template <typename T>
    void acquireInterfaces(T** interfaces, uint32_t interfacesSize);
    void*(CARB_ABI* acquireInterfaceWithClient)(const char* clientName, InterfaceDesc desc, const char* pluginName);
    static_assert(kFrameworkVersion.major == 0, "Remove above function in next Framework version");
    void*(CARB_ABI* tryAcquireInterfaceWithClient)(const char* clientName, InterfaceDesc desc, const char* pluginName);
    static_assert(kFrameworkVersion.major == 0, "Remove above function in next Framework version");
    void*(CARB_ABI* acquireInterfaceFromInterfaceWithClient)(const char* clientName,
                                                             InterfaceDesc desc,
                                                             const void* pluginInterface);
    static_assert(kFrameworkVersion.major == 0, "Remove above function in next Framework version");
    void*(CARB_ABI* tryAcquireInterfaceFromInterfaceWithClient)(const char* clientName,
                                                                InterfaceDesc desc,
                                                                const void* pluginInterface);
    static_assert(kFrameworkVersion.major == 0, "Remove above function in next Framework version");
    void*(CARB_ABI* acquireInterfaceFromLibraryWithClient)(const char* clientName,
                                                           InterfaceDesc desc,
                                                           const char* libraryPath);
    static_assert(kFrameworkVersion.major == 0, "Remove above function in next Framework version");
    void*(CARB_ABI* tryAcquireInterfaceFromLibraryWithClient)(const char* clientName,
                                                              InterfaceDesc desc,
                                                              const char* libraryPath);
    static_assert(kFrameworkVersion.major == 0, "Remove above function in next Framework version");
    uint32_t(CARB_ABI* getInterfacesCountEx)(InterfaceDesc interfaceDesc);
    void(CARB_ABI* acquireInterfacesWithClient)(const char* clientName,
                                                InterfaceDesc interfaceDesc,
                                                void** interfaces,
                                                uint32_t interfacesSize);
    template <typename T>
    void releaseInterface(T* pluginInterface);
    void(CARB_ABI* releaseInterfaceWithClient)(const char* clientName, void* pluginInterface);
    const PluginDesc&(CARB_ABI* getPluginDesc)(const char* pluginName);
    const PluginDesc&(CARB_ABI* getInterfacePluginDesc)(void* pluginInterface);
    void(CARB_ABI* getCompatiblePlugins)(InterfaceDesc interfaceDesc, PluginDesc* outPlugins);
    size_t(CARB_ABI* getPluginCount)();
    void(CARB_ABI* getPlugins)(PluginDesc* outPlugins);
    void(CARB_ABI* tryReloadPlugins)();
    bool(CARB_ABI* registerPlugin)(const char* clientName, const PluginRegistrationDesc& desc);
    bool(CARB_ABI* unregisterPlugin)(const char* pluginName);
    const PluginRegistrationDesc&(CARB_ABI* getBuiltinLoggingDesc)();
    const PluginRegistrationDesc&(CARB_ABI* getBuiltinFileSystemDesc)();
    template <class T>
    void setDefaultPlugin(const char* pluginName);
    void(CARB_ABI* setDefaultPluginEx)(const char* clientName, InterfaceDesc desc, const char* pluginName);
    void(CARB_ABI* setReloadableTempPath)(const char* tempPath);
    const char*(CARB_ABI* getReloadableTempPath)();
    const char*(CARB_ABI* getBuildInfo)();
    template <typename T>
    T* verifyInterface(T* interfaceCandidate);
    void*(CARB_ABI* verifyInterfaceEx)(InterfaceDesc desc, void* interfaceCandidate);
    const PluginRegistrationDesc&(CARB_ABI* getBuiltinAssertDesc)();
    const PluginRegistrationDesc&(CARB_ABI* getBuiltinThreadUtilDesc)();
    LoadPluginResult(CARB_ABI* loadPlugin)(const char* libraryPath, bool reloadable, bool unload);
    bool(CARB_ABI* unloadPlugin)(const char* libraryPath);
    bool(CARB_ABI* addReleaseHook)(void* iface, ReleaseHookFn fn, void* user);
    bool(CARB_ABI* removeReleaseHook)(void* iface, ReleaseHookFn fn, void* user);
    CARB_DEPRECATED("Use carbReallocate() instead")
    void*(CARB_ABI* internalRealloc)(void* prev, size_t newSize, size_t align);
    static_assert(kFrameworkVersion.major == 0, "Remove Framework::internalRealloc in next Framework version");
    CARB_DEPRECATED("Use carb::allocate() instead") void* allocate(size_t size, size_t align = 0)
    {
        return carb::allocate(size, align);
    }
    static_assert(kFrameworkVersion.major == 0, "Remove Framework::allocate in next Framework version");
    CARB_DEPRECATED("Use carb::deallocate() instead") void free(void* p)
    {
        return carb::deallocate(p);
    }
    static_assert(kFrameworkVersion.major == 0,
                  "Remove Framework::free and CARB_FREE_UNDEFINED in next Framework version");
    CARB_DEPRECATED("Use carb::reallocate() instead") void* reallocate(void* p, size_t size, size_t align = 0)
    {
        return carb::reallocate(p, size, align);
    }
    static_assert(kFrameworkVersion.major == 0, "Remove Framework::reallocate in next Framework version");
    const char*(CARB_ABI* getSdkVersion)();
    template <class T>
    LoadHookHandle addLoadHook(const char* pluginName, LoadHookFn func, void* userData);
    LoadHookHandle(CARB_ABI* internalAddLoadHook)(
        const InterfaceDesc& iface, const char* plugin, const char* clientName, LoadHookFn fn, void* user, bool add);
    bool(CARB_ABI* removeLoadHook)(LoadHookHandle handle);
    void(CARB_ABI* registerScriptBinding)(BindingType type, const char* clientName, const char* scriptType);
    void*(CARB_ABI* internalAcquireInterface)(const AcquireInterfaceOptions& options);
};
} // namespace carb
CARB_WEAKLINK CARB_HIDDEN const char* g_carbClientName;
CARB_WEAKLINK CARB_HIDDEN carb::Framework* g_carbFramework;
extern bool g_needToCall_CARB_GLOBALS_atGlobalScope;
#define CARB_FRAMEWORK_GLOBALS(clientName)                                                                             \
    CARB_HIDDEN bool g_needToCall_CARB_GLOBALS_atGlobalScope = carb::detail::setClientName(clientName);
namespace carb
{
namespace detail
{
inline bool setClientName(const char* clientName)
{
    g_carbClientName = clientName;
    return true;
}
} // namespace detail
inline Framework* getFramework()
{
    return g_carbFramework;
}
inline void Framework::loadPlugins(const PluginLoadingDesc& desc)
{
    return this->loadPluginsEx(desc);
}
template <typename T>
T* Framework::verifyInterface(T* interfaceCandidate)
{
    const auto desc = T::getInterfaceDesc();
    return static_cast<T*>(getFramework()->verifyInterfaceEx(desc, interfaceCandidate));
}
template <typename T>
T* Framework::acquireInterface(const char* pluginName)
{
    const char* clientName = g_needToCall_CARB_GLOBALS_atGlobalScope ? g_carbClientName : nullptr;
    if (this->internalAcquireInterface)
        return static_cast<T*>(this->internalAcquireInterface(
            { sizeof(AcquireInterfaceOptions), clientName, T::getInterfaceDesc(), eAIFDefaultType, pluginName }));
    else
        return static_cast<T*>(this->acquireInterfaceWithClient(clientName, T::getInterfaceDesc(), pluginName));
}
template <typename T>
T* Framework::tryAcquireInterface(const char* pluginName)
{
    const char* clientName = g_needToCall_CARB_GLOBALS_atGlobalScope ? g_carbClientName : nullptr;
    if (this->internalAcquireInterface)
        return static_cast<T*>(
            this->internalAcquireInterface({ sizeof(AcquireInterfaceOptions), clientName, T::getInterfaceDesc(),
                                             AcquireInterfaceFlags(eAIFDefaultType | fAIFOptional), pluginName }));
    else
        return static_cast<T*>(this->tryAcquireInterfaceWithClient(clientName, T::getInterfaceDesc(), pluginName));
}
template <typename T>
T* Framework::acquireInterface(const void* pluginInterface)
{
    const char* clientName = g_needToCall_CARB_GLOBALS_atGlobalScope ? g_carbClientName : nullptr;
    if (this->internalAcquireInterface)
        return static_cast<T*>(
            this->internalAcquireInterface({ sizeof(AcquireInterfaceOptions), clientName, T::getInterfaceDesc(),
                                             eAIFFromInterfaceType, pluginInterface }));
    else
        return static_cast<T*>(
            this->acquireInterfaceFromInterfaceWithClient(clientName, T::getInterfaceDesc(), pluginInterface));
}
template <typename T>
T* Framework::tryAcquireInterface(const void* pluginInterface)
{
    const char* clientName = g_needToCall_CARB_GLOBALS_atGlobalScope ? g_carbClientName : nullptr;
    if (this->internalAcquireInterface)
        return static_cast<T*>(this->internalAcquireInterface(
            { sizeof(AcquireInterfaceOptions), clientName, T::getInterfaceDesc(),
              AcquireInterfaceFlags(eAIFFromInterfaceType | fAIFOptional), pluginInterface }));
    else
        return static_cast<T*>(
            this->tryAcquireInterfaceFromInterfaceWithClient(clientName, T::getInterfaceDesc(), pluginInterface));
}
template <typename T>
T* Framework::acquireInterfaceFromLibrary(const char* libraryPath)
{
    const char* clientName = g_needToCall_CARB_GLOBALS_atGlobalScope ? g_carbClientName : nullptr;
    if (this->internalAcquireInterface)
        return static_cast<T*>(this->internalAcquireInterface(
            { sizeof(AcquireInterfaceOptions), clientName, T::getInterfaceDesc(), eAIFFromLibraryType, libraryPath }));
    else
        return static_cast<T*>(
            this->acquireInterfaceFromLibraryWithClient(clientName, T::getInterfaceDesc(), libraryPath));
}
template <typename T>
T* Framework::tryAcquireInterfaceFromLibrary(const char* libraryPath)
{
    const char* clientName = g_needToCall_CARB_GLOBALS_atGlobalScope ? g_carbClientName : nullptr;
    if (this->internalAcquireInterface)
        return static_cast<T*>(
            this->internalAcquireInterface({ sizeof(AcquireInterfaceOptions), clientName, T::getInterfaceDesc(),
                                             AcquireInterfaceFlags(eAIFFromLibraryType | fAIFOptional), libraryPath }));
    else
        return static_cast<T*>(
            this->tryAcquireInterfaceFromLibraryWithClient(clientName, T::getInterfaceDesc(), libraryPath));
}
template <typename T>
T* Framework::tryAcquireExistingInterface(const char* pluginName)
{
    const char* clientName = g_needToCall_CARB_GLOBALS_atGlobalScope ? g_carbClientName : nullptr;
    return this->internalAcquireInterface ?
               static_cast<T*>(this->internalAcquireInterface(
                   { sizeof(AcquireInterfaceOptions), clientName, T::getInterfaceDesc(),
                     AcquireInterfaceFlags(eAIFDefaultType | fAIFOptional | fAIFNoInitialize), pluginName })) :
               nullptr;
}
template <typename T>
uint32_t Framework::getInterfacesCount()
{
    const InterfaceDesc desc = T::getInterfaceDesc();
    return this->getInterfacesCountEx(desc);
}
template <typename T>
void Framework::acquireInterfaces(T** interfaces, uint32_t interfacesSize)
{
    const InterfaceDesc desc = T::getInterfaceDesc();
    const char* clientName = g_needToCall_CARB_GLOBALS_atGlobalScope ? g_carbClientName : nullptr;
    this->acquireInterfacesWithClient(clientName, desc, reinterpret_cast<void**>(interfaces), interfacesSize);
}
template <typename T>
void Framework::releaseInterface(T* pluginInterface)
{
    (void)(T::getInterfaceDesc()); // Compile-time check that the type is plugin interface
    const char* clientName = g_needToCall_CARB_GLOBALS_atGlobalScope ? g_carbClientName : nullptr;
    this->releaseInterfaceWithClient(clientName, pluginInterface);
}
template <typename T>
void Framework::setDefaultPlugin(const char* pluginName)
{
    const char* clientName = g_needToCall_CARB_GLOBALS_atGlobalScope ? g_carbClientName : nullptr;
    this->setDefaultPluginEx(clientName, T::getInterfaceDesc(), pluginName);
}
template <typename T>
LoadHookHandle Framework::addLoadHook(const char* pluginName, LoadHookFn func, void* user)
{
    const char* clientName = g_needToCall_CARB_GLOBALS_atGlobalScope ? g_carbClientName : nullptr;
    return this->internalAddLoadHook(T::getInterfaceDesc(), pluginName, clientName, func, user, true);
}
} // namespace carb
#ifdef CARB_FREE_UNDEFINED
#    pragma pop_macro("free")
#    undef CARB_FREE_UNDEFINED
#endif