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

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

surdeus

Warning

This post was published 107 days ago. The information described in this article may have changed.

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