Variant.cpp

// Variant.cpp
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2011

@import "Store.h"
@import "Ceda/cxObject/PrintReflectedVariable.h"
#include "Ceda/cxUtils/ScopeWriter.h"
#include "Ceda/cxUtils/Environ.h"

namespace VariantEx
{

///////////////////////////////////////////////////////////////////////////////////////////////////
// Example with a variant containing a pref.

$variant+ MyVariant
{
    default -1;
    ceda::int32;
    ceda::pref<ceda::IPersistable>;
};

$struct+ Y <<os>> isa ceda::IPersistable :
    model
    {
        MyVariant V;
        MyVariant W;
    }
{
    Y() {}
    Y(MyVariant v, MyVariant w) 
    {
        _model_.V = v;
        _model_.W = w;
    }
    
    static void Write(ceda::xostream& os, const MyVariant& v)
    {
        if (v.is<ceda::int32>())
        {
            os << v.as<ceda::int32>();
        }
        else
        {
            ceda::pref<ceda::IPersistable> p = v.as<ceda::pref<ceda::IPersistable> >();
            if (p)
            {
                Y* y = ceda::qccast<Y>(p.Get());
                cxAssert(y);
                y->Write(os);
            }
            else
            {
                os << "null";
            }
        }
    }

    void Write(ceda::xostream& os) const
    {
        os << '(';
        Write(os,V);
        os << ',';
        Write(os,W);
        os << ')';
    }
};

/*
Generated output:

    Variant with pref
    {
        root = (((10,20),30),-1)
        root = (((10,20),30),(1,(2,null)))
    }
*/

void VariantWithPref()
{
    ceda::TraceGroup g("Variant with pref");

    ceda::xstring path = ceda::GetCedaTestPath("VariantWithPref.ced");

    {
        Store store(path, ceda::OM_CREATE_ALWAYS);
        Y* root = store.BootstrapRoot<Y>();
    }

    {
        Store store(path);
        Y* root = store.BootstrapRoot<Y>();
        
        {
            ceda::CSpaceTxn txn;

            Y* child2 = $new Y(10,20);
            Y* child = $new Y(MyVariant(child2), 30);

            // These objects just created are not reachable from the persistent store yet so they
            // don't have an OID yet
            cxAssert(!GetOid(child2));
            cxAssert(!GetOid(child));

            cxAssert(!root->IsDirty());
            
            root->V = MyVariant(child);

            // The assignment to V marked root as dirty and allocated oids to the reachable objects.
            cxAssert(root->IsDirty());
            cxAssert(GetOid(child2));
            cxAssert(GetOid(child));
        }
    }
    
    {
        Store store(path);
        Y* root = store.BootstrapRoot<Y>();
        {
            ceda::CSpaceTxn txn;
            Tracer() << "root = " << *root << '\n';
        }
    }
    
    {
        Store store(path);
        Y* root = store.BootstrapRoot<Y>();
        {
            ceda::CSpaceTxn txn;
            
            // todo : $new doesn't support nesting at the moment.
            //root->W = MyVariant( $new Y(1, MyVariant($new Y(2,3))) );

            Y* y = $new Y(2,ceda::pref<ceda::IPersistable>());
            root->W = MyVariant( $new Y(1, MyVariant(y)) );
        }
    }

    {
        Store store(path);
        Y* root = store.BootstrapRoot<Y>();
        {
            ceda::CSpaceTxn txn;
            Tracer() << "root = " << *root << '\n';
        }
    }
}

void Run()
{
    VariantWithPref();
}

};