// Copyright (c) 2022-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/Interface.h>
#include <omni/core/OmniAttr.h>
#include <omni/core/ResultError.h>

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

#ifndef OMNI_BIND_INCLUDE_INTERFACE_IMPL


//! Stores and provides access to the execution state of the graph.
//!
//! The @rstref{execution graph <ef_execution_graph>} is only a description of what needs to be executed. The actual
//! graph state is stored separately in an instance of this object.
//!
//! The execution context allows computing the same graph description within multiple contexts. It also enables the
//! ability to perform this computation concurrently.  Some example use cases of this class:
//!
//! - Computing the state of a graph at a time different than the current time (e.g. asynchronous caching, fake
//!   dynamics)
//!
//! - Computing the state of a graph with a inputs different than the current input state (e.g. double solve)
//!
//! All execution begins with a call to one of the execute methods on this interface. @ref
//! omni::graph::exec::unstable::IExecutionContext::execute() is used to execute the entire execution graph while @ref
//! omni::graph::exec::unstable::IExecutionContext::executeNode() can be used to execute only a part of the graph.
//!
//! Part of this interface defines a key/value store.  The *key* in this store is an @ref
//! omni::graph::exec::unstable::ExecutionPath.  The *value* is an implementation of @ref
//! omni::graph::exec::unstable::IExecutionStateInfo, which in addition to storing computation state, can also store
//! user defined data.  The computation state and user data can be access with one of the `getStateInfo` /
//! `setStateInfo` methods though if you wish to access the user data using one of the `getNodeData` / `setNodeData` is
//! slightly faster.
//!
//! Another feature of @ref omni::graph::exec::unstable::IExecutionContext is the ability to quickly search for nodes
//! using a particular definition and apply a function on them.  Definitions can be searched by name or by pointer (see
//! @ref omni::graph::exec::unstable::IExecutionContext::applyOnEach()).  These methods are used extensively during
//! @rstref{Graph Construction <ef_pass_concepts>}.
//!
//! See @rstref{Execution Concepts <ef_execution_concepts>} for an in-depth guide on how this object is used during
//! execution.
//!
//! Since multiple threads can concurrently traverse a graph, implementors of methods within this class should expect
//! that multiple threads will be accessing this object in parallel.
template <>
class omni::core::Generated<omni::graph::exec::unstable::IExecutionContext_abi>
    : public omni::graph::exec::unstable::IExecutionContext_abi
{
public:
    OMNI_PLUGIN_INTERFACE("omni::graph::exec::unstable::IExecutionContext")

    //! Current execution version. Incremented with each execution of the context.
    //!
    //! @thread_safety See thread safety information in interface description.
    omni::graph::exec::unstable::Stamp getExecutionStamp() noexcept;

    //! Returns `true` if context is currently executing
    //!
    //! See thread safety information in interface description.
    bool inExecute() noexcept;

    //! Returns `true` if the current thread is the one who started this context's execution.
    //!
    //! Note, do not assume that the thread that started the context's execution is the "main" thread.
    //!
    //! @thread_safety See thread safety information in interface description.
    bool isExecutingThread() noexcept;

    //! Main execution method.  Executes the entire execution graph.
    //!
    //! @thread_safety See thread safety information in interface description.
    omni::graph::exec::unstable::Status execute() noexcept;

    //! On-demand execution method.  Executes the given node.
    //!
    //! @thread_safety See thread safety information in interface description.
    omni::graph::exec::unstable::Status executeNode(const omni::graph::exec::unstable::ExecutionPath& upstreamPath,
                                                    omni::core::ObjectParam<omni::graph::exec::unstable::INode> node);

    //! Context initialization. Responsible to propagate initialization to graphs.
    //!
    //! @thread_safety See thread safety information in interface description.
    void initialize();

    //! Access state for a given execution path.
    //!
    //! If the given node is not @c nullptr, a copy of the given path with the node appended will be used as the lookup
    //! key.
    //!
    //! @thread_safety See thread safety information in interface description.
    //!
    //! @warning    This method should be used for read only access by downstream nodes, example accessing graph state
    //!             when executing downstream nodes. Extra care needs to be taken if this state has to be mutated
    //!             concurrently.
    omni::graph::exec::unstable::IExecutionStateInfo* getStateInfo(
        const omni::graph::exec::unstable::ExecutionPath& path,
        omni::core::ObjectParam<omni::graph::exec::unstable::INode> node);

    //! Returns a value from a node's key/value datastore.
    //!
    //! The node from which to grab data is identified by the given path and
    //! node.  The @p node may be @c nullptr.
    //!
    //! The key is used as a look-up in the node's key/value datastore.
    //!
    //! The type of each data item is returned in @p outTypeId.
    //!
    //! @p outPtr will be updated with a pointer to the actual data.
    //!
    //! @p outItemSize store the size of each item in the returned array.
    //!
    //! @p outItemCount contains the number of items returned (i.e. the number
    //! of items @p outPtr points to).  For an array, this will be greater than
    //! 1.
    //!
    //! If the key is not found, @p outPtr is set to @c nullptr and @p
    //! outItemCount is set to 0.
    //!
    //! Accessing the node's key/value datastore is not thread safe.
    //!
    //! An exception is thrown on all other errors.
    void getNodeData(const omni::graph::exec::unstable::ExecutionPath& path,
                     omni::core::ObjectParam<omni::graph::exec::unstable::INode> node,
                     omni::graph::exec::unstable::NodeDataKey key,
                     omni::core::TypeId* outTypeId,
                     void** outPtr,
                     uint64_t* outItemSize,
                     uint64_t* outItemCount);

    //! Sets a value in a node's key/value datastore.
    //!
    //! The node in which to set the data is identified by the given path and
    //! node.  The @p node may be @c nullptr.
    //!
    //! The key is used as a look-up in the node's key/value datastore.
    //!
    //! The type of each data item is set with @p typeId.
    //!
    //! @p data points to an array of data items.
    //!
    //! @p itemSize is the size of each item in the given array.
    //!
    //! @p itemCount contains the number of items pointed to by @p data. For an
    //! array, this will be greater than 1.
    //!
    //! @p deleter is a function used to delete @p data when either a new value
    //! is set at the key or the context is invalidated.  If @p deleter is @c
    //! nullptr, it is up to the calling code to manage the lifetime of the @p
    //! data.
    //!
    //! Accessing the node's key/value datastore is not thread safe.
    //!
    //! An exception is thrown on all other errors.
    void setNodeData(const omni::graph::exec::unstable::ExecutionPath& path,
                     omni::core::ObjectParam<omni::graph::exec::unstable::INode> node,
                     omni::graph::exec::unstable::NodeDataKey key,
                     omni::core::TypeId typeId,
                     void* data,
                     uint64_t itemSize,
                     uint64_t itemCount,
                     omni::graph::exec::unstable::NodeDataDeleterFn* deleter);

    //! Discover all execution paths leading to given definition and invoke given function with each of them.
    //!
    //! Implementation of this interface will cache results to remove the traversal cost for subsequent call. Change in
    //! execution graph topology will cause invalidation of the cache.
    //!
    //! @thread_safety This method is thread-safe and thread-efficient and can be called during execution, as well as
    //! from within the provided @p callback.
    //!
    //! This method must not be called during graph construction.
    //!
    //! @p def definition to look for
    //! @p callback wrapped function into a callback to execute with each path to given definition
    void applyOnEachDef(omni::core::ObjectParam<omni::graph::exec::unstable::IDef> def,
                        omni::core::ObjectParam<omni::graph::exec::unstable::IApplyOnEachFunction> callback) noexcept;

    //! Discover all execution paths leading to definition with the given name and invoke the given function with each
    //! of them
    //!
    //! Implementation of this interface will cache results to remove the traversal cost for subsequent call. Change in
    //! execution graph topology will cause invalidation of the cache.
    //!
    //! @thread_safety This method is thread-safe and thread-efficient and can be called during execution, as well as
    //! from within the provided @p callback.
    //!
    //! This method must not be called during graph construction.
    //!
    //! @p name definition to look for
    //! @p callback wrapped function into a callback to execute with each path to given definition
    void applyOnEachDefWithName(const omni::graph::exec::unstable::ConstName* name,
                                omni::core::ObjectParam<omni::graph::exec::unstable::IApplyOnEachFunction> callback) noexcept;
};

#endif

#ifndef OMNI_BIND_INCLUDE_INTERFACE_DECL

inline omni::graph::exec::unstable::Stamp omni::core::Generated<
    omni::graph::exec::unstable::IExecutionContext_abi>::getExecutionStamp() noexcept
{
    return getExecutionStamp_abi();
}

inline bool omni::core::Generated<omni::graph::exec::unstable::IExecutionContext_abi>::inExecute() noexcept
{
    return inExecute_abi();
}

inline bool omni::core::Generated<omni::graph::exec::unstable::IExecutionContext_abi>::isExecutingThread() noexcept
{
    return isExecutingThread_abi();
}

inline omni::graph::exec::unstable::Status omni::core::Generated<omni::graph::exec::unstable::IExecutionContext_abi>::execute() noexcept
{
    return execute_abi();
}

inline omni::graph::exec::unstable::Status omni::core::Generated<omni::graph::exec::unstable::IExecutionContext_abi>::executeNode(
    const omni::graph::exec::unstable::ExecutionPath& upstreamPath,
    omni::core::ObjectParam<omni::graph::exec::unstable::INode> node)
{
    OMNI_THROW_IF_ARG_NULL(node);
    auto return_ = executeNode_abi(&upstreamPath, node.get());
    return return_;
}

inline void omni::core::Generated<omni::graph::exec::unstable::IExecutionContext_abi>::initialize()
{
    OMNI_THROW_IF_FAILED(initialize_abi());
}

inline omni::graph::exec::unstable::IExecutionStateInfo* omni::core::
    Generated<omni::graph::exec::unstable::IExecutionContext_abi>::getStateInfo(
        const omni::graph::exec::unstable::ExecutionPath& path,
        omni::core::ObjectParam<omni::graph::exec::unstable::INode> node)
{
    omni::graph::exec::unstable::IExecutionStateInfo* out;
    OMNI_THROW_IF_FAILED(getStateInfo_abi(&path, node.get(), &out));
    return out;
}

inline void omni::core::Generated<omni::graph::exec::unstable::IExecutionContext_abi>::getNodeData(
    const omni::graph::exec::unstable::ExecutionPath& path,
    omni::core::ObjectParam<omni::graph::exec::unstable::INode> node,
    omni::graph::exec::unstable::NodeDataKey key,
    omni::core::TypeId* outTypeId,
    void** outPtr,
    uint64_t* outItemSize,
    uint64_t* outItemCount)
{
    OMNI_THROW_IF_ARG_NULL(outTypeId);
    OMNI_THROW_IF_ARG_NULL(outPtr);
    OMNI_THROW_IF_ARG_NULL(outItemSize);
    OMNI_THROW_IF_ARG_NULL(outItemCount);
    OMNI_THROW_IF_FAILED(getNodeData_abi(&path, node.get(), key, outTypeId, outPtr, outItemSize, outItemCount));
}

inline void omni::core::Generated<omni::graph::exec::unstable::IExecutionContext_abi>::setNodeData(
    const omni::graph::exec::unstable::ExecutionPath& path,
    omni::core::ObjectParam<omni::graph::exec::unstable::INode> node,
    omni::graph::exec::unstable::NodeDataKey key,
    omni::core::TypeId typeId,
    void* data,
    uint64_t itemSize,
    uint64_t itemCount,
    omni::graph::exec::unstable::NodeDataDeleterFn* deleter)
{
    OMNI_THROW_IF_ARG_NULL(data);
    OMNI_THROW_IF_FAILED(setNodeData_abi(&path, node.get(), key, typeId, data, itemSize, itemCount, deleter));
}

inline void omni::core::Generated<omni::graph::exec::unstable::IExecutionContext_abi>::applyOnEachDef(
    omni::core::ObjectParam<omni::graph::exec::unstable::IDef> def,
    omni::core::ObjectParam<omni::graph::exec::unstable::IApplyOnEachFunction> callback) noexcept
{
    applyOnEachDef_abi(def.get(), callback.get());
}

inline void omni::core::Generated<omni::graph::exec::unstable::IExecutionContext_abi>::applyOnEachDefWithName(
    const omni::graph::exec::unstable::ConstName* name,
    omni::core::ObjectParam<omni::graph::exec::unstable::IApplyOnEachFunction> callback) noexcept
{
    applyOnEachDefWithName_abi(name, callback.get());
}

#endif

#undef OMNI_BIND_INCLUDE_INTERFACE_DECL
#undef OMNI_BIND_INCLUDE_INTERFACE_IMPL
