# `zerodds-c-api`
ZeroDDS **C-FFI** — cross-language hub for C, C++, C# and TypeScript.
Exports an `extern "C"` layer over the ZeroDDS DCPS runtime
that all non-Rust bindings use as a common binary interface.
Part of the [**ZeroDDS**](../../README.md) project. Safety class
**STANDARD** — `unsafe` allowed at the FFI boundary, every block carries
a `// SAFETY:` comment; internal code is `unsafe`-free.
---
## Who docks here
| Pure C | direct | `#include <zerodds.h>` + `-lzerodds` |
| C++17 RAII wrapper | [`crates/cpp`](../cpp/README.md) | `#include <zerodds/dds.hpp>` over the C-API |
| C# (P/Invoke, NativeAOT) | [`crates/cs`](../cs/README.md) | `DllImport("zerodds")` |
| TypeScript / Node.js | [`crates/ts-node`](../ts-node/README.md) | koffi FFI over `libzerodds.so` |
| ROS-2 RMW shim | [`crates/rmw-zerodds-shim`](../rmw-zerodds-shim/README.md) | Apex.AI plugin model |
Python (`crates/py`) and Java (`crates/java-omgdds`) do
**not** go over the C-API — they use pyo3 / jni-rs direct
bridges into the Rust stack.
## Quick start — pure C
`zerodds.h` is generated by `cbindgen` from the Rust source (see
`build.rs`) and checked in at `include/zerodds.h`.
```c
#include <stdio.h>
#include <zerodds.h>
int main(void) {
zerodds_runtime_t* rt = zerodds_runtime_create();
zerodds_participant_t* p =
zerodds_runtime_create_participant(rt, /* domain_id */ 0);
zerodds_topic_t* t =
zerodds_participant_create_topic(p, "Greetings", "Greeting");
zerodds_writer_t* w = zerodds_participant_create_writer(p, t);
uint8_t payload[] = { /* CDR-encoded "Greeting{id:42,text:'hi'}" */ };
zerodds_writer_write(w, payload, sizeof(payload));
zerodds_writer_destroy(w);
zerodds_topic_destroy(t);
zerodds_participant_destroy(p);
zerodds_runtime_destroy(rt);
return 0;
}
```
Build (Linux/macOS, with a built `libzerodds.so` on the `LD_LIBRARY_PATH`):
```bash
clang -std=c11 -lzerodds main.c -o demo
./demo
```
## Type model — deliberately byte-oriented
The FFI takes **raw CDR bytes** for all samples:
```c
zerodds_writer_write(writer, sample_bytes, sample_len);
zerodds_reader_take(reader, &out_buf, &out_len, ...); // out_buf via _free()
```
The CDR encode/decode logic lives in the language bindings:
`idl-cpp` emits a C++ encoder, `idl-csharp` a C# encoder, etc. The
C-FFI is neutral — wire-drift tests pass byte-exactly.
Advantages:
* No generic-type acrobatics across the FFI boundary.
* The Apex.AI plugin and ROS-2 RMW keep their own marshaling paths.
* Wire-vector conformance is trivial to validate.
## Handle model
All objects are opaque pointers. Callers must pair `*_destroy()`:
| `zerodds_runtime_create()` | `zerodds_runtime_destroy()` |
| `zerodds_participant_create()` | `zerodds_participant_destroy()` |
| `zerodds_writer_create()` | `zerodds_writer_destroy()` — before the participant |
| `zerodds_reader_take()` (buffer) | `zerodds_buffer_free()` |
Memory ownership is explicitly documented in `include/zerodds.h`
and tested against Apex.AI plugin conformance.
## Spec mapping
| ZeroDDS C-API 1.0 (vendor spec) | `docs/spec-coverage/zerodds-c-api-1.0.md` |
| OMG DDSI-RTPS 2.5 | §8 — wire format |
| OMG DDS-XCDR2 | complete CDR pipeline (byte pass-through in the FFI) |
## Features
* `default = []` — no feature needed.
* Build output: `cdylib` (`libzerodds.so`), `staticlib` (`libzerodds.a`),
`rlib` (Rust consumers).
## Stability
`1.0.0-rc.2`. The ABI is **stable** from 1.0.0-final; until then
symbol renames or handle-type changes are possible (every
break is marked in the CHANGELOG).
## Tests
```bash
cargo test -p zerodds-c-api
```
Plus cross-vendor conformance against Cyclone DDS / Fast-DDS in
`crates/discovery/tests/cyclone_*.rs`.
## See also
- [`zerodds-dcps`](../dcps/README.md) — Rust-native DCPS runtime (input side).
- [`zerodds-cpp`](../cpp/README.md) — C++17 RAII wrapper over this C-API.
- [`zerodds-cs`](../cs/README.md) — C# P/Invoke bindings.
- [`zerodds-ts-node`](../ts-node/README.md) — TypeScript / Node.js via koffi.
- [`zerodds-rmw-zerodds-shim`](../rmw-zerodds-shim/README.md) — ROS-2 RMW plugin.
- [`packaging/docker/cpp-runtime/`](../../packaging/docker/cpp-runtime/) — sandbox image with libzerodds.so + headers.