// 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.
//

//! @file IBackgroundResult.h
//!
//! @brief Defines @ref omni::graph::exec::unstable::IBackgroundResult.
#pragma once

#include <omni/graph/exec/unstable/IBase.h>
#include <omni/graph/exec/unstable/Status.h>
#include <omni/graph/exec/unstable/Types.h>

#include <chrono>

namespace omni
{
namespace graph
{
namespace exec
{
namespace unstable
{

// forward declarations needed by interface declaration
class ExecutionTask;
class IBackgroundResult;
class IBackgroundResult_abi;

//! Class representing a result of asynchronous computation.
//!
//! Create via @ref omni::graph::exec::unstable::IBackgroundTask::getBackgroundResult().
//!
//! Call @ref omni::graph::exec::unstable::IBackgroundResult::isReady() or @ref
//! omni::graph::exec::unstable::IBackgroundResult::waitFor() to make sure the result is ready.  Once the result is
//! ready, call @ref omni::graph::exec::unstable::IBackgroundResult::write() to make the result visible.
//!
//! Operates much like `std::future`.
class IBackgroundResult_abi : public omni::core::Inherits<omni::graph::exec::unstable::IBase,
                                                          OMNI_TYPE_ID("omni.graph.exec.unstable.IBackgroundResult")>
{
protected:
    //! Check if background computation has a result available for consumption.
    //!
    //! @return @c true when it is safe to call omni::graph::exec::unstable::IBackgroundResult::write(), @c false
    //! otherwise.
    //!
    //! Once @ref omni::graph::exec::unstable::IBackgroundResult::write() has been called, this method will return an
    //! error.
    //!
    //! This method is not thread safe.
    //!
    //! May throw.
    virtual OMNI_ATTR("throw_result") omni::core::Result
        isReady_abi(OMNI_ATTR("not_null, throw_if_null, out, *return") bool* ready) noexcept = 0;

    //! Request background processing cancellation
    //!
    //! @param blocking If @c true, this call won't exit until background processing is completed.
    //!
    //! This method is not thread safe.
    //!
    //! May throw.
    virtual OMNI_ATTR("throw_result") omni::core::Result cancel_abi(bool blocking) noexcept = 0;

    //! Write the result.
    //!
    //! This method is not thread safe.
    //!
    //! An error is returned if this method is called more than once.
    //!
    //! May throw.
    virtual OMNI_ATTR("throw_result") omni::core::Result
        write_abi(OMNI_ATTR("in, out, not_null, throw_if_null, ref") ExecutionTask* info,
                  OMNI_ATTR("out, not_null, throw_if_null, *return") Status* out) noexcept = 0;

    //! Waits for the specified time for the result to become ready.
    //!
    //! If the result becomes ready in the specified time (or is already ready) @ref
    //! omni::graph::exec::unstable::BackgroundResultStatus::eReady is returned. Otherwise, @ref
    //! omni::graph::exec::unstable::BackgroundResultStatus::eTimeout is returned.
    //!
    //! This method is not thread safe.
    //!
    //! Returns an error if the result has already been consumed.
    //!
    //! May throw.
    virtual OMNI_ATTR("throw_result") omni::core::Result
        waitFor_abi(uint64_t nanoseconds,
                    OMNI_ATTR("out, not_null, throw_if_null, *return") BackgroundResultStatus* out) noexcept = 0;
};

//! Smart pointer managing an instance of @ref IBackgroundResult.
using BackgroundResultPtr = omni::core::ObjectPtr<IBackgroundResult>;

} // namespace unstable
} // namespace exec
} // namespace graph
} // namespace omni

// generated API declaration
#define OMNI_BIND_INCLUDE_INTERFACE_DECL
#include <omni/graph/exec/unstable/IBackgroundResult.gen.h>

//! @copydoc omni::graph::exec::unstable::IBackgroundResult_abi
//!
//! @ingroup groupOmniGraphExecInterfaces
class omni::graph::exec::unstable::IBackgroundResult
    : public omni::core::Generated<omni::graph::exec::unstable::IBackgroundResult_abi>
{
public:
    //! Waits the specified time for the result to become ready.
    //!
    //! See @ref IBackgroundResult_abi::waitFor_abi().
    template <typename Rep, typename Period>
    BackgroundResultStatus waitFor(std::chrono::duration<Rep, Period> duration)
    {
        return waitFor(std::chrono::duration_cast<std::chrono::nanoseconds>(duration).count());
    }
    using omni::core::Generated<IBackgroundResult_abi>::waitFor;
};

// generated API implementation
#define OMNI_BIND_INCLUDE_INTERFACE_IMPL
#include <omni/graph/exec/unstable/IBackgroundResult.gen.h>
