
1) Big picture.

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

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

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

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

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

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

Converting between IX and C++ is done via overloads of
fromIX/toIX methods. fromIX is always autogenerated, but you
may need to do toIX 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 fromIX(__this->impl()->foo(fromIX(p1), fromIX(p2));

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

Since these methods are static in IXGadget, 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 IX 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 IX 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(), fromIX(), toIX();
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<IXGadget>() will
make an IXGadget, 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 toIX/fromIX. But you'll get you vtables laid out.

fromIX/toIX/impl() don't make any sense for these.

Like for value, no subclassing for these in C++ land.
(But may be likely in IX land --- this is how I do event listeners;
 which dispatch via the ->vtable() to IX 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 IX. 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.

fromIX() is generated automatically; but you'll need to write the toIX 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*?)
