Marshall.cpp

// Marshall.cpp
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2007

@import "Ceda/cxPython/cxPython.h"
#include "Ceda/cxUtils/TracerUtils.h"

@def mPrint(v) = print @str(v = ) + `v`

///////////////////////////////////////////////////////////////////////////////////////////////////
/*
This example demonstrates the marshalling of a user defined class/struct by value.  The 
class/struct must be reflected, have a public copy constructor and assignment operator and not be 
declared << -copy >>.
*/

namespace Marshall1
{
    $struct+ X
    {
        X(int val = 15) 
        { 
            v = new int(val);
        }
        X(const X& rhs) 
        { 
            v = new int(*rhs.v);
        }
        X& operator=(const X& rhs)
        {
            if (this != &rhs)
            {
                *v = *rhs.v;
            }
            return *this;
        }
        ~X() 
        { 
            delete v; 
        }
        
        $ceda::int32 GetValue() const { return *v; }

        ceda::int32* v;
    };

	$function+ X ReturnX()
	{
        return X(10);
	}

	$function+ void PassX(X val)
	{
        Tracer() << "PassX() received value " << val.GetValue() << '\n';
	}
	
	void Run()
	{
		ceda::TraceGroup g("Marshall class by value");
		
        PyRun_SimpleString(
            @strx
            (
                Marshall1 = rootnamespace.Marshall1
                x = Marshall1.ReturnX();
                Marshall1.PassX(x)
            ));
	}	
}

///////////////////////////////////////////////////////////////////////////////////////////////////
/*
Marshalling ptr<T>
*/
namespace Marshall2
{
    /////////////////// Interfaces
    
    $interface+ Ix : ceda::IObject
    {
        ceda::int32 GetX() const;
    };

    $interface+ Iy : ceda::IObject
    {
        ceda::int32 GetY() const;
    };

    $interface+ Iz : ceda::IObject
    {
        ceda::int32 GetZ() const;
    };
    
	$function+ void PassIx(ceda::ptr<Ix> ix)
	{
        Tracer() << "PassIx() received x = " << ix->GetX() << '\n';
	}

	$function+ void PassIy(ceda::ptr<Iy> iy)
	{
        Tracer() << "PassIy() received y = " << iy->GetY() << '\n';
	}

	$function+ void PassIz(ceda::ptr<Iz> iz)
	{
        Tracer() << "PassIz() received z = " << iz->GetZ() << '\n';
	}

    //////////////////////////////
    $struct+ X isa Ix,Iy
    {
        X(ceda::int32 x=0,ceda::int32 y=0) : m_x(x), m_y(y) {}
        
        ceda::int32 GetX() const { return m_x; }
        ceda::int32 GetY() const { return m_y; }
        
        ceda::int32 m_x;
        ceda::int32 m_y;
    };
    
    $struct+ Y
    {
        $ceda::ptr<Ix> m_ix;
        $ceda::ptr<Iy> m_iy;
    };
    
    $function+ Y CreateY()
    {
        return Y();
    }

	$function+ ceda::ptr<Ix> ReturnIx()
	{
        return new X(10,20);
	}

    /*
    TODO:
    
    We already have a way to convert a ClassVariableWrapper to a InterfacePtrWrapper 
    
    Need a way to convert a InterfacePtrWrapper to a ClassVariableWrapper
    
    Proposal :  Use getattr() with the name 'self'
    */
	void Run()
	{
		ceda::TraceGroup g("Marshalling ptr<T>");
		
        PyRun_SimpleString(
            @strx
            (
                Marshall2 = rootnamespace.Marshall2
                
                # ---------------------------------------------------------------------------------
                # Return ptr<Ix> by value
                x = Marshall2.ReturnIx();
                mPrint(x)
                mPrint(x.self)
                
                # ---------------------------------------------------------------------------------
                # Pass ptr<Ix> by value
                Marshall2.PassIx(x)

                # ---------------------------------------------------------------------------------
                # Pass ptr<Ix> as ptr<Iy>
                Marshall2.PassIy(x)
                
                # ---------------------------------------------------------------------------------
                # Assign to ptr<Ix> member
                y = Marshall2.CreateY()
                y.m_ix = x
                mPrint(y.m_ix.GetX())

                # ---------------------------------------------------------------------------------
                # Assign to ptr<Iy> member using ptr<Ix>
                y.m_iy = x
                mPrint(y.m_iy.GetY())
                
                # ---------------------------------------------------------------------------------
                # Pass ptr<Ix> as ptr<Iz>
                # This will fail, because x doesnt implement Iz.
                try:
                    Marshall2.PassIz(x)
                except TypeError as e:
                    print("Caught " + type(e).__name__ + ": " + str(e))
                
            ));
	}	
}

///////////////////////////////////////////////////////////////////////////////////////////////////
namespace Marshall
{
    void Run()
    {
        Marshall1::Run();
        Marshall2::Run();
    }
}