PathNavigatorBC.h

// PathNavigatorBC.h
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2007

@import "cxObject.h"
@import "IObject.h"
@import "FieldPath.h"
@import "ReflectionByteCode.h"
#include "Ceda/cxUtils/Stream.h"

namespace ceda
{
enum EPathNavigatorMode
{
    // Purpose of path navigation is to get read access to the field
    PNM_READ_ACCESS,

    // Purpose of path navigation is to get write access to the field
    PNM_WRITE_ACCESS,
};

class @api PathNavigatorBC
{
public:
    // Prepare to navigate the field of a datasource located at address 'data'
    // using the given path.
    PathNavigatorBC(const FieldPath& path, void* data, EPathNavigatorMode mode);
    
    // Prepare to iterate through a given path starting from an instance 
    // of a reflected class of type rc, located at address 'data'.
    PathNavigatorBC(const FieldPath& path, void* data, EPathNavigatorMode mode, const ReflectedClass& rc);

    // Navigate the datasource which is of type 'rc'.
    // If a field of type set<Key> is encountered then stop there, even though the 
    // path may include a key into the set.
    // Returns false if the field has been $dropped.
    bool NavigateReflectedClassInstance(const ReflectedClass& rc);
    
    bool AtEnd() const { return ar_ == ar_end_; }
    
    // After navigating the path, gives the address of the field
    void* GetFieldAddress() const { return data_; }
    
    // After navigating the path, can be used to get at the type of the field
    ReflectionByteCode GetFieldType() const { return rbc_; }
    
    // Must only be called after navigating the path and both the following hold:
    //
    //  1)  The field type is a set; and 
    //
    //  2)  It can be assumed that the original path included a key into this set 
    //      (which hasn't been read from the path yet).  
    //
    // Reads the key from the path and either inserts or deletes the key depending
    // on 'ins'.
    void InsertOrDeleteKeyInSet(bool ins);
    
    // Must only be called after navigating the path and both the following hold:
    //
    //  1)  The field type is a set; and 
    //
    //  2)  It can be assumed that the original path included a key into this set 
    //      (which hasn't been read from the path yet).  
    //
    // Reads the key from the path and returns true if the key is currently a member
    // of the set.
    bool IsKeyInSet();

private:
    // Returns false if the field has been $dropped.
    bool NavigateReflectedVariable();

private:
    // Archive used to to deserialise elements of the path
    InputArchive ar_;
    InputArchive ar_end_;
    
    // If the purpose of the path navigation is to perform an operation on a set, then
    // this flag indicates whether an insertion or deletion is to be performed.
    EPathNavigatorMode mode_;

    ReflectionByteCode rbc_;
    octet_t* data_;
};

// Navigate the given path through obj.  Returns address of field and sets rbc to
// the type of the field.
// Returns nullptr if the field has been $dropped
@api void* NavigatePathToField(ptr<IObject> obj, const FieldPath& path, ReflectionByteCode& rbc, bool writeAccess);

} // namespace ceda