// SPDX-License-Identifier: MIT
#pragma once
#include <plugin/PluginCatalog.hh>
#include <any>
#include <string>
namespace plugin
{
/**
* @brief Registers a plugin (default-constructible only) into a PluginCatalog
* upon construction and unregisters it upon destruction.
*/
template< class T, class Base >
class PLUGIN_EXPORT PluginRegisterer
{
public:
PluginRegisterer( typename PluginCatalog< Base >::key_type const& name, bool copy = false )
: key( name )
{
Base::catalog( ).insert( key, Creator< Base >( CreateDefault, copy ) );
}
PluginRegisterer( PluginRegisterer&& ) = delete;
~PluginRegisterer( )
{
Base::catalog( ).erase( key );
}
PluginRegisterer& operator=( PluginRegisterer&& ) = delete;
static Base* CreateDefault( ) { return new T( ); }
protected:
PluginRegisterer( ) = default;
PluginRegisterer( PluginRegisterer const& r )
: key( r.key )
{
}
PluginRegisterer& operator=( PluginRegisterer const& r )
{
if( this != &r )
key = r.key;
return *this;
}
protected:
typename PluginCatalog< Base >::key_type key;
};
/**
* @brief Registers a plugin with both default and config-based construction.
*
* The Config type is the concrete struct that the plugin's constructor accepts.
* At creation time, std::any_cast is used to extract the Config — a type
* mismatch throws std::bad_any_cast at runtime.
*
* @tparam T Concrete plugin class
* @tparam Base Base class of the plugin hierarchy
* @tparam Config Configuration struct accepted by T's constructor
*/
template< class T, class Base, class Config >
class PLUGIN_EXPORT PluginRegistererWithConfig
{
public:
PluginRegistererWithConfig( typename PluginCatalog< Base >::key_type const& name,
bool copy = false )
: key( name )
{
Base::catalog( ).insert(
key,
Creator< Base >( CreateDefault, CreateFromConfig, copy ) );
}
PluginRegistererWithConfig( PluginRegistererWithConfig&& ) = delete;
~PluginRegistererWithConfig( )
{
Base::catalog( ).erase( key );
}
PluginRegistererWithConfig& operator=( PluginRegistererWithConfig&& ) = delete;
static Base* CreateDefault( ) { return new T( ); }
static Base* CreateFromConfig( std::any const& cfg )
{
return new T( std::any_cast< Config const& >( cfg ) );
}
protected:
PluginRegistererWithConfig( ) = default;
PluginRegistererWithConfig( PluginRegistererWithConfig const& r )
: key( r.key )
{
}
PluginRegistererWithConfig& operator=( PluginRegistererWithConfig const& r )
{
if( this != &r )
key = r.key;
return *this;
}
protected:
typename PluginCatalog< Base >::key_type key;
};
} // namespace plugin
// -----------------------------------------------------------------------
// Macros
// -----------------------------------------------------------------------
#define PLUGIN_CONCAT_IMPL( a, b ) a##b
#define PLUGIN_CONCAT( a, b ) PLUGIN_CONCAT_IMPL( a, b )
/// Register with default constructor only (backward compatible)
#define REGISTERBYNAME( NAME, CLASS, BASE ) \
namespace \
{ \
static const volatile plugin::PluginRegisterer< CLASS, BASE > \
PLUGIN_CONCAT( REGISTERER_##NAME##_, __LINE__ )( #NAME, false ); \
}
#define REGISTER( CLASS, BASE ) REGISTERBYNAME( CLASS, CLASS, BASE )
/// Register with both default and config-based construction
#define REGISTERBYNAME_WITH_CONFIG( NAME, CLASS, BASE, CONFIG ) \
namespace \
{ \
static const volatile plugin::PluginRegistererWithConfig< CLASS, BASE, CONFIG > \
PLUGIN_CONCAT( REGISTERER_##NAME##_, __LINE__ )( #NAME, false ); \
}
#define REGISTER_WITH_CONFIG( CLASS, BASE, CONFIG ) \
REGISTERBYNAME_WITH_CONFIG( CLASS, CLASS, BASE, CONFIG )
/// Alias registrations
#define REGISTERAS( NAME, CLASS, BASE ) \
namespace \
{ \
static const volatile plugin::PluginRegisterer< CLASS, BASE > \
PLUGIN_CONCAT( REGISTERER_##NAME##_, __LINE__ )( #NAME, true ); \
}
#define REGISTERBYNICK( CNAME, CLASS, BASE ) \
namespace \
{ \
static const volatile plugin::PluginRegisterer< CLASS, BASE > \
PLUGIN_CONCAT( REGISTERERNICK_, __LINE__ )( ( CNAME ), true ); \
}