Best practices to design a C API that can be ergonomically used in Rust

⚓ Rust    📅 2025-08-18    👤 surdeus    👁️ 4      

surdeus

Hi,

For those of you who have worked on safe Rust bindings to C libraries before, what aspects of a C API makes it particularly suitable to be used in Rust.
Or in other words, what to do and what to avoid when designing a C API with the express purpose to be used within Rust.

Here are the things I came up with, but I suspect there are other things that I am forgetting.

General

  • Obvious: It must be possible to build a safe abstraction.
  • Keep things simple
    • bindgen should have no issues creating Rust equivalent ffi-bindings.
  • No C preprocessor Macros
  • Support standard rust traits (where it makes sense):
    • Debug, Clone, PartialEq, Eq, Default, Hash

All types on the FFI API surface should fall into one of the two categories:

1. Resource Manager Types

This kind of type manages (allocates and frees) a resource like memory or other system resources.

  • These types should should have straightforward object lifetimes and the C API should expose the following functions:

      1. function to create -> wrapped as new method
      1. Functions to use functionality
      1. function to destroy -> wrapped as drop method
  • Should be representable as a opaque types, only work on raw pointers (which are wrapped by safe abstraction)

2. Simple Value Type

  • Only struct of value types
  • Bitwise copyable

In your experience, what other parts should be considered, that are otherwise annoying (not ergonomic) or difficult to represent in Rust?

1 post - 1 participant

Read full topic

🏷️ Rust_feed