// 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.
//
// --------- Warning: This is a build system generated file. ----------
//

//! @file
//!
//! @brief This file was generated by <i>omni.bind</i>.

#include <omni/core/OmniAttr.h>
#include <omni/core/Interface.h>
#include <omni/core/ResultError.h>

#include <functional>
#include <utility>
#include <type_traits>

#ifndef OMNI_BIND_INCLUDE_INTERFACE_IMPL


//! A mapping from type id's to implementations.
//!
//! This object maps type id's to concrete implementations.  The type id's can represent interface ids or implementation
//! ids.
//!
//! Register types with registerInterfaceImplementationsFromModule() and registerInterfaceImplementations().
//!
//! Instantiate types with omni::core::createType(). This is the primary way Omniverse applications are able to
//! instantiate concrete implementations of @rstref{ABI-safe <abi-compatibility>} interfaces.  See
//! omni::core::createType() for a helpful wrapper around omni::core::ITypeFactory::createType().
//!
//! In practice, there will be a single ITypeFactory active in the process space (accessible via
//! omniGetTypeFactoryWithoutAcquire()).  However, @ref omni::core::ITypeFactory is not inherently a singleton, and as
//! such multiple instantiations of the interface may exists.  This can be used to create private type trees.
//!
//! Unless otherwise noted, all methods in this interface are thread safe.
template <>
class omni::core::Generated<omni::core::ITypeFactory_abi> : public omni::core::ITypeFactory_abi
{
public:
    OMNI_PLUGIN_INTERFACE("omni::core::ITypeFactory")

    //! Instantiates a concrete type.
    //!
    //! The given type id can be an interface or implementation id.
    //!
    //! If the id is an interface id, the following rules are followed:
    //!
    //! - If the application specified a default implementation, that implementation will be instantiated.
    //!
    //! - Otherwise, the first registered implementation of the interface is instantiated.  If multiple versions of the
    //!   implementation exist, the highest version is picked.
    //!
    //! - implVersion must be 0 since interfaces are not versioned (only implementations are versioned). If implVersion
    //!   is not 0, nullptr is returned.
    //!
    //! - If a default module name was provided by the app, the rules above will only be applied to implementations from
    //!   the specified default module.
    //!
    //! If the id is an implementation id, the followings rules apply:
    //!
    //! - If version is 0, the highest version of the implementation is returned.
    //!
    //! - If version is not 0, the returned object is the specified version of the implementation.  If such a version
    //!   does not exists, nullptr is returned. If multiple implementations exists with the same version, the
    //!   implementation registered first is instantiated.
    //!
    //! In both cases above, if moduleName given, the rules above are followed by only looking at implementations from
    //! the specified module.  If no match is found, nullptr is returned.
    //!
    //! If moduleName has not been loaded, it will be loaded and its implementations registered.
    //!
    //! If moduleName is nullptr, the rules above are applied across all loaded modules.
    //!
    //! This method is thread safe.
    omni::core::ObjectPtr<omni::core::IObject> createType(omni::core::TypeId id,
                                                          const char* moduleName,
                                                          uint32_t implVersion) noexcept;

    //! Registers types from the given module.
    //!
    //! If the module is currently loaded, it will not be reloaded and kResultSuccess is returned.
    //!
    //! Modules (e.g. .dll or .so) may contain one or many implementations of one or many interfaces. When registering a
    //! module with the type factory, a function, whose name is described by 'kModuleGetExportsName', is found and
    //! invoked.  Let's assume the exported function name is "omniModuleGetExports".
    //!
    //! "omniModuleGetExports" returns a key/value database of the module's capabilities and the module's requirements.
    //! Some things to note about this database:
    //!
    //!   - The module's requirements can be marked as optional.
    //!
    //!   - The module's capabilities can be ignored by ITypeFactory.
    //!
    //! These properties allow ITypeFactory and the module to find an intersection of desired functionality in a data
    //! driven manner.  If one party's required needs are not met, the module fails to load (e.g. an appropriate
    //! omni::core::Result is returned).
    //!
    //! It is expected the module has entries in the key/value database describing the functions ITypeFactory should
    //! call during the loading process.  The most important of these entries is the one defined by
    //! OMNI_MODULE_ON_MODULE_LOAD(), which points to the function ITypeFactory should call to get a list of
    //! implementations in the module.  ITypeFactory invokes exports from the module in the following pattern:
    //!
    //! .--------------------------------------------------------------------------------------------------------------.
    //! |                                                -> Time ->                                                    |
    //! |--------------------------------------------------------------------------------------------------------------|
    //! | omniModuleGetExports | onLoad (req.) | onStarted (optional) | onCanUnload (optional) | onUnload (optional)   |
    //! |                      |               | impl1->createFn      |                        |                       |
    //! |                      |               | impl2->createFn      |                        |                       |
    //! |                      |               | impl1->createFn      |                        |                       |
    //! \--------------------------------------------------------------------------------------------------------------/
    //!
    //! Above, functions in the same column can be called concurrently. It's up to the module to make sure such call
    //! patterns are thread safe within the module.
    //!
    //! onCanUnload and createFn can be called multiple times.  All other functions are called once during the lifecycle
    //! of a module.
    //!
    //! \see omni/core/ModuleExports.h.
    //! \see onModuleLoadFn
    //! \see onModuleStartedFn
    //! \see onModuleCanUnloadFn
    //! \see onModuleUnloadFn
    //!
    //!
    //! The module can be explicitly unloaded with unregisterInterfaceImplementationsFromModule().
    //!
    //! Upon destruction of this ITypeFactory, unregisterInterfaceImplementationsFromModule is called for each loaded
    //! module.  If the ITypeFactory destructor's call to unregisterInterfaceImplementationsFromModule fails to safely
    //! unload a module (via the module's onModuleCanUnload and onModuleUnload), an attempt will be made to
    //! forcefully/unsafely unload the module.
    //!
    //! The given module name must not be nullptr.
    //!
    //! This method is thread safe. Modules can be loaded in parallel.
    //!
    //! \returns Returns kResultSuccess if the module is loaded (either due to this function or a previous call).
    //! Otherwise, an error is returned.
    omni::core::Result registerInterfaceImplementationsFromModule(const char* moduleName,
                                                                  omni::core::TypeFactoryLoadFlags flags) noexcept;

    //! Unregisters all types registered from the given module.
    //!
    //! Unregistering a module may fail if the module does not belief it can safely be unloaded. This is determined by
    //! OMNI_MODULE_ON_MODULE_CAN_UNLOAD().
    //!
    //! If unregistration does succeed, the given module will be unloaded from the process space.
    //!
    //! Upon destruction of this ITypeFactory, unregisterInterfaceImplementationsFromModule is called for each loaded
    //! module.  If the ITypeFactory destructor's call to unregisterInterfaceImplementationsFromModule fails to safely
    //! unload a module (via the module's onModuleCanUnload and onModuleUnload), an attempt will be made to
    //! forcefully/unsafely unload the module.
    //!
    //! The given module name must not be nullptr.
    //!
    //! This method is thread safe.
    //!
    //! \returns Returns kResultSuccess if the module wasn't already loaded or if this method successfully unloaded the
    //! module. Return an error code otherwise.
    omni::core::Result unregisterInterfaceImplementationsFromModule(const char* moduleName) noexcept;

    //! Register the list of types.
    //!
    //! Needed data from the "implementations" list is copied by this method.
    //!
    //! This method is thread safe.
    void registerInterfaceImplementations(const omni::core::InterfaceImplementation* implementations,
                                          uint32_t implementationsCount,
                                          omni::core::TypeFactoryLoadFlags flags) noexcept;

    //! Maps a type id back to its type name.
    //!
    //! The memory returned is valid for the lifetime of ITypeFactory
    //!
    //! Returns nullptr if id has never been registered. Types that have been registered, and then unregistered, will
    //! still have a valid string returned from this method.
    //!
    //! This method is thread safe.
    const char* getTypeIdName(omni::core::TypeId id) noexcept;

    //! Sets the implementation matching constraints for the given interface id.
    //!
    //! See omni::core::ITypeFactory_abi::createType_abi() for how these constraints are used.
    //!
    //! moduleName can be nullptr.
    //!
    //! if implVersion is 0 and implId is an implementation id, the implementation with the highest version is chosen.
    //!
    //! This method is thread safe.
    void setInterfaceDefaults(omni::core::TypeId interfaceId,
                              omni::core::TypeId implId,
                              const char* moduleName,
                              uint32_t implVersion) noexcept;

    //! Returns the implementation matching constraints for the given interface id.
    //!
    //! See omni::core::ITypeFactory_abi::createType_abi() for how these constraints are used.
    //!
    //! If the given output implementation id pointer (outImplid) is not nullptr, it will be populated with the default
    //! implementation id instantiated when the interface requested to be created.
    //!
    //! If the given output implementation version pointer (outImplVersion) is not nullptr, it will be populated with
    //! the default implementation version instantiated when the interface is requested to be created.
    //!
    //! If the output module name pointer (outModuleName) is not nullptr, it will be populated with the name of the
    //! module searched when trying to find an implementation of the interface.  If there is no current default module
    //! name, the output module name will be populated with the empty string. If the output module name's buffer size is
    //! insufficient to store the null terminated module name, kResultBufferInsufficient is returned and the module
    //! name's buffer size is updated with the needed buffer size.
    //!
    //! If the output module name is nullptr, the output module name buffer size (inOutModuleNameCount) will be
    //! populated with the size of the buffer needed to store the module name.
    //!
    //! The output module name buffer size pointer (inOutModuleNameCount) must not be nullptr.
    //!
    //! If the given interface id is not found, kResultNotFound is returned and the output implementation id (outImplId)
    //! and version (outImplVersion), if defined, are set to 0.  Additionally, the output module name (outModuleName),
    //! if defined, is set to the empty string.
    //!
    //! If kResultInsufficientBuffer and kResultNotFound are both flagged internally, kResultNotFound is returned.
    //!
    //! See omni::core::getInterfaceDefaults() for a C++ wrapper to this method.
    //!
    //! This method is thread safe.
    omni::core::Result getInterfaceDefaults(omni::core::TypeId interfaceId,
                                            omni::core::TypeId* outImplId,
                                            char* outModuleName,
                                            uint32_t* inOutModuleNameCount,
                                            uint32_t* outImplVersion) noexcept;
};

#endif

#ifndef OMNI_BIND_INCLUDE_INTERFACE_DECL

inline omni::core::ObjectPtr<omni::core::IObject> omni::core::Generated<omni::core::ITypeFactory_abi>::createType(
    omni::core::TypeId id, const char* moduleName, uint32_t implVersion) noexcept
{
    return omni::core::steal(createType_abi(id, moduleName, implVersion));
}

inline omni::core::Result omni::core::Generated<omni::core::ITypeFactory_abi>::registerInterfaceImplementationsFromModule(
    const char* moduleName, omni::core::TypeFactoryLoadFlags flags) noexcept
{
    return registerInterfaceImplementationsFromModule_abi(moduleName, flags);
}

inline omni::core::Result omni::core::Generated<omni::core::ITypeFactory_abi>::unregisterInterfaceImplementationsFromModule(
    const char* moduleName) noexcept
{
    return unregisterInterfaceImplementationsFromModule_abi(moduleName);
}

inline void omni::core::Generated<omni::core::ITypeFactory_abi>::registerInterfaceImplementations(
    const omni::core::InterfaceImplementation* implementations,
    uint32_t implementationsCount,
    omni::core::TypeFactoryLoadFlags flags) noexcept
{
    registerInterfaceImplementations_abi(implementations, implementationsCount, flags);
}

inline const char* omni::core::Generated<omni::core::ITypeFactory_abi>::getTypeIdName(omni::core::TypeId id) noexcept
{
    return getTypeIdName_abi(id);
}

inline void omni::core::Generated<omni::core::ITypeFactory_abi>::setInterfaceDefaults(omni::core::TypeId interfaceId,
                                                                                      omni::core::TypeId implId,
                                                                                      const char* moduleName,
                                                                                      uint32_t implVersion) noexcept
{
    setInterfaceDefaults_abi(interfaceId, implId, moduleName, implVersion);
}

inline omni::core::Result omni::core::Generated<omni::core::ITypeFactory_abi>::getInterfaceDefaults(
    omni::core::TypeId interfaceId,
    omni::core::TypeId* outImplId,
    char* outModuleName,
    uint32_t* inOutModuleNameCount,
    uint32_t* outImplVersion) noexcept
{
    return getInterfaceDefaults_abi(interfaceId, outImplId, outModuleName, inOutModuleNameCount, outImplVersion);
}

#endif

#undef OMNI_BIND_INCLUDE_INTERFACE_DECL
#undef OMNI_BIND_INCLUDE_INTERFACE_IMPL
static_assert(std::is_standard_layout<omni::core::InterfaceImplementation>::value,
              "omni::core::InterfaceImplementation must be standard layout to be used in ONI ABI");
