Extending Dao VM


In the help entry daovm.interface.embedding, it has been  demonstrated that embedding Da
o is extremely simple. Here we will demonstrate that extending Dao is also extremely simp
le. Since Dao supports explicit type specification in function parameter lists, you will 
not need to write a lot of boilerplate codes to check and  convert function parameters fr
om Dao data types to C/C++ data types. This means writing wrapping functions (Dao-callabl
e C functions)  is significantly simpler than writing wrapping functions for other langua
ges such as Python or even Lua.

 1   The First Simple Extending Module     
 1   The First Simple Extending Module     
 1   The First Simple Extending Module     

 1.1   Extension Function Prototype  

All Dao-callable C functions must have prototype similar to the following example, 
   1  void MyCFunction( DaoProcess *proc, DaoValue *param[], int nparam )
   2  {
   3      printf( "Hello Dao!\n" );
   4  }

 1.2   Module Entry Function  

Each Dao extending module must provide an entry function. The following "DaoOnLoad" is th
e basic form of the entry function name, which may also include the module name. 
   1  // Entry function for each C/C++ module:
   2  int DaoOnLoad( DaoVmSpace *vmspace, DaoNamespace *ns );
This function will be called automatically to allow the module to register its functions 
and types etc. The first parameter is the DaoVmSpace instance which is responsible for lo
ading and managing the module. And the second parameter is the namespace object that will
represent this module, so all the functions and types etc. should be registered to this n

As mentioned above, the name of the entry function may also include the module name. Supp
ose the module name is "abc" and may appear in load statements as  load abc or load path.
abc, the module name can appear in the entry function name in the following forms and is 
also searched in this order: 
  1. All lower case letters: e.g. Daoabc_OnLoad;
  2. First upper case letter: e.g. DaoAbc_OnLoad;
  3. All upper case letters: e.g. DaoABC_OnLoad; 

 1.3   Function Registeration  

To register functions to a namespace, one can use one of the following interface function
s of DaoNamespace, 
   1  // Function to register a single function:
   2  DaoRoutine*
   3  DaoNamespace_WrapFunction( DaoNamespace *self, DaoCFunction fp, const char *proto );
   5  // Function to register multiple functions:
   6  int DaoNamespace_WrapFunctions( DaoNamespace *self, DaoFunctionEntry *items );
We will come to the second function later. For the first function, the first parameter is
the namespace to which the function is registering to; the second is the function pointer
to the function that needs to be registered (MyCFunction in this case); and the last para
meter is the Dao function prototype for the registered function.

So you can register the above function MyCFunction as the following, 
   1  // Register function:
   2  DaoNamespace_WrapFunction( nspace, MyCFunction, "HelloDao()" );
So that this function can be called in Dao by name HelloDao without any parameter.

 1.4   Summary  

To sum it up, the simplest Dao extending module could be the following, 
   1  #include "dao.h"
   2  #include "stdio.h"
   3  static void MyCFunction( DaoProcess *proc, DaoValue *param[], int nparam )
   4  {
   5      printf( "Hello Dao!\n" );
   6  }
   7  int DaoOnLoad( DaoVmSpace *vmspace, DaoNamespace *nspace )
   8  {
   9      DaoNamespace_WrapFunction( nspace, MyCFunction, "HelloDao()" );
  10      return 0;
  11  }
To compile it, you will need to add the Dao header file path to your compiling option. An
d you will also need to add the following preprocessor definitions: 
  *  On Win32: WIN32;
  *  On Unix: UNIX;
  *  On Mac OSX: MACOSX; 
For linking, on Windows you will need to link the module against the Dao library. But on 
the other platforms, you can simply use the following flags, 
  *  On Unix: -rdynamic;
  *  On Mac OSX: -undefined dynamic_lookup; 
If you use DaoMake (tool.standard.daomake) to build your modules, these will be taken car
e of automatically.

 2   The Second Simple Extending Module     
 2   The Second Simple Extending Module     
 2   The Second Simple Extending Module     

Now we will demonstrate how to wrap a function that can accept parameters and return a va
lue. Suppose we want to wrap the following C function, 
   1  float Test( int id, const char *name, int extra );
and support a default value for the last parameter "extra". Then we would need to registe
r the function with the following Dao function prototype, 
   1  # Dao function prototype
   2  MyTest( id: int, name: string, extra = 0 ) => float
So this function will take an integer parameter, a string parameter and  an extra integer
parameter with default value. This prototype also indicates that it will return a float.

In the C wrapping function, it is very easy to convert Dao data type to C data type, and 
to return C data type to Dao, 
   1  void MyTestInC( DaoProcess *proc, DaoValue *param[], int nparam )
   2  {
   3      daoint id = param[0]->xInteger.value;
   4      char *name = param[1]->xString.value->chars;
   5      daoint extra = param[2]->xInteger.value;
   6      DaoProcess_PutFloat( proc, Test( id, name, extra ) );
   7  }
As you can see, you can just get the data without boilerplate codes  to check the number 
of parameters or the type of parameters. When Dao programs invoke this function, it is gu
aranteed to pass parameter values with correct types to the function.

But to convert the data in the above way, you may need to include extra header files such
as daoValue.h in your module source file. And you may also need to be familiar with the s
tandard Dao data type structures (it is simple actually). If you only want to use the API
s from the dao.h header file, you may need to used those DaoValue_TryGetXXX() functions w
hich do some mininum data type checking with little overheads and return the proper C dat
   1  void MyTestInC( DaoProcess *proc, DaoValue *param[], int nparam )
   2  {
   3      daoint id = DaoValue_TryGetInteger( param[0] );
   4      char *name = DaoValue_TryGetChars( param[1] );
   5      daoint extra = DaoValue_TryGetInteger( param[2] );
   6      DaoProcess_PutFloat( proc, Test( id, name, extra ) );
   7  }
If you register the function with proper Dao function prototype, the type checking will a
lways succeed and correct data will always be obtained. The DaoProcess_PutFloat() is for 
returning a float value at a proper location as the returned value of the C function. Ple
ase see the following section(s) for more details.

Now this function can be registered as: 
   1  // Register a function with parameters and returned value:
   2  DaoNamespace_WrapFunction( nspace, MyTestInC, "MyTest(id:int,name:string,extra=0)=>float" );

 3   Type Wrapping     
 3   Type Wrapping     
 3   Type Wrapping     

In Dao virtual machine, a Dao data type is usually represented by three structures: 
  *  DaoType:  The high level representation of the type for type matching and checking;
  *  DaoTypeKernel:  The middle level representation of the type for holding the wrapped 
     values and methods,  or specialized methods for some generic types;
  *  DaoTypeCore:  The low level representation of the type for specifying the basic info
     rmation,  type checking, running time execution, copying, comparison, hashing, print
     ing,  printing, deletion and garbage collection behaviours; 

The first two structures are usually generated automatically from the last one. For wrapp
ing C/C++ types, you only need to define the DaoTypeCore structure.

 3.1   Type Definition Structure  

The type definition structure DaoTypeCore is defined as the following: 
   1  struct DaoTypeCore
   2  {
   3      const char        *name;      // Name of the type;
   4      int                size;      // Size of the value structure;
   5      DaoTypeCore       *bases[8];  // Type cores for the base types;
   6      DaoNumberEntry    *numbers;   // Member numbers;
   7      DaoFunctionEntry  *methods;   // Member methods;
   9      DaoType* (*CheckGetField)( DaoType *self, DaoString *field, DaoRoutine *rout );
  10      DaoValue* (*DoGetField)( DaoValue *self, DaoString *field, DaoProcess *proc );
  12      int (*CheckSetField)( DaoType *self, DaoString *field, DaoType *value, DaoRoutine *rout );
  13      int (*DoSetField)( DaoValue *self, DaoString *field, DaoValue *value, DaoProcess *proc );
  15      DaoType*  (*CheckGetItem)( DaoType *self, DaoType *index[], int N, DaoRoutine *rout );
  16      DaoValue* (*DoGetItem)( DaoValue *self, DaoValue *index[], int N, DaoProcess *proc );
  18      int (*CheckSetItem)( DaoType *self, DaoType *index[], int N, DaoType *value, DaoRoutine *rout );
  19      int (*DoSetItem)( DaoValue *self, DaoValue *index[], int N, DaoValue *value, DaoProcess *proc );
  21      DaoType* (*CheckUnary)( DaoType *self, DaoVmCode *op, DaoRoutine *rout );
  22      DaoValue* (*DoUnary)( DaoValue *self, DaoVmCode *op, DaoProcess *proc );
  24      DaoType* (*CheckBinary)( DaoType *self, DaoVmCode *op, DaoType *operands[2], DaoRoutine *rout );
  25      DaoValue* (*DoBinary)( DaoValue *self, DaoVmCode *op, DaoValue *operands[2], DaoProcess *proc );
  27      DaoType*  (*CheckConversion)( DaoType *self, DaoType *type, DaoRoutine *rout );
  28      DaoValue* (*DoConversion)( DaoValue *self, DaoType *type, int copy, DaoProcess *proc );
  30      DaoType* (*CheckForEach)( DaoType *self, DaoRoutine *rout );
  31      int (*DoForEach)( DaoValue *self, DaoTuple *iterator, DaoProcess *proc );
  33      void (*Print)( DaoValue *self, DaoStream *stream, DMap *cycmap, DaoProcess *proc );
  34      void (*Slice)( DaoValue *self );
  35      int (*Compare)( DaoValue *self, DaoValue *other, DMap *cycmap );
  36      size_t (*Hash)( DaoValue *self );
  37      DaoValue* (*Create)( DaoType *self );
  38      DaoValue* (*Copy)( DaoValue *self, DaoValue *target );
  39      void (*Delete)( DaoValue *self );
  40      void (*HandleGC)( DaoValue *self, DList *values, DList *lists, DList *maps, int remove );
  41  };

The type definition structure DaoTypeCore not only defines the basic information for the 
type, but also includes some function pointers that perform some standard operations on t
he type.

Some of these function pointers are grouped into pairs per operation, where the first is 
the type checking function used at compiling time, and the second is the execution functi
on called at running time to do the operation. The type checking function should return t
he resulting type on success and null otherwise.

For user defined types, the default implementations are provided and declared as DaoCstru
ct_CheckXXX() and DaoCstruct_DoXXX() functions in this file. These default implementation
s use operator overloading from the member methods to do type checkings and running time 

At running time, the executing DaoProcess object is usually passed to the execution funct
ions, so that these functions can put the resulting values directly on the process stack.
Otherwise, they should just return the results, and let the VM to put them on the stack i
f necessary.

 3.1.1  Type Registraction 

A C/C++ type can be used in Dao if only if it is registered in a Dao namespace with a typ
e definition structure DaoTypeCore through, 
   1  DaoType* DaoNamespace_WrapType( DaoNamespace *self, DaoTypeCore *core, int tid, int options );
   2  int DaoNamespace_WrapTypes( DaoNamespace *self, DaoTypeCore *core[] );
The tid parameter must be set to  DAO_CSTRUCT for customized types, or DAO_CDATA for opaq
ue wrapper types. The options parameter can be set to either 0 or DAO_CTYPE_INVAR for inv
ariable types.

There are two ways to extend Dao with user defined C/C++ types. One is to wrap it around 
by a DaoCdata object, and access it as an opaque pointer. This is the standard way to wra
p existing C/C++ types. The other is to define a customized C type, and use it in the sam
e way as the first. A customized C type is a C structure sharing the same header fields a
s DaoCdata, which can make sharing types between Dao and C simpler (especially for garbag
e collection). Wrapped C/C++ types and customized C types can be added to Dao in almost t
he identical way, so I will introduce the wrapped types first, and then the customized ty
pes should be very easy to understand.

Dao interface types can also be defined in C/C++ extensions. To define interface types, y
ou need to defined type definition structions in a similar way as the above wrapped C/C++
data types. And then wrap them using, 
   1  DaoType* DaoNamespace_WrapInterface( DaoNamespace *self, DaoTypeCore *core );
   2  DaoType* DaoNamespace_WrapCinType( DaoNamespace *self, DaoTypeCore *c, DaoType *a, DaoType *t );
See bellow for example.

 3.1.2  Member constant numbers and methods 

The third field numItems can be used to specify a list of member constant numbers, which 
are defined in an array of the following structure: 
   1  struct DaoNumberEntry
   2  {
   3      const char *name;   /* contant name; */
   4      int         type;   /* number type; */
   5      double      value;  /* number value; */
   6  };
The number type should be one of DAO_INTEGER, DAO_FLOAT and DAO_DOUBLE. The array should 
be terminated with a item with null name: 
   1  static DaoNumberEntry myTypeNumbers[] =
   2  {
   3      { "MODE_ONE", DAO_INTEGER, MODE_ONE },
   4      { "MODE_TWO", DAO_INTEGER, MODE_TWO },
   5      { NULL, 0, 0 }
   6  };
If the type has no member constant numbers, it can be simply set to NULL.

The fourth field funcItems can be used to specify a list of member methods, which are def
ined in an array of the following structure: 
   1  struct DaoFunctionEntry
   2  {
   3      DaoCFunction  fpter;  /* C function pointer; */
   4      const char   *proto;  /* function prototype: name( parlist ) => return_type */
   5  };
where the two fields fpter and proto should be the same as they would in the parameter li
st of: 
   1  DaoRoutine*
   2  DaoNamespace_WrapFunction( DaoNamespace *self, DaoCFunction fp, const char *proto );

 3.1.3  Base types and casting functions 

The fifth field supers can be use to expose the inheritance structure of C/C++ types to D
ao. To do this, one just need to set the supers array to the type definition structures o
f the parent types, and terminate the array with a NULL pointer.

If the wrapped type is a C++ class with virtual method(s) or virtual base(s), Dao will ne
ed to know how to cast this type to and from its parent type properly. This can be done b
y specifying a list of cast functions in the sixth field casts of the type structure.

If the C++ class has virtual method(s) but no virtual base(s), the cast function should b
e provided in the following form, 
   1  void* cast_Sub_Base( void *data, int down_casting )
   2  {
   3      if( down_casting ) return static_cast<Sub*>( (Base*)data );
   4      return dynamic_cast<Base*>( (Sub*)data );
   5  }
And if the C++ class has virtual base(s), the cast function should be like, 
   1  void* cast_Sub_Base( void *data, int down_casting )
   2  {
   3      if( down_casting ) return dynamic_cast<Sub*>( (Base*)data );
   4      return dynamic_cast<Base*>( (Sub*)data );
   5  }

 3.1.4  Deallocation and GC handling 

To be updated
If the C/C++ type should not be deallocated by the standard C function free(), a customiz
ed deallocation function must be specified for the type structure. For wrapped C/C++ type
s, the self parameter passed to the deallocation function will be the opaque C/C++ pointe
r, and for customized C types, it will be the whole objects that have the same header fie
lds as DaoCdata.

The last field GetGCFields can be normally set to NULL. But if the C/C++ type may retain 
reference(s) to Dao data structures that can form potentially cyclic referencing relation
ships, this field must be set to a proper function. The main purpose of this function is 
to expose the references retained by the C/C++ type to Dao garbage collector. In this fun
ction, the pointers of Dao data that are directly referenced by the C/C++ type should be 
pushed to the values parameters; and for Dao data that are referenced through DList struc
tures, these DList structures should be pushed into the lists; and for those that are ref
erenced through DMap structures, these DMap structures should be pushed into the maps.

This function is called with a zero remove parameter automatically by  the garbage collec
tor (GC) when an object of the C/C++ type needs to be scanned to determine  if it is no l
onger reachable from the program. It is also called before the object is deallocated by t
he GC, this time the remove parameter is set to one, and in this case, the GetGCFields mu
st break the references that are pushed into the values, lists and maps lists. This is ne
cessary, because some of the objects referenced by the C/C++ object can be deallocated by
the GC, breaking references to them will avoid posible double deletion.

 3.2  A simple example 

Given the following C++ class, 
   1  class ClassOne
   2  {
   3      public:
   4      int  value;
   6      enum{ CLASSONE_AA, CLASSONE_BB };
   8      ClassOne( int v );
  10      int Method( const char *s );
  11  };
It can be wrapped in the following way, 
   1  // Declare the wrapper functions first:
   2  static void dao_ClassOne_ClassOne( DaoProcess *proc, DaoValue *p[], int n );
   3  static void dao_ClassOne_Method( DaoProcess *proc, DaoValue *p[], int n );
   4  // List of constant member numbers for the enums:
   5  static DaoNumberEntry ClassOneNumbers[] =
   6  {
   9      { NULL, 0, 0 }
  10  };
  11  // List of member constructors or methods of ClassOne:
  12  static DaoFunctionEntry ClassOneMethods[] =
  13  {
  14      // Methods with the same name as the type name are constructors:
  15      { dao_ClassOne_ClassOne,  "ClassOne( v: int )" },
  16      { dao_ClassOne_Method,    "Method( self: ClassOne, s: string ) => int" },
  17      { NULL, NULL }
  18  };
  19  static void ClassOne_Delete( void *self )
  20  {
  21      delete (ClassOne*) self;
  22  }
  23  // The type definition structure for ClassOne:
  24  static DaoTypeCore ClassOne_Typer = 
  25  {
  26      "ClassOne", NULL, ClassOneNumbers, ClassOneMethods,
  27      {NULL}, {NULL}, ClassOne_Delete, NULL
  28  };
  29  // The Dao type structure for ClassOne:
  30  DaoType *dao_type_ClassOne = NULL;
  32  static void dao_ClassOne_ClassOne( DaoProcess *proc, DaoValue *p[], int n )
  33  {
  34      // Get the integer parameter;
  35      daoint v = DaoValue_TryGetInteger( p[0] );
  36      // Create a ClassOne instance:
  37      ClassOne *self = new ClassOne( v );
  38      // Wrap the instance with Dao type structure:
  39      DaoProcess_PutCdata( proc, self, dao_type_ClassOne );
  40  }
  41  static void dao_ClassOne_Method( DaoProcess *proc, DaoValue *p[], int n )
  42  {
  43      // Get the ClassOne instance:
  44      ClassOne *self = (ClassOne*) DaoValue_TryCastCdata( p[0], dao_type_ClassOne );
  45      // Get the string parameter:
  46      char *s = DaoValue_TryGetChars( p[1] );
  47      int res = self->Method( s );
  48      // Return the integer result:
  49      DaoProcess_PutInteger( proc, res );
  50  }
  51  int DaoOnLoad( DaoVmSpace *vmSpace, DaoNamespace *nspace )
  52  {
  53      // Wrap ClassOne as an opaque C/C++ type:
  54      dao_type_ClassOne = DaoNamespace_WrapType( nspace, & ClassOne_Typer, 1 );
  55      return 0;
  56  }

Since the value member of ClassOne is a public member, it is reasonable to add a getter a
nd a setter method to wrapped ClassOne type. To add a getter, one only needs to register 
a method with name .field and no extra parameter. And for a setter, the method name must 
be .field=, and it must also accept a parameter with type the same as the value  that can
be assigned. For example, for the value member, one can added the following to the 
ClassOneMethods list, 
   1  // the getter and setter:
   2      { dao_ClassOne_GETF_value,  ".value( self: ClassOne ) => int" },
   3      { dao_ClassOne_SETF_value,  ".value=( self: ClassOne, value: int )" },
Here the name dao_ClassOne_GETF_value  and dao_ClassOne_SETF_value are completely arbitra
ry. They can be implemented in the following way, 
   1  static void dao_ClassOne_GETF_value( DaoProcess *proc, DaoValue *p[], int n )
   2  {
   3      ClassOne *self = (ClassOne*) DaoValue_TryCastCdata( p[0], dao_type_ClassOne );
   4      DaoProcess_PutInteger( proc, self->value );
   5  }
   6  static void dao_ClassOne_SETF_value( DaoProcess *proc, DaoValue *p[], int n )
   7  {
   8      ClassOne *self = (ClassOne*) DaoValue_TryCastCdata( p[0], dao_type_ClassOne );
   9      self->value = DaoValue_TryGetInteger( p[1] );
  10  }

 3.3  An advanced example 

Now given the following class that is derived from ClassOne, 
   1  class ClassTwo : public ClassOne
   2  {
   3      public:
   4      virtual void VirtualMethod( int i, float f );
   5  };
Because this class has a virtual method, if we want Dao classes can be derived from 
ClassTwo and reimplement its virtual functions, the wrapping will be a bit more sophistic
ated. First, we will need to define a "proxy" class that is derived from ClassTwo and rei
mplements its virtual function  such that this reimplemented function can check for a Dao
reimplementation of the function and invoke it if it exists. When an instance of ClassTwo 
needs to be created, an instance of this proxy class will be created and returned instead
of the original ClassTwo.

Here is an example of such proxy class, 
   1  class Dao_ClassTwo : public ClassTwo
   2  {
   3      public:
   5      DaoCdata *dao_cdata;
   7      Dao_ClassTwo();
   8      ~Dao_ClassTwo();
  10      int VirtualMethod( int i, float f );
  11  };
This proxy class will need to maintain a reference to the wrapper object, so an extra fie
ld dao_cdata is declared in the class. This wrapper object can be pre-allocated in the co
nstructor of Dao_ClassTwo, 
   1  Dao_ClassTwo::Dao_ClassTwo()
   2  {
   3      dao_cdata = DaoCdata_New( dao_type_ClassTwo, this );
   4      DaoGC_IncRC( (DaoValue*)dao_cdata );
   5  }
Here the dao_type_ClassTwo is the Dao type object for ClassTwo, and can be obtained in th
e same way as dao_type_ClassOne. Now that Dao_ClassTwo has a reference to a DaoCdata obje
ct, the GetGCFields field of the type definition structure for ClassTwo should be set to 
a proper function, which will be provided later. The destructor should also be handled th
is reference properly by, 
   1  Dao_ClassTwo::~Dao_ClassTwo()
   2  {
   3      if( dao_cdata ){ // Could have been set to NULL by the GC:
   4          // Set the opaque pointer of dao_cdata to NULL, so that the deallocator
   5          // of DaoCdata will not attempt to call the deallocator of the opaque pointer:
   6          DaoCdata_SetData( dao_cdata, NULL );
   7          DaoGC_DecRC( (DaoValue*) dao_cdata );
   8      }
   9  }

Then the VirtualMethod() could be implemented in the following way, 
   1  int Dao_ClassTwo::VirtualMethod( int i, float f )
   2  {
   3      DaoVmSpace *vmspace = DaoVmSpace_MainVmSpace();
   4      DaoProcess *proc = NULL;
   6      // Try to get the instance of a derived Dao class:
   7      DaoObject *object = DaoCdata_GetObject( dao_cdata );
   8      if( object == NULL ) goto CallDefault;
  10      // Try to get a method named "VirtualMethod":
  11      DaoRoutine *method = DaoObject_GetMethod( object, "VirtualMethod" );
  12      if( method == NULL ) goto CallDefault;
  14      // Check if the method is a C/C++ wrapper function:
  15      if( DaoRoutine_IsWrapper( method ) ) goto CallDefault;
  17      // Acquire a process object to execute the re-implemented virtual function:
  18      proc = DaoVmSpace_AcquireProcess( vmspace );
  20      // Prepare function call parameters:
  21      DaoProcess_NewInteger( proc, i );
  22      DaoProcess_NewFloat( proc, f );
  23      DaoValue **params = DaoProcess_GetLastValues( proc, 2 );
  25      // Resolve possible overloading using the parameters:
  26      method = DaoRoutine_ResolveByValue( method, object, params, 2 );
  27      if( method == NULL ) goto CallDefault;
  29      // Run the re-implemented function:
  30      if( DaoProcess_Call( proc, method, object, params, 2 ) ) goto ErrorCall;
  32      // Check the returned value:
  33      DaoValue *res = DaoProcess_GetReturned( proc );
  34      if( DaoValue_CastInteger( res ) ) goto ErrorCall;
  36      int ires = DaoValue_TryGetInteger( res );
  38      // Release the process object:
  39      DaoProcess_Release( vmspace, proc );
  41      return ires;
  43  CallDefault:
  44      if( proc ) DaoProcess_Release( vmspace, proc );
  45      return ClassTwo::VirtualMethod( i, f );
  46  ErrorCall:
  47      DaoProcess_Release( vmspace, proc );
  48      return 0;
  49  }

Now we will define a function that can be set to the GetGCFields field of the type defini
tion structure of ClassTwo. 
   1  static void Dao_ClassTwo_GetGCFields( void *self0,
   2          DList *values, DList *lists, DList *maps, int remove )
   3  {
   4      Dao_ClassTwo *self = (Dao_ClassTwo*) self0;
   5      if( self->dao_cdata == NULL ) return;
   6      DList_Append( values, self->dao_cdata );
   7      if( removeĀ ){
   8          // Parameter "remove" is zero, when this function is called by the
   9          // garbage collector during the phase when the candidate garbage
  10          // objects are scanned to determine true garbage objects.
  11          //
  12          // For true garbage objects for wrapped types, this function will be
  13          // called again with non-zero "remove" parameter. And in this case,
  14          // the "dao_cdata" field should be set to NULL here, since it will be
  15          // deleted by the garbage collector directly.
  16          //
  17          // Care must be taken if there is something else that is responsible
  18          // for deallocating the wrapped C/C++ object. For example, in some GUI
  19          // libraries, the parent widget will be responsible for deleting its
  20          // children widgets. To prevent the deallocator of the wrapped C/C++
  21          // objects from being invoked by Dao garbage collector, something like
  22          // the following can be used:
  23          // if( self->parent() ) DaoCdata_SetData( self->dao_cdata, NULL );
  25          // After this call, "dao_cdata" may become invalid, now set it to NULL
  26          // to avoid wrong using:
  27          self->dao_cdata = NULL;
  28      }
  29  }

The remaining part for wrapping ClassTwo should be something like, 
   1  static void dao_ClassTwo_ClassTwo( DaoProcess *proc, DaoValue *p[], int n )
   2  {
   3      Dao_ClassTwo *self = new Dao_ClassTwo();
   4      DaoProcess_PutValue( proc, (DaoValue*) self->dao_cdata );
   5  }
   6  static DaoFunctionEntry ClassTwoMethods[] =
   7  {
   8      { dao_ClassTwo_ClassTwo,  "ClassTwo()" },
   9      { NULL, NULL }
  10  };
  11  static void Dao_ClassTwo_Delete( void *self )
  12  {
  13      delete (Dao_ClassTwo*) self;
  14  }
  15  static void* Dao_ClassTwo_Cast_ClassOne( void *data, int down )
  16  {
  17      if( down ) return static_cast<ClassTwo*>((ClassOne*)data);
  18      return dynamic_cast<ClassOne*>((ClassTwo*)data);
  19  }
  20  // The type definition structure for ClassTwo:
  21  static DaoTypeCore ClassTwo_Typer = 
  22  {
  23      "ClassTwo", NULL, NULL, ClassTwoMethods,
  24      { & ClassOne_Typer, NULL },
  25      { Dao_ClassTwo_Cast_ClassOne, NULL },
  26      Dao_ClassTwo_Delete, NULL
  27  };
  28  // The Dao type structure for ClassTwo:
  29  DaoType *dao_type_ClassTwo = NULL;
  31  int DaoOnLoad( DaoVmSpace *vmSpace, DaoNamespace *nspace )
  32  {
  33      ...
  34      // Wrap ClassTwo as an opaque C/C++ type:
  35      dao_type_ClassTwo = DaoNamespace_WrapType( nspace, & ClassTwo_Typer, 1 );
  36      return 0;
  37  }

 4   Data Conversion between Dao and C/C++     
 4   Data Conversion between Dao and C/C++     
 4   Data Conversion between Dao and C/C++     

Dao provides various C interface functions to make data conversion between Dao and C/C++ 
simple. For simple data types, one can use the one of the following functions to convert 
Dao values to C values, 
   1  dao_integer DaoValue_TryGetInteger( DaoValue *self );
   2  dao_float   DaoValue_TryGetFloat( DaoValue *self );
   3  dao_complex DaoValue_TryGetComplex( DaoValue *self );
   4  char*     DaoValue_TryGetChars( DaoValue *self );
   5  DString*  DaoValue_TryGetString( DaoValue *self );
   6  int       DaoValue_TryGetEnum( DaoValue *self );
   8  void*     DaoValue_TryGetCdata( DaoValue *self );
   9  void**    DaoValue_TryGetCdata2( DaoValue *self );
  10  void*     DaoValue_TryCastCdata( DaoValue *self, DaoType *totype );
If the DaoValue object is of the requested type, the correct data will be returned, other
wise zero or a null pointer is return. The last three functions are execlusively for opaq
uely wrapped C/C++ types.

For other data types, you may need to cast DaoValue objects to proper types, and then use
proper methods to retrieve C data values. There are two ways to cast from DaoValue to oth
er types, one is to use DaoValue_Type() to check its type and than do C casting, the othe
r is to use one of the DaoValue_CastXXX() series of methods. For example, the following a
re the two ways to cast value  from DaoValue to DaoTuple, 
   1  DaoTuple *tup1 = DaoValue_Type( value ) == DAO_TUPLE ? (DaoTuple*) value : NULL;
   2  DaoTuple *tup2 = DaoValue_CastTuple( value );
DaoValue_CastXXX() methods will return NULL, if the value is not the correct type.