General ======= Each IDL namespace (as opposed to an interface, struct, etc. namespace) is mapped to a C++ header file and a directory. The name of the directory is the name of the namespace; the name of the file is the namespace name, followed by ".h". The header file and the directory are both part of the same directory; the former does not go in the latter. The directory contains sub-IDL-namespaces; if there are no such namespaces, the implementation is permitted, but not required, to create an empty directory. Each sub-IDL-namespace's header file is #included from its parent header file, so that #including the top-level header file shall be sufficient to access any descendent namespace. Each header file shall contain protection against being #included multiple times. This protection may not interfere with that of any other namespace. All identifiers and preprocessor symbols beginning with _IDL_CPP_ are reserved for use by the language binding. Types ===== IDL types are mapped to C++ types as follows: IDL Type C++ Type ======== ======== bool uint8_t octet uint8_t short int16_t ushort uint16_t int int32_t uint uint32_t long int64_t ulong uint64_t fshort float flong double char uint8_t (UTF8) FIXME: currently char simply acts as octet; should it refer to an actual character, and thus be uint32_t? If so, then unless the language supports UTF8 natively, an array of char would still be an array of octets, which could be confusing... Alternatively, get rid of char as a basic type, and use a typedef of octet to indicate that this particular octet is UTF8. Namespaces ========== IDL namespaces are mapped directly to C++ namespaces. Symbols declared inside a struct or interface which are not methods or non-const data members will go into a parallel namespace, which is the type-namespace name with "_ns" appended. Enumerations ============ As the size of a native C++ enum type is not guaranteed, and since they are not type-safe or namespace-safe, IDL enums are mapped to C++ structs. Each enumeration value is declared inside the struct as an anonymous enum value, and there is a _val entry which is an unsigned integer of the smallest type that can hold the IDL enum size. Bitfields ========= An IDL bitfield is mapped to a C++ struct using field width specifiers on the members. Integral members are mapped directly to C++ unsigned integers of the smallest type that can hold the IDL bitfield size, with a field size specifier. When a bitfield is used as the type of a bitfield entry, it cannot be directly mapped, as C++ does not allow non-integral types to have field size specifiers. Instead, get and set methods are provided to pack and unpack the data, and the contents of the bitfield type are directly inlined in the enclosing bitfield. If the field name is foo and the type is Foo, then the methods will be "Foo get_foo() and set_foo(Foo foo)". If a field name begins with "set_" or "get_", it will be preceded with an underscore for the field itself (but not for the set or get methods). Thus, a field called set_foo in IDL would become _set_foo, but a get method (if required) would be get_set_foo, not get__set_foo. The underscore prefix happens regardless of whether the field requires get and set methods. With an embedded bitfield, the inlined fields have the sub-bitfield name prefixed to the field name. Thus, if a bitfield Foo with fields a and b is included in a bitfield Bar as fields c and d, then Bar will have fields c_IDLNS_a, c_IDLNS_b, d_IDLNS_a, and d_IDLNS_b, and methods set_c(Foo), Foo get_c(), set_d(Foo), and Foo get_d(). The IDLNS is ugly, but there's no way I know of to use a C++ namespace mechanism without introducing unwanted padding (even __attribute__((packed)) will byte-align a substruct). Likewise, embedded enumerations cannot use the actual enumeration struct as a C++ bitfield member; they are treated as a simple integers instead. Get and set methods are not needed, as enums will convert to integers, but they may be added in the future to provide a type-safe alternative to direct assignment. Objects ======= A reference to an object has the name of the type, with no pointer or reference marker. If uninitialized, they default to NULL. Methods are called in the same way as on a C++ class, using the dot, not the arrow. To increment an object's reference count, call the retain() method. To decrement it, call the release() method. Weak references and autorelease pools will be added later. Classes ======= The implementor of a class must #include the generated .h file for the class in a public: portion of the class definition. The class's constructor must call init_iface() before any object references to the object are used. The generated footer.cc file must be included in exactly one non-header file. It is recommended that this be the file in which the methods are defined, so that they can be inlined by the stubs; however, the only requirement is that it have access to the class definition and any interface headers the implemented interfaces reference.