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

//! @file
//!
//! @brief Macros for defining a Carbonite interface.
#pragma once

#include "Version.h"

#include <type_traits>

namespace carb
{
//! Defines a descriptor for the plugin interface.
//!
//! In order to get this information from an interface, call the interface's `getInterfaceDesc` function.
struct InterfaceDesc
{
    const char* name = nullptr; //!< Name of the interface.
    Version version = { 0, 0 }; //!< Version of the interface.
};
CARB_ASSERT_INTEROP_SAFE(InterfaceDesc);
} // namespace carb

//! Macro to declare a `struct` as a Carbonite interface.
//!
//! This macro must be used in a public section of the interface `struct`. It is recommended to have it be the first
//! public "member" of the struct.
//!
//! @param name The name of the interface.
//!
//! @param major The major <a href="https://semver.org/">Semantic Version</a> of the interface.  It is recommended to
//! start at `1`.
//! @param minor The minor <a href="https://semver.org/">Semantic Version</a> of the interface.  It is recommended to
//! start at `0`.
//!
//! For plugins that support multiple interface versions through @ref CARB_PLUGIN_IMPL_EX, the @p major and @p minor
//! version represent the highest version available. This version will also be requested immediately after plugin
//! registration and **must** succeed.
//!
//! When using, a trailing semicolon is optional.
//!
//! @note A @p major of `0` has special significance to <a href="https://semver.org/">Semantic Versioning</a>: every
//! iteration of @p minor is also considered a breaking change. However, @ref carb::isVersionSemanticallyCompatible will
//! warn on different \a minor versions if the \a major version is `0`, but still report `true`.
//!
//! See @carb_framework_overview and @carb_interfaces for more information on creating Carbonite plugins.
//! @code{.cpp}
//! // Effective implementation
//! #define CARB_PLUGIN_INTERFACE(name, major, minor)
//!     static constexpr carb::InterfaceDesc getInterfaceDesc()
//!     {
//!         return carb::InterfaceDesc{ name, { major, minor } };
//!     }
//! @endcode
#define CARB_PLUGIN_INTERFACE(name, major, minor)                                                                      \
    /**                                                                                                                \
     * Returns information about this interface. Auto-generated by @ref CARB_PLUGIN_INTERFACE().                       \
     * @returns The @ref carb::InterfaceDesc struct with information about this interface.                             \
     */                                                                                                                \
    static constexpr carb::InterfaceDesc getInterfaceDesc()                                                            \
    {                                                                                                                  \
        return carb::InterfaceDesc{ name, { major, minor } };                                                          \
    }

// note that this needs to be included last to avoid a circular include dependency in
// 'carb/Defines.h'.  A lot of source files and tests depend on 'carb/Interface.h'
// also pulling in 'carb/Defines.h'.  Since nothing here strictly requires 'Defines.h',
// we'll just defer it's include until everything else useful in here has been defined.
#include "Defines.h"
