Skeleton.h

// Skeleton.h
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2020

@import "cxRpc.h"
@import "Ceda/cxObject/Object.h"
#include "Ceda/cxUtils/Archive.h"

namespace ceda
{
class Skeleton;

///////////////////////////////////////////////////////////////////////////////////////////////////
// ISkeletonFactory

struct ISkeletonFactory
{
    virtual Skeleton* CreateSkeleton() = 0;
};

///////////////////////////////////////////////////////////////////////////////////////////////////
// Skeleton factory registry

// The SkeletonFactoryRegistry is a transient registry indexed by fully qualified name of the
// interface.
// This allows the system to automatically generate a suitable skeleton object for a given interface

// The following three functions can be called by different threads - they are fully threadsafe.

// Returns false if skeleton factory has already been registered
@api bool RegisterSkeleton(ConstStringZ qualifiedInterfaceName, ISkeletonFactory* factory);

@api void UnregisterSkeleton(ConstStringZ qualifiedInterfaceName);

// Create a skeleton for the given interface for which a skeleton factory has previously been 
// registered.
// This must be deleted using C++ delete keyword
// Returns nullptr if no skeleton factory for the given interface has been registered.
@api Skeleton* CreateSkeleton(ConstStringZ qualifiedInterfaceName);

///////////////////////////////////////////////////////////////////////////////////////////////////
// Skeleton

typedef void (*SkeletonThunkFn)(void* self);

/*
    template<typename T>
    struct SkeletonThunkFnTable3
    {
        static void sThunk0(void* self) { ((T*)self)->Thunk0(); }
        static void sThunk1(void* self) { ((T*)self)->Thunk1(); }
        static void sThunk2(void* self) { ((T*)self)->Thunk2(); }

        static const SkeletonThunkFn* Table()
        {
            static const SkeletonThunkFn t[] =
            {
                &sThunk0,
                &sThunk1,
                &sThunk2,
            };
            return t;
        }
    };
*/

class Skeleton
{
    cxNotCloneable(Skeleton)
public:
    explicit Skeleton(const SkeletonThunkFn* skeletonThunkFnTable, ssize_t numMethods) : 
        m_ar(nullptr),
        m_skeletonThunkFnTable(skeletonThunkFnTable),
        numMethods(numMethods)
    {
    }

    // Returns read-archive for reading the in-parameters
    inline InputArchive& Pop() { return m_ar; }

    // Test whether the given index is valid
    inline bool ValidIndex(ssize_t index) const { return 0 <= index && index < numMethods; }

    // The ultimate receiver of the messages.   It is assumed this can be reinterpret cast to the
    // interface associated with this Skeleton.
    AnyInterface m_delegate;
    
    InputArchive m_ar;
    const SkeletonThunkFn* m_skeletonThunkFnTable;
    ssize_t numMethods;
};

} // namespace ceda