libghostty: add _get_multi to all _get APIs

Replace the ImageInfo and PlacementInfo sized structs and their
associated .info enum variants with a new _get_multi pattern that
batches multiple enum+pointer pairs into a single call. This avoids
struct ABI concerns (field order, padding, alignment, GHOSTTY_INIT_SIZED)
while preserving the single-call-crossing performance benefit for FFI
and Cgo callers.

Each _get_multi function takes an array of enum keys, an array of
output pointers, and an optional out_written parameter that reports
how many values were successfully written before any error. This
applies uniformly to all _get APIs: terminal_get, cell_get, row_get,
render_state_get, render_state_row_get, render_state_row_cells_get,
kitty_graphics_image_get, and kitty_graphics_placement_get.

The C example is updated to use compound-literal _get_multi calls,
and tests cover both success and error paths for every new function.
This commit is contained in:
Mitchell Hashimoto
2026-04-11 07:14:52 -07:00
parent 7421b4b13f
commit 2c1dad790b
12 changed files with 823 additions and 254 deletions

View File

@@ -215,17 +215,6 @@ typedef enum GHOSTTY_ENUM_TYPED {
*/
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_Z = 12,
/**
* All placement metadata as a sized struct.
*
* This is an optimization over querying each field individually,
* particularly useful in environments with high per-call overhead
* such as FFI or Cgo.
*
* Output type: GhosttyKittyGraphicsPlacementInfo *
* (initialize with GHOSTTY_INIT_SIZED)
*/
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_INFO = 13,
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyKittyGraphicsPlacementData;
@@ -354,96 +343,9 @@ typedef enum GHOSTTY_ENUM_TYPED {
*/
GHOSTTY_KITTY_IMAGE_DATA_DATA_LEN = 8,
/**
* All image metadata as a sized struct.
*
* This is an optimization over querying each field individually,
* particularly useful in environments with high per-call overhead
* such as FFI or Cgo.
*
* Output type: GhosttyKittyGraphicsImageInfo *
* (initialize with GHOSTTY_INIT_SIZED)
*/
GHOSTTY_KITTY_IMAGE_DATA_INFO = 9,
GHOSTTY_KITTY_IMAGE_DATA_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyKittyGraphicsImageData;
/**
* All image metadata in a single sized struct.
*
* Returned by ghostty_kitty_graphics_image_get() with
* GHOSTTY_KITTY_IMAGE_DATA_INFO. This is an optimization over
* querying each field individually, particularly useful in
* environments with high per-call overhead such as FFI or Cgo.
*
* This struct uses the sized-struct ABI pattern. Initialize with
* GHOSTTY_INIT_SIZED(GhosttyKittyGraphicsImageInfo).
*
* @ingroup kitty_graphics
*/
typedef struct {
/** Size of this struct in bytes. Must be set to sizeof(GhosttyKittyGraphicsImageInfo). */
size_t size;
/** The image ID. */
uint32_t id;
/** The image number. */
uint32_t number;
/** Image width in pixels. */
uint32_t width;
/** Image height in pixels. */
uint32_t height;
/** Pixel format of the image. */
GhosttyKittyImageFormat format;
/** Compression of the image. */
GhosttyKittyImageCompression compression;
/** Borrowed pointer to the raw pixel data. */
const uint8_t* data_ptr;
/** Length of the raw pixel data in bytes. */
size_t data_len;
} GhosttyKittyGraphicsImageInfo;
/**
* All placement metadata in a single sized struct.
*
* Returned by ghostty_kitty_graphics_placement_get() with
* GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_INFO. This is an optimization
* over querying each field individually, particularly useful in
* environments with high per-call overhead such as FFI or Cgo.
*
* This struct uses the sized-struct ABI pattern. Initialize with
* GHOSTTY_INIT_SIZED(GhosttyKittyGraphicsPlacementInfo).
*
* @ingroup kitty_graphics
*/
typedef struct {
/** Size of this struct in bytes. Must be set to sizeof(GhosttyKittyGraphicsPlacementInfo). */
size_t size;
/** The image ID this placement belongs to. */
uint32_t image_id;
/** The placement ID. */
uint32_t placement_id;
/** Whether this is a virtual placement (unicode placeholder). */
bool is_virtual;
/** Pixel offset from the left edge of the cell. */
uint32_t x_offset;
/** Pixel offset from the top edge of the cell. */
uint32_t y_offset;
/** Source rectangle x origin in pixels. */
uint32_t source_x;
/** Source rectangle y origin in pixels. */
uint32_t source_y;
/** Source rectangle width in pixels (0 = full image width). */
uint32_t source_width;
/** Source rectangle height in pixels (0 = full image height). */
uint32_t source_height;
/** Number of columns this placement occupies. */
uint32_t columns;
/** Number of rows this placement occupies. */
uint32_t rows;
/** Z-index for this placement. */
int32_t z;
} GhosttyKittyGraphicsPlacementInfo;
/**
* Combined rendering geometry for a placement in a single sized struct.
*
@@ -542,6 +444,40 @@ GHOSTTY_API GhosttyResult ghostty_kitty_graphics_image_get(
GhosttyKittyGraphicsImageData data,
void* out);
/**
* Get multiple data fields from a Kitty graphics image in a single call.
*
* This is an optimization over calling ghostty_kitty_graphics_image_get()
* repeatedly, particularly useful in environments with high per-call
* overhead such as FFI or Cgo.
*
* Each element in the keys array specifies a data kind, and the
* corresponding element in the values array receives the result.
* The type of each values[i] pointer must match the output type
* documented for keys[i].
*
* Processing stops at the first error; on success out_written
* is set to count, on error it is set to the index of the
* failing key (i.e. the number of values successfully written).
*
* @param image The image handle (NULL returns GHOSTTY_INVALID_VALUE)
* @param count Number of key/value pairs
* @param keys Array of data kinds to query
* @param values Array of output pointers (types must match each key's
* documented output type)
* @param[out] out_written On return, receives the number of values
* successfully written (may be NULL)
* @return GHOSTTY_SUCCESS if all queries succeed
*
* @ingroup kitty_graphics
*/
GHOSTTY_API GhosttyResult ghostty_kitty_graphics_image_get_multi(
GhosttyKittyGraphicsImage image,
size_t count,
const GhosttyKittyGraphicsImageData* keys,
void** values,
size_t* out_written);
/**
* Create a new placement iterator instance.
*
@@ -627,6 +563,40 @@ GHOSTTY_API GhosttyResult ghostty_kitty_graphics_placement_get(
GhosttyKittyGraphicsPlacementData data,
void* out);
/**
* Get multiple data fields from the current placement in a single call.
*
* This is an optimization over calling ghostty_kitty_graphics_placement_get()
* repeatedly, particularly useful in environments with high per-call
* overhead such as FFI or Cgo.
*
* Each element in the keys array specifies a data kind, and the
* corresponding element in the values array receives the result.
* The type of each values[i] pointer must match the output type
* documented for keys[i].
*
* Processing stops at the first error; on success out_written
* is set to count, on error it is set to the index of the
* failing key (i.e. the number of values successfully written).
*
* @param iterator The iterator handle (NULL returns GHOSTTY_INVALID_VALUE)
* @param count Number of key/value pairs
* @param keys Array of data kinds to query
* @param values Array of output pointers (types must match each key's
* documented output type)
* @param[out] out_written On return, receives the number of values
* successfully written (may be NULL)
* @return GHOSTTY_SUCCESS if all queries succeed
*
* @ingroup kitty_graphics
*/
GHOSTTY_API GhosttyResult ghostty_kitty_graphics_placement_get_multi(
GhosttyKittyGraphicsPlacementIterator iterator,
size_t count,
const GhosttyKittyGraphicsPlacementData* keys,
void** values,
size_t* out_written);
/**
* Compute the grid rectangle occupied by the current placement.
*

View File

@@ -331,8 +331,36 @@ GHOSTTY_API GhosttyResult ghostty_render_state_update(GhosttyRenderState state,
* @ingroup render
*/
GHOSTTY_API GhosttyResult ghostty_render_state_get(GhosttyRenderState state,
GhosttyRenderStateData data,
void* out);
GhosttyRenderStateData data,
void* out);
/**
* Get multiple data fields from a render state in a single call.
*
* Each element in the keys array specifies a data kind, and the
* corresponding element in the values array receives the result.
*
* Processing stops at the first error; on success out_written
* is set to count, on error it is set to the index of the
* failing key (i.e. the number of values successfully written).
*
* @param state The render state handle (NULL returns GHOSTTY_INVALID_VALUE)
* @param count Number of key/value pairs
* @param keys Array of data kinds to query
* @param values Array of output pointers (types must match each key's
* documented output type)
* @param[out] out_written On return, receives the number of values
* successfully written (may be NULL)
* @return GHOSTTY_SUCCESS if all queries succeed
*
* @ingroup render
*/
GHOSTTY_API GhosttyResult ghostty_render_state_get_multi(
GhosttyRenderState state,
size_t count,
const GhosttyRenderStateData* keys,
void** values,
size_t* out_written);
/**
* Set an option on a render state.
@@ -433,6 +461,34 @@ GHOSTTY_API GhosttyResult ghostty_render_state_row_get(
GhosttyRenderStateRowData data,
void* out);
/**
* Get multiple data fields from the current row in a single call.
*
* Each element in the keys array specifies a data kind, and the
* corresponding element in the values array receives the result.
*
* Processing stops at the first error; on success out_written
* is set to count, on error it is set to the index of the
* failing key (i.e. the number of values successfully written).
*
* @param iterator The iterator handle (NULL returns GHOSTTY_INVALID_VALUE)
* @param count Number of key/value pairs
* @param keys Array of data kinds to query
* @param values Array of output pointers (types must match each key's
* documented output type)
* @param[out] out_written On return, receives the number of values
* successfully written (may be NULL)
* @return GHOSTTY_SUCCESS if all queries succeed
*
* @ingroup render
*/
GHOSTTY_API GhosttyResult ghostty_render_state_row_get_multi(
GhosttyRenderStateRowIterator iterator,
size_t count,
const GhosttyRenderStateRowData* keys,
void** values,
size_t* out_written);
/**
* Set an option on the current row in a render-state row iterator.
*
@@ -571,6 +627,34 @@ GHOSTTY_API GhosttyResult ghostty_render_state_row_cells_get(
GhosttyRenderStateRowCellsData data,
void* out);
/**
* Get multiple data fields from the current cell in a single call.
*
* Each element in the keys array specifies a data kind, and the
* corresponding element in the values array receives the result.
*
* Processing stops at the first error; on success out_written
* is set to count, on error it is set to the index of the
* failing key (i.e. the number of values successfully written).
*
* @param cells The row cells handle (NULL returns GHOSTTY_INVALID_VALUE)
* @param count Number of key/value pairs
* @param keys Array of data kinds to query
* @param values Array of output pointers (types must match each key's
* documented output type)
* @param[out] out_written On return, receives the number of values
* successfully written (may be NULL)
* @return GHOSTTY_SUCCESS if all queries succeed
*
* @ingroup render
*/
GHOSTTY_API GhosttyResult ghostty_render_state_row_cells_get_multi(
GhosttyRenderStateRowCells cells,
size_t count,
const GhosttyRenderStateRowCellsData* keys,
void** values,
size_t* out_written);
/**
* Free a row cells instance.
*

View File

@@ -314,8 +314,35 @@ typedef enum GHOSTTY_ENUM_TYPED {
* @ingroup screen
*/
GHOSTTY_API GhosttyResult ghostty_cell_get(GhosttyCell cell,
GhosttyCellData data,
void *out);
GhosttyCellData data,
void *out);
/**
* Get multiple data fields from a cell in a single call.
*
* Each element in the keys array specifies a data kind, and the
* corresponding element in the values array receives the result.
*
* Processing stops at the first error; on success out_written
* is set to count, on error it is set to the index of the
* failing key (i.e. the number of values successfully written).
*
* @param cell The cell value
* @param count Number of key/value pairs
* @param keys Array of data kinds to query
* @param values Array of output pointers (types must match each key's
* documented output type)
* @param[out] out_written On return, receives the number of values
* successfully written (may be NULL)
* @return GHOSTTY_SUCCESS if all queries succeed
*
* @ingroup screen
*/
GHOSTTY_API GhosttyResult ghostty_cell_get_multi(GhosttyCell cell,
size_t count,
const GhosttyCellData* keys,
void** values,
size_t* out_written);
/**
* Get data from a row.
@@ -334,8 +361,35 @@ GHOSTTY_API GhosttyResult ghostty_cell_get(GhosttyCell cell,
* @ingroup screen
*/
GHOSTTY_API GhosttyResult ghostty_row_get(GhosttyRow row,
GhosttyRowData data,
void *out);
GhosttyRowData data,
void *out);
/**
* Get multiple data fields from a row in a single call.
*
* Each element in the keys array specifies a data kind, and the
* corresponding element in the values array receives the result.
*
* Processing stops at the first error; on success out_written
* is set to count, on error it is set to the index of the
* failing key (i.e. the number of values successfully written).
*
* @param row The row value
* @param count Number of key/value pairs
* @param keys Array of data kinds to query
* @param values Array of output pointers (types must match each key's
* documented output type)
* @param[out] out_written On return, receives the number of values
* successfully written (may be NULL)
* @return GHOSTTY_SUCCESS if all queries succeed
*
* @ingroup screen
*/
GHOSTTY_API GhosttyResult ghostty_row_get_multi(GhosttyRow row,
size_t count,
const GhosttyRowData* keys,
void** values,
size_t* out_written);
/** @} */

View File

@@ -1038,6 +1038,39 @@ GHOSTTY_API GhosttyResult ghostty_terminal_get(GhosttyTerminal terminal,
GhosttyTerminalData data,
void *out);
/**
* Get multiple data fields from a terminal in a single call.
*
* This is an optimization over calling ghostty_terminal_get()
* repeatedly, particularly useful in environments with high per-call
* overhead such as FFI or Cgo.
*
* Each element in the keys array specifies a data kind, and the
* corresponding element in the values array receives the result.
* The type of each values[i] pointer must match the output type
* documented for keys[i].
*
* Processing stops at the first error; on success out_written
* is set to count, on error it is set to the index of the
* failing key (i.e. the number of values successfully written).
*
* @param terminal The terminal handle (may be NULL)
* @param count Number of key/value pairs
* @param keys Array of data kinds to query
* @param values Array of output pointers (types must match each key's
* documented output type)
* @param[out] out_written On return, receives the number of values
* successfully written (may be NULL)
* @return GHOSTTY_SUCCESS if all queries succeed
*
* @ingroup terminal
*/
GHOSTTY_API GhosttyResult ghostty_terminal_get_multi(GhosttyTerminal terminal,
size_t count,
const GhosttyTerminalData* keys,
void** values,
size_t* out_written);
/**
* Resolve a point in the terminal grid to a grid reference.
*