minid.bind
This module contains scary template stuff to make it possible to wrap D functions,
classes, and structs and expose them as functions and types in MiniD.
This binding library is not supposed to be the most flexible or capable. For
example, its class wrapping is meant to be usable with classes to whose source
code you don't necessarily have access to, or whose code you can't change (like
in third-party libraries). This library has to sacrifice some efficiency and
capabilities to be able to do this.
However, if you're really only concerned with integrating your own code with
MiniD, something like
might be more appropriate. Xpose allows you to add reflection info to your types
which you can then use to make bindings to MiniD.
License:
Copyright (c) 2008 Jarrett Billingsley
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the
use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software in a
product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not
be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
- void
WrapModule
(char[] name, Members...)(MDThread* t);
- Wraps a module. This registers a custom module loader in the global modules.customLoaders
table of the given thread. The members will not actually be wrapped until the module is imported
the first time.
Template Params:
name = The name of the module, in dotted form (like "foo.bar.baz"). This is the name that will
be used to import it.
Members = A variadic list of things to declare in this module. These will be declared as module
globals, just as if you declared them globals in MiniD. Supported member types include
WrapFunc, WrapNamespace, WrapValue, and WrapType.
Params:
t |
This module's loader will be added into the global modules.customLoaders table accessible
from this thread. |
- void
WrapGlobals
(Members...)(MDThread* t);
- Wraps any number of values into the global namespace accessible from the given thread. This is
the root global namespace, outside of any modules. Works just like WrapModule otherwise.
Supported member types include WrapFunc, WrapNamespace, WrapValue, and WrapType.
The wrapped values are immediately loaded into the global namespace.
- struct
WrapFunc
(alias func);
struct
WrapFunc
(alias func,funcType);
struct
WrapFunc
(alias func,char[] name);
struct
WrapFunc
(alias func,char[] name,funcType);
- Wraps a static function - that is, a function that doesn't have a 'this' parameter. These four
template specializations allow you to fine-tune how the function is to be wrapped.
The first specialization takes just an alias to a function. In this case, the first overload
of the function (if any) will be wrapped and the name of the function in MiniD will be the same
as in D.
The second specialization allows you to explicitly specify a function signature to choose, in the
case that the function you're wrapping is overloaded. The signature should be a function type that
matches the signature of the overload you want to wrap. In this case, though, the name in MiniD
will still be the name of the D function.
The third specialization allows you to rename the function without explicitly selecting an overload.
The fourth specialization allows you to both select an overload and give it the name that should
be used in MiniD. This is the form you'll probably be using most often with overloaded D functions.
If you use one of the two forms where you explicitly specify the function signature, the resulting
wrapped function will only accept exactly as many parameters as are specified in the signature.
Otherwise, the wrapped function will be allowed to have optional parameters.
- struct
WrapNamespace
(char[] name,members...);
- Wraps a bunch of values into a namespace object. This works virtually the same as WrapModule,
except that it's meant to be used as a member of something like WrapModule. Legal member
types include WrapFunc, WrapValue,
WrapNamespace
, and WrapType.
- struct
WrapValue
(char[] name,value...);
- Wraps a single value and gives it a name. Despite the fact that the value parameter is
variadic, it is restricted to exactly one item. It's variadic just so it can accept any
value type.
- struct
WrapType
(Type,char[] name = NameOfType!(Type),Members...);
- Wraps a class or struct type. This supports wrapping constructors (or static opCall for structs),
methods, properties (though they will be functions in MiniD), and arbitrary values. That means
the valid member types are WrapCtors, WrapMethod, WrapProperty, and WrapValue.
Template Params:
Type = The class or struct type to be wrapped.
name = The name that will be given to the type in MiniD.
Members = The members of the type.
BUGS:
Abstract classes cannot be wrapped. D1 does not provide enough reflective information to do so reliably.
- struct
WrapCtors
(T...);
- D doesn't really provide any facilities for introspecting class constructors, so you'll have to specify
to the binding library the signatures of the constructors to expose. You'll also have to do it for structs.
There can be at most one
WrapCtors
inside a WrapType, but since you specify as many constructors as you
want all at once, it doesn't matter. The constructor signatures should be function types; the return type
is ignored, and only the parameter types are significant.
Unlike wrapping other functions, a form of overloading is allowed for constructors. That is, you can have
a constructor that takes (int) and another that takes (float), wrap them as two separate types, and they
will be correctly dispatched when the type is instantiated in MiniD. This also means that the usual
implicit conversion from int to float that happens when calling other functions will not happen when calling
constructors.
- struct
WrapMethod
(alias func);
struct
WrapMethod
(alias func,char[] name);
struct
WrapMethod
(alias func,funcType);
struct
WrapMethod
(alias func,char[] name,funcType);
- Wraps a method of a class or struct type. The argument to this template will look like "A.foo" for a given
type "A". Other than the fact that it's a method (and therefore takes 'this'), this works pretty much
exactly the same as WrapFunction, including the differences between the multiple specializations.
- struct
WrapProperty
(alias func);
struct
WrapProperty
(alias func,char[] name);
struct
WrapProperty
(alias func,funcType);
struct
WrapProperty
(alias func,char[] name,funcType);
- Wraps a D "property." D of course does not have real properties but only syntactic sugar for function
calls. These wrap a pair of functions (or just one function, if the property is read-only) that denote
a property. In MiniD, each property has a method named "prop_name" which does the actual setting and
getting, and the wrapped type is given opField and opFieldAssign metamethods which dispatch field access
to the appropriate property accessors. If you want to override the behavior of setting/getting a property,
you can do so by overriding the "prop_name" method.
The D "property" must be one or two functions (either just a getter or a getter/setter pair). The setter,
if any exists, must be able to take one parameter that is the same type as the getter's return type.
The setter may optionally return a value.
It doesn't matter whether you pass an alias to the setter or the getter to this; the library will figure
out which one you gave and which one it needs. So if you have a property "x" of a type "A", it'll just
be
WrapProperty
!(A.x).
Since this is another variety of function wrapping, the parameters here all do the same thing as for
WrapFunction and WrapMethod.
BUGS:
Currently overridden setters/getters are not called polymorphically and therefore will not be called
by D code accessing the properties.
- int
getWrappedClass
(MDThread* t, TypeInfo ti);
- Given a TypeInfo instance of the desired class/struct type (that is, typeid(SomeType)), pushes
the corresponding wrapped MiniD class, or pushes null if the type has not been wrapped.
You probably won't have to call this function under normal circumstances.
Params:
TypeInfo ti |
The runtime TypeInfo instance of the desired type. |
Returns:
The stack index of the newly-pushed value.
- int
getWrappedClass
(MDThread* t, ClassInfo ci);
- Given a ClassInfo instance of the desired class type, pushes
the corresponding wrapped MiniD class, or pushes null if the type has not been wrapped.
You probably won't have to call this function under normal circumstances.
Params:
ClassInfo ci |
The runtime ClassInfo instance of the desired class. |
Returns:
The stack index of the newly-pushed value.
- int
getWrappedClassOrSuper
(MDThread* t, ClassInfo ci);
- Given a ClassInfo instance of the desired class type, pushes
the corresponding wrapped MiniD class, or pushes null if the type has not been wrapped.
This version looks for a super class if a direct match cannot be found.
You probably won't have to call this function under normal circumstances.
Params:
ClassInfo ci |
The runtime ClassInfo instance of the desired class. |
Returns:
The stack index of the newly-pushed value.
- void
setWrappedClass
(MDThread* t, TypeInfo ti);
- Expects a class object on top of the stack, and sets it to be the MiniD class that corresponds
to the given runtime TypeInfo object. The class object is not popped off the stack.
You probably won't have to call this function under normal circumstances.
- void
setWrappedClass
(MDThread* t, ClassInfo ci);
- Expects a class object on top of the stack, and sets it to be the MiniD class that corresponds
to the given runtime ClassInfo object. The class object is not popped off the stack.
You probably won't have to call this function under normal circumstances.
- int
getWrappedInstance
(MDThread* t, Object o);
- Assuming a valid wrapped class is on the top of the stack, this function will take a D object
and push the corresponding MiniD instance. If a MiniD instance has already been created for
this object, pushes that instance; otherwise, this will create an instance and link it to this
D object. The class is popped off, meaning the wrapped instance takes its place.
You probably won't have to call this function under normal circumstances.
Params:
Object o |
The D object to convert to a MiniD instance. |
Returns:
The stack index of the newly-pushed instance.
- void
setWrappedInstance
(MDThread* t, Object o, int idx);
- For a given D object instance, sets the MiniD instance at the given stack index to be
its corresponding object.
You probably won't have to call this function under normal circumstances.
Params:
Object o |
The D object that should be linked to the given MiniD instance. |
int idx |
The stack index of the MiniD instance that should be linked to the given D object. |
- Type*
checkStructSelf
(Type, char[] FullName)(MDThread* t);
- Checks that the 'this' parameter passed to a native function is an instance of the given struct
type, and returns a pointer to the struct object that is referenced by 'this'.
Template Params:
Type = The D struct type that corresponds to 'this'.
FullName = The name of the type in MiniD, in dotted form.
Returns:
A pointer to the struct object referenced by 'this'.
- Type
checkClassSelf
(Type, char[] FullName)(MDThread* t);
- Checks that the 'this' parameter passed to a native function is an instance of the given class
type, and returns the reference to the D object instance that is referenced by 'this'.
Template Params:
Type = The D class type that corresponds to 'this'.
FullName = The name of the type in MiniD, in dotted form.
Returns:
A reference to the D object instance referenced by 'this'.
- word
superPush
(Type)(MDThread* t, Type val);
- It's
superPush
! It's better than your average push.
This is a templated push function that will take any D type that is convertible to a MiniD type
and push its MiniD conversion onto the stack. This includes not only simple value types, but also
arrays, associative arrays, classes, and structs. Classes and structs are convertible as long as they
have been wrapped. Arrays are convertible as long as their element type is convertible. AAs are
convertible as long as their key and value types are convertible. Arrays will become MiniD arrays,
and AAs will become MiniD tables. Classes and structs will become MiniD instances of the wrapped
MiniD class type.
Returns:
The stack index of the newly-pushed value.
- word
multiPush
(T, U...)(MDThread* t, T arg1, U args);
- Like superPush, but pushes multiple values onto the stack in one function call. Calls superPush
internally, so any types that are legal to pass to superPush are legal to pass to this.
Params:
arg1 |
The first value to push. This is separated to force you to push at least one value. |
args |
Any additional values to push. |
Returns:
The stack index of the first value that was pushed.
- Type
superGet
(Type)(MDThread* t, word idx);
- The inverse of superPush, this function allows you to get any type of value from the MiniD stack
and convert it into a D type. The rules in this direction are pretty much the same as in the other:
a MiniD array can only be converted into a D array as long as its elements can be converted to the
D array's element type, and similarly for MiniD tables.
Strings will also be converted to the correct Unicode encoding. Keep in mind, however, that this
function will duplicate the string data onto the D heap, unlike the raw API getString function.
This is because handing off pointers to internal MiniD memory to arbitrary D libraries is probably
not a good idea.
- void
multiGet
(T, U...)(MDThread* t, word start, ref T arg1, ref U args);
- Like superGet, but gets multiple consecutive values off the stack. There must be at least
as many values after the start index as you have values to get. This calls superGet internally,
so any types that are legal to get with superGet are legal here too.
Params:
start |
The stack index of the first value to retrieve. |
arg1 |
The first value to get. This is separate to force you to get at least one value. |
args |
Any additional values to get. |
- bool
canCastTo
(Type)(MDThread* t, word idx);
- Returns true if the value at the given stack index can be converted to the given D type,
or false otherwise. That's all.
|