
1) Big picture.

bingen is mostly for making C++ classes available to Xi. Therefore,
if it tries to wrap C++ type Gadget, it'll try to create an Xi
type Gadget as well.

The Xi type Gadget is represented in C++ land by the type XiGadget,
which includes the wrapped C++ Gadget object, by pointer or value.

All of these XiGadget wrappers are generated to have at least these
2 methods:

vtable() -- returns a pointer to the Xi vtable for the object.
It's a struct of the appropriate type, so everything is named nicely
and typechecked. Since it's the actual Xi vtable, if a Xi subclass
overrides some methods, calling through it will dispatch to the Xi
overrides.

impl() --- returns a pointer to the wrapped C++ object. This method
is also responsible for autoinitialization when subclassed from Xi;
so basically every time one needs state, one should access impl().

Note: destructors will get called when the Xi object is finalized,
but as usual with finalizers, it may take a while.

Converting between Xi and C++ is done via overloads of
fromXi/toXi methods. fromXi is always autogenerated, but you
may need to do toXi manually. (See below).

Normally, when you declare, say, a method T1 foo(T2 p1, T3 p2); in the .idl
file, all the generator does is produce a default implementation with body
that looks like this:

return fromXi(__this->impl()->foo(fromXi(p1), fromXi(p2));

... and stick it into the vtable for XiGadget or such.

Since these methods are static in XiGadget, the instance pointer for
the wrapper is stored into __this.

Now, you can also specify a method body, by writing something like this:

T1 foo(T2 p1, T3 p2) [[
    // body here.
]]

The [[ foo ]] syntax is a code literal, and is basically an escape ---
everything until the ]] goes straight into Xi or C++ code (with some
attempts made to keep indentation sane).

Inside such a body, __this is available, but parameters need to be
demarshalled, and return marshalled, manually.

2) value

value Foo {
}

wraps are meant for value-like C++ classes that are not subclassed
in C++ end (but may be freely subclassed in Xi land) ---
and hence you cannot subclass them in the .idl land, either,
though bindgen doesn't check too hard.

The generator will automatically generate impl(), fromXi(), toXi();
so all you have to do is describe methods, and may be write some
custom bodies (using __this->impl() to access the wrapped object).

As long as impl() gets called, the object will get constructed properly.

Also, if you want to write a constructor method for these, you
may find the gcNew template useful --- gcNew<XiGadget>() will
make an XiGadget, fully construct it, setup finalizer, etc.

3) nopeer

This means you're not actually wrapping anything, so you're
responsible for providing all the method bodies, using
__this to refer to your instance, and manually marshalling/demarshalling
using toXi/fromXi. But you'll get you vtables laid out.

fromXi/toXi/impl() don't make any sense for these.

Like for value, no subclassing for these in C++ land.
(But may be likely in Xi land --- this is how I do event listeners;
 which dispatch via the ->vtable() to Xi overrides)

4) pointer

These are for when you have an inheritance hierarchy in C++ land.
Because of this, you need to provide a couple of instance methods:

getImpl() -- return a pointer to the wrapped object (with appropriate
             subtype)

createImpl() --- initialize the pointer to the wrapped object.
                 This is used when subclassed from Xi. The constructor
                 will have already run when this is called, so the wrapped
                 object is in usable state.

The usual way to do it to use bindH [[ code ]] and bindCPP [[ code ]]
commands to output things to the .h (within the class declaration)
or .cpp file.

fromXi() is generated automatically; but you'll need to write the toXi overload
yourself.

Note that the constructor does not call createImpl() automatically
(though impl()) does, so if you use gcNew<> to make these object,
you may need to call createImpl by hand in the factory/constructor method.


5) Limitations.

It's more a preprocessor than a compiler --- very little semantic
checking is done.

Tuple types aren't understood. Array types are turned into void*
(or was it int*?)
