ReflectionRegistries.h

// ReflectionRegistries.h
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2022

@import "IObject.h"

namespace ceda
{
@def CEDA_REGISTER_PROJECT =
{
    @def reg = Register_Project_@@@project
    @def unreg = Unregister_Project_@@@project
    void reg();
    reg();
    struct Finally_@@unreg { ~Finally_@@unreg() { void unreg(); unreg(); } } finally_@@unreg;
}

@def mRegistryTypes = [Interface,Class,Variant,Enum,Functor,Typedef,GlobalFunction,GlobalVariable]


$enum+ ENameSpaceError
{
    NSE_OK,
    NSE_COLON_EXPECTED,
    NSE_IDENTIFIER_EXPECTED,
    NSE_NAME_ALREADY_IN_USE,
    NSE_NAME_NOT_FOUND,
    NSE_NOT_A_NAMESPACE
};

@for (rType in mRegistryTypes)
{
    @def R = Reflected@@rType
    @def Reg = Reflected@@rType@@Registry
    @def Ex = R@@NotFoundException

    ///////////////////////////////////////////////////////////////////////////////////////////////////
    @unstr('//') Reg

    struct @api Ex : public IException
    {
        Ex(ConstStringZ fullyQualifiedName) : m_fullyQualifiedName(fullyQualifiedName) {}

        virtual void Write(xostream& os) const
        {
            os << @str(Reflected rType not found : ) << m_fullyQualifiedName;
        }
        
        xstring m_fullyQualifiedName;
    };
    
    // Register the given item.  r must not be nullptr.  r->name must be a fully qualified name
    // using '::' delimiters.  The name must be unique.
    //
    // Possible return values : 
    //      NSE_OK
    //      NSE_COLON_EXPECTED
    //      NSE_IDENTIFIER_EXPECTED
    //      NSE_NAME_ALREADY_IN_USE
    @api ENameSpaceError Register@@R(const R* r, XTarget* target);
    
    // Unregister the given item.  r must not be nullptr.  r must have previously have been 
    // successfully registered
    @api void Unregister@@R(const R* r);
    
    // Write out the entire registry to the given ostream
    @api void Write@@Reg(xostream& os);

    // Returns nullptr on failure to find an entry with the given fully qualified name
    @api const R* TryFind@@R(ConstStringZ fullyQualifiedName);

    // Version that throws an exception if not found
    @api const R& Find@@R(ConstStringZ fullyQualifiedName);

}

/*
Global functions can be registered as through they were member functions of a class.  It is assumed
that the given global function contains a pointer to a class as its first argument.

The namespace in which the global function is defined is completely ignored when it is registered.
Instead, it is registered in a namespace that matches the qualified name of the class associated
with the first argument of the global function.
*/
@api ENameSpaceError RegisterReflectedMemberFunction(const ReflectedGlobalFunction* x);
} // namespace ceda