C ABI guide — libair-base.so (overview)
Audience: C developers (and, eventually, Swift / Python / Ruby via bindings) consuming Air without writing Rust. These pages explain how to use the library and what obligations fall on the caller — not just what to call.
air-base-capi exposes the layer-1 air-base-lib (pure Rust) as a stable C ABI,
producing libair-base.so. This is the project’s first C-ABI pass: the proving
ground for the methodology of the whole future “Air libc” (Rust userland, redrawn
contracts, explicit memory ownership). Contract decisions:
- Single source of truth: per-symbol docs are born from the Rust
///comments, carried bycbindgeninto the committed headerinclude/air_base.h, then rendered by Doxygen (HTML +manpages). No hand-written C docs, hence zero drift (ADR-027). - Stability: the header is a C-ABI contract guaranteed for 10 years, committed and diffed in CI (ADR-012).
- Errors:
AirStatusreturned in-band, noerrno,panic = "abort"(ADR-045).
Why a C ABI, not just Rust
Rust is the implementation; the C ABI is the universal contract. Every language
can call C. By freezing the boundary in C — #[repr(C)] types, in-band status,
explicit ownership — Air becomes polyglot from day one without maintaining N
parallel docs: one header, one set of guarantees.
The pages in this guide
- Getting started — include the header, link the lib, versioning/ABI.
- Error model (
AirStatus) — test, read, propagate; why nopaniccrosses the ABI; why noerrno. - Memory ownership & lifecycle — the critical point: who allocates, who frees, with which function. Per-symbol table.
- Thread-safety by type — what is callable from which thread, with concrete pitfalls.
- Compilable C examples — UUID, logging, time measurement, compiled against the committed header.
The three rules to remember above all
- Check every return. Every function returns an
AirStatus(or a non-NULLpointer forair_status_message). An*outis written only onAIR_STATUS_OK. See Error model. - Uniform ownership rule: +1 on RETURN, +0 on ARGUMENT. A returned handle
(
air_log_open,air_log_fields_new) is owned by the caller → you must free it. A type passed as an argument is borrowed → the callee neither frees it nor retains it. See Memory ownership. - String outputs use YOUR buffer. No string is allocated by Air in T1/T3: you
provide the buffer (sizes
AIR_UUID_HYPHENATED_LEN/AIR_ID128_HEX_LEN); too small ⇒AIR_STATUS_BUFFER_TOO_SMALL(never silent truncation). Nothing to free.
Version française : voir Guide ABI C — vue d’ensemble.