RingLoom’s native core is written in Zig, but services do not have to be. Non-Zig integrations build on the ringloom_service C ABI, which exposes the service runtime as a shared native library with stable C-compatible handles, structs, and status codes.

The broker remains a native process. Bindings start service processes, register with a local broker, create clients, send messages, poll inbound messages, and shut down cleanly.

Native service ABI

The C ABI is defined by:

include/ringloom_service.h
src/service/c_abi.zig

Build it with:

zig build service-c

Installed outputs include:

Artifact Purpose
zig-out/lib/libringloom_service.so or .dylib Shared library loaded by Java, Node.js, and other FFI consumers.
zig-out/lib/libringloom_service.a Static archive for C/C++ embedders.
zig-out/include/ringloom_service.h Stable C ABI header.

The ABI version macro is RINGLOOM_SERVICE_ABI_VERSION. Opaque handles keep internal Zig structures private:

  • ringloom_service_t
  • ringloom_client_t
  • ringloom_message_consumer_t
  • ringloom_metrics_reader_t

ABI design principles

The C surface is intentionally low-level and explicit:

  • use C-compatible scalar types, pointers, enums, and extern struct layouts;
  • return ringloom_status_t from fallible functions;
  • return handles through out-parameters;
  • pass strings as pointer plus byte length;
  • expose copy-based sends for convenience;
  • expose claim/commit/abort for zero-copy sends;
  • expose polling receive APIs driven by the caller’s thread;
  • keep borrowed message payload memory valid only during the poll callback;
  • never let Zig panics or Zig-specific error unions cross the ABI boundary.

This lets higher-level bindings choose their own ergonomics while sharing the same runtime contract.

C ABI capabilities

Area Functions / types
Lifecycle ringloom_service_start, ringloom_service_stop, ringloom_service_destroy
Identity ringloom_service_id, ringloom_service_node_id
Control progress ringloom_service_poll_control
Clients ringloom_service_create_client, ringloom_client_destroy
Discovery targets ringloom_client_list_targets
Lifecycle callbacks ringloom_client_set_lifecycle_handler
Copy sends ringloom_client_send, ringloom_client_send_message, request variants, send_to, send_to_leader
Zero-copy sends ringloom_client_try_claim, try_claim_to, try_claim_to_leader, request variants, ringloom_buffer_claim_commit, ringloom_buffer_claim_abort
Receive polling ringloom_service_create_message_consumer, ringloom_message_consumer_poll
Metrics ringloom_service_create_metrics_reader, counter/gauge registration, ring stats, counter iteration
Diagnostics ringloom_status_string, ringloom_last_error_message

Hot-path methods use status returns rather than exceptions. Expected outcomes such as buffer full, no available instance, back-pressure, and peer disconnected are normal control-flow results.

Java bindings

The Java bindings live under bindings/java and use the Java Foreign Function & Memory API.

Build and test:

zig build test-java

The Gradle project can also build a distributable JAR that embeds the platform native library. Java services use these low-level types:

Java type Purpose
RingloomService Starts/stops a service and polls control messages.
ServiceConfig Service startup configuration.
RingloomClient Sends to discovered targets and exposes target lists.
TargetService Target node ID, service ID, and leader flag.
BufferClaim Reusable zero-copy send claim.
MessageConsumer Polls inbound messages.
RingloomMessage Borrowed view of a received message.
RingloomMetricsReader Reads native counters, gauges, and ring stats.

Java services must make control-plane progress by calling RingloomService.pollControl(limit) from an application thread. Lifecycle callbacks run synchronously on the thread that polls control messages.

For hot paths, reuse BufferClaim instances and copy payload bytes only if they must outlive the receive callback.

C++ bindings

The C++ bindings live under bindings/cpp. They are a header-only C++17 RAII wrapper around the same C ABI and native library.

Build and test:

zig build cpp-bindings
zig build test-cpp

The integration test starts a real broker, starts two C++ services, sends through a zero-copy BufferClaim, and receives through a polling MessageConsumer.

The C++ API uses exceptions for setup/convenience code through helpers such as throwIfNotOk, while hot-path operations return primitive status/count values to avoid exception allocation for expected runtime outcomes.

Node.js bindings

The Node.js bindings live under bindings/node and expose libringloom_service through a Node-API addon.

Build and test:

zig build node-bindings
zig build test-node

The addon provides RingloomService, RingloomClient, status helpers, reusable claims, borrowed payload buffers, and polling consumers. As with Java and C++, borrowed receive payloads are valid only during the callback unless copied by the application.

Choosing an integration layer

If you want… Use…
Native Zig services ringloom_service directly from Zig.
A stable C integration surface include/ringloom_service.h.
C++ RAII wrappers bindings/cpp.
Java FFM and JAR packaging bindings/java.
Node.js services bindings/node.

All bindings still rely on a running local broker. Start the broker first, then start services with matching storage path, group, and broker node ID.