valavapi

How to bind a delayed out parameter?


Normally C API pointers are translated to either arrays or out parameters in Vala bindings:

// C
void get_user_name (char *buffer, int buffer_length);
void get_user_count (int *count_ptr);
// Vala
public static void get_user_name (uint8[] buffer);
public static void get_user_count (out int count);

I have now come across a case where a pointer is used as a delayed out parameter.

// C
void bind_buffer (void *buffer, int buffer_length, int *length);
int fetch (void);

Every time fetch () is called, data is transferred to buffer and length.

What is the best way to bind such an API in Vala?

// Vala
public static void bind_buffer (uint8[] buffer, int *length);
public static int fetch ();

I don't think I can use out int length here?

Also I have to make sure that the bound data is available the whole time it is still bound. How can I achieve this?


Solution

  • You're basically right with that last example. The CCode annotations are a bit off (array_length is true by default, you don't need to include it, and array_pos doesn't exist. There is array_length_pos, but again, it's not actually necessary since the default value will work fine). A pointer is really the only way to go in this situation for length.

    As for making sure the data is available, it doesn't look like the C API gives you a way to do this. Typically this would be achieved by transferring ownership, but that requires the C API to provide a way to automatically destroy/unref the data when is no longer required. The only thing you can do is try to make sure the VAPI consumer is aware of the requirement that they keep the data alive for as long as it is needed.

    Vala tends to work very well with well-designed C APIs but when working with poorly designed C APIs it's not always possible to create a good Vala API. Your only real options are to either improve the C library or write a wrapper library (either in C or Vala) which proxies calls to the C API while providing a more sane API.