Skip to content

Type Mapping

String and Pointer Types

C uses char * for both strings and raw memory buffers. ruby-bindgen uses const-qualification and context to pick an FFI type as shown in the following table:

Context const char * char *
Function parameters :string :pointer
Function returns :string :pointer
Callback returns :pointer :pointer
Struct/union fields :string :pointer

Since const char * is a read-only string, FFI can safely auto-convert it to a Ruby String. On the other hand, char * often indicates a caller-allocated buffer (e.g., char *buf, size_t buf_size), so it is safer to map it to :pointer. This allows callers to create the buffer with FFI::MemoryPointer.new. Callback returns always use :pointer regardless of const because FFI cannot manage the lifetime of callback-returned strings.

If a specific function needs a different type mapping, use symbols: overrides: to replace the generated signature.

Struct Pointer Types

When a function parameter is a pointer to a struct, ruby-bindgen generates StructName.by_ref. This is correct for the common case of passing a single struct by pointer:

int proj_get_area_of_use(PJ *obj, double *west, ...);
// → attach_function :proj_get_area_of_use, ..., [:pointer, :pointer, ...], :int

However, .by_ref is wrong when the pointer is actually an array of structs. ruby-bindgen cannot distinguish these cases from the C signatures — both are SomeStruct *.

Below are two common patterns to help decide.

Array parameters

Look for aa count parameter that either precedes or follows the struct pointer:

PJ *proj_create_conversion(PJ_CONTEXT *ctx, ..., int param_count,
                            const PJ_PARAM_DESCRIPTION *params);

Here params points to an array of param_count structs. The caller allocates the array with FFI::MemoryPointer and writes structs into it.

Array returns

A function returns a pointer to a statically-allocated or heap-allocated array of structs:

const PJ_OPERATIONS *proj_list_operations(void);

This returns a NULL-terminated array of PJ_OPERATIONS structs, not a single struct. The caller iterates the array by advancing the pointer.

Use symbols: overrides: to fix these:

symbols:
  overrides:
    proj_create_conversion: "[:pointer, :string, :string, :string, :string, :string, :string, :int, :pointer], :pointer"
    proj_list_operations: "[], :pointer"

Union Pointer Types

The same considerations apply to unions. When a function takes a pointer to a union, ruby-bindgen generates UnionName.by_ref. As with structs, this is wrong when the pointer is actually an array of unions — use symbols: overrides: to fix these cases.