Code View

plugin / plugin-2.2.0.0 / src / plugin / PluginCreator.hh
// SPDX-License-Identifier: MIT
#pragma once

#include <any>
#include <functional>
#include <stdexcept>

#include <dso/DSOVisibility.hh>

namespace plugin
{
  /**
   * @brief Factory class for plugins.
   *
   * Stores two factory callables:
   *   - A default factory: creates an instance with no arguments
   *   - A config factory:  creates an instance from a type-erased std::any
   *
   * The config factory is optional. If not provided, attempting to create
   * with a config argument will throw std::runtime_error.
   *
   * @tparam Base The base class of the plugin hierarchy
   */
  template< class Base >
  class PLUGIN_EXPORT Creator
  {
    public:
      using DefaultFactory = std::function< Base*( ) >;
      using ConfigFactory  = std::function< Base*( std::any const& ) >;

      Creator( )
        : alias_( true )
      {
      }

      /**
       * @brief Constructor with default factory only (backward compatible).
       */
      Creator( DefaultFactory defaultFn, bool isAlias = false )
        : defaultFactory_( std::move( defaultFn ) ),
          alias_( isAlias )
      {
      }

      /**
       * @brief Constructor with both default and config factories.
       */
      Creator( DefaultFactory defaultFn, ConfigFactory configFn, bool isAlias = false )
        : defaultFactory_( std::move( defaultFn ) ),
          configFactory_( std::move( configFn ) ),
          alias_( isAlias )
      {
      }

      Creator( Creator const& )            = default;
      Creator( Creator&& )                 = default;
      Creator& operator=( Creator const& ) = default;
      Creator& operator=( Creator&& )      = default;
      ~Creator( )                          = default;

      /**
       * @brief Create an instance using the default (parameterless) factory.
       * @return Pointer to new instance, or nullptr if no default factory is set.
       */
      Base* operator( )( )
      {
        return defaultFactory_ ? defaultFactory_( ) : nullptr;
      }

      /**
       * @brief Create an instance using a type-erased config.
       * The config's actual type must match what was registered;
       * a mismatch will throw std::bad_any_cast.
       *
       * @throws std::runtime_error  if no config factory was registered
       * @throws std::bad_any_cast   if the config type doesn't match
       */
      Base* operator( )( std::any const& config )
      {
        if( ! configFactory_ )
        {
          throw std::runtime_error(
            "This plugin was registered without config support. "
            "Use the parameterless create() or register with REGISTER_WITH_CONFIG." );
        }
        return configFactory_( config );
      }

      bool hasConfigFactory( ) const { return static_cast< bool >( configFactory_ ); }

      bool isAlias( ) const { return alias_; }

    private:
      DefaultFactory defaultFactory_;
      ConfigFactory configFactory_;
      bool alias_ = true;
  };
}  // namespace plugin