This document specifies all rules bindgen uses to do conversions. All have an assigned paragraph number for easy referencing.
Rules should have one (or more) examples, showcasing its implications.
Methods for which no other sub-rule applies have their name underscored:
addWidget() -> #add_widget
A getter method is a method which:
- Returns something different than C++
void
- Has no arguments
- Starts with
get
If those rules are fulfilled, then the get
prefix is removed:
getWindowTitle() -> #window_title
This rule can be overriden by §2.1.2 Boolean getters
.
A boolean getter is a method which:
- Returns C++
bool
- Has no arguments
- Starts with
get
oris
orhas
If these rules are fulfilled, then:
get
prefix is removed:getAwesome() -> #awesome?
is
prefix is removed:isEmpty() -> #empty?
has
prefix is retained:hasSpace() -> #has_space?
A setter is a method which:
- Returns C++
void
- Has exactly one argument
- Starts with
set
If these rules are fulfilled, then the set
prefix is removed, and a Crystal
writer method is created: setWindowTitle() -> #window_title=
A conversion from the wrapper towards the binding happens if any of:
- The
crystal_type
and thebinding_type
differs - A
from_crystal
for the arguments type is configured - A
converter
for the arguments type is configured
If a conversion happens, the precedence is as follows:
from_crystal
is used if setconverter
is used if set
Examples:
- A type with both
from_crystal
andconverter
set would be wrapped by using thefrom_crystal
template:my_from_crystal(arg_name)
. - A type with
converter
set would be wrapped by using theconverter
module:MyConverter.unwrap(arg_name)
.
C++ allows the declaration of unnamed arguments, like this: void foo(int)
.
To wrap these methods, such arguments are given a name like unnamed_arg_X
,
where X
is the zero-indexed index of the affected argument.
Given void foo(int, int two, int)
, the generated wrapper prototype would look
like this: foo(unnamed_arg_0 : Int32, two : Int32, unnamed_arg_2 : Int32)
.
If an argument has a name which is a reserved word in Crystal, it gets an
underscore (_
) appended: void foo(int next) -> foo(next_ : Int32)
.
Inheritance from wrapped C++ classes is replicated in Crystal.
For a C++ class to be used as base-class in the Crystal wrapper, all of these have to be true:
- The base-class is wrapped.
- The base-class is publicly inherited.
The base-class is inherited in Crystal, mirroring the C++ definition.
class Foo : public Bar { ... };
If both Foo
and Bar
are wrapped, the following wrapper will be generated:
class Foo < Bar
# ...
end
The Crystal wrapper class will inherit from the first of all base-classes. All
following base-classes are wrapped through an #as_X
conversion method.
class Foo : public Bar, public AnotherOne { ... };
Will generate:
class Foo < Bar
def as_another_one : AnotherOne
# Conversion code ...
end
# ...
end
An abstract C++ class will also be declared abstract
in Crystal. Further,
an implementation class is generated to aid in conversion calls later on:
class Foo { // A pure class
virtual void doSomething() = 0;
};
Will be wrapped as:
abstract class Foo
abstract def do_something
end
class FooImpl < Foo
def do_something
# Call implementation ...
end
end
Note: The Impl
class cannot be inherited from.
It's possible to override a C++ method in a Crystal sub-class, if the C++ method
was defined as virtual
. A Crystal method is considered to override a C++
virtual method if the Crystal method and the C++ method share the same name.
class Foo {
virtual int doWork() { ... }
};
Can be overriden from Crystal like this:
class MyFoo < Foo # Inherit
def do_work
# ...
end
end
The arguments and result values are proxied back and forth from C++ like normal wrappers do. The rules of argument handling is the same. Such overrides will look and behave the same to C++ as any other virtual C++ method.
The bindings have to support method overloading, and as such use name mangling to generate unique method names based on a method prototype.
The name consists out of the following parts (in this order):
bg
prefix, marking it as bindgen wrapper function- The qualified C++ class name
- Method type marker (See below)
- The C++ method name
- The mangled argument list (See below)
All of these parts are joined by a single underscore (_
).
Argument type mangling
The argument list is a list of all types of the arguments, in the order they appear in the method prototype. Each argument types C++ name is taken and transformed, such that:
- A
*
is replaced withX
- A
&
is replaced withR
- All alpha-numeric characters are kept
- All other characters are replaced with
_
Method types
The method type marker mainly depends on the method type. However, special generated methods may use custom markers to distinguish them.
- Member methods don't have a marker
- Static methods use
STATIC
- Constructors use
CONSTRUCT
- Destructors use
DESTRUCT
Examples
- Member method
void Foo::bar(int *&) -> bg_Foo_bar_int_XR
- Static method:
void Foo::bar(std::string) -> bg_Foo_STATIC_bar_std__string
- Method without arguments:
void Foo::bar() -> bg_Foo_bar_
(Trailing_
)
For each wrapped C++ function, there is at least one wrapper function generated.
The name of an enum is constantized: enum foo_bar
is translated as
enum FooBar
.
The name of an enum constant is constantized: color_0 -> Color0
.
If an enumeration type is signaled to be a flags type, it'll get a @[Flags]
annotation in Crystal wrapper code.
Given a QFlags<ApplicationFlag>
, the generated enumeration will look like
@[Flags]
enum ApplicationFlag : Int32
# Constants ...
end
QObject signals are wrapped in two methods: First, the emission method, and second the connection method, which are then exposed as Crystal wrappers.
- Given this signal:
void changed(int one)
- Emission method:
changed(one : Int32) : Void
- Connection method:
on_changed(&block : Int32 -> Void)
The connection method returns an connection object, which responds to
#disconnect
. Calling this method breaks the connection. Subsequent calls to
this method have no effect.
QFlags<EnumT>
is a C++/Qt template type marking a C++ enum
to be a flags
type. Once detected, the clang
tool will mark the enum
type as a flags
type. See §5.3 Flag types
.