Part 19 — C ABI / FFI Architecture

Reusable P2P Communication Platform

Status: Architecture specification
Part: 19 of 24
Primary implementation language: Rust
Primary ABI: C-compatible ABI
Primary goals: stable cross-language integration, safe ownership, ABI/version stability, async interop, zero/low-copy data paths, mobile/desktop bindings, daemon/library dual mode, error isolation, panic containment, reusable SDK distribution


1. Purpose

The communication platform is written primarily in Rust, but reusable infrastructure becomes much more valuable if other products can consume it without rewriting their entire application in Rust.

Potential consumers include:

C
C++
Kotlin / Java
Swift / Objective-C
Python
Dart / Flutter
Go
C#
Node.js
other native runtimes

The architecture therefore needs a stable foreign-function boundary.

The core rule is:

Rust internals remain Rust; the public cross-language contract is a small, explicit, versioned C ABI built around opaque handles and stable data-transfer rules.

Do not expose:

Rust struct layout
Rust enums directly
Arc<T>
Box<T> internals
Vec<T> internals
String internals
trait objects
async Future
panic unwinding

across the ABI.


2. Why C ABI First

C ABI is the most portable native interoperability layer.

It can be consumed by:

C/C++
JNI/JNA
Swift/Objective-C
Python ctypes/cffi
Dart FFI
C#
Go cgo
Node native addons

This gives one stable low-level boundary instead of independently designing incompatible bindings for each language.


3. Architectural Position

                 Rust Core
     ┌────────────────────────────┐
     │ comm-runtime               │
     │ comm-messaging             │
     │ comm-files                 │
     │ comm-dtn                   │
     │ comm-routing               │
     │ comm-diagnostics           │
     └──────────────┬─────────────┘
                    │
              comm-ffi-core
                    │
               C ABI Layer
       ┌────────────┼─────────────┐
       │            │             │
     C/C++       Kotlin/Java    Swift
       │            │             │
     Python       Android         iOS/macOS
       │
   Dart/Flutter

4. FFI Scope

The C ABI should expose high-level platform operations:

runtime creation
runtime start/stop
identity/device operations
send message
send file
query status
subscribe to events
network diagnostics
DTN status
bootstrap/pairing

It should not expose every internal crate function.


5. Stable Boundary Principle

The ABI should remain stable even if internal Rust architecture changes.

For example:

Rust internal:
HashMap<DeviceId, Arc<PeerRuntime>>

C ABI:
comm_peer_handle_t

Internal layout can change freely.


6. Opaque Handles

Represent internal objects as opaque handles.

Example C:

typedef struct comm_runtime comm_runtime_t;
typedef struct comm_client comm_client_t;
typedef struct comm_transfer comm_transfer_t;
typedef struct comm_subscription comm_subscription_t;

Actual memory layout remains private.


7. Handle Ownership

Every handle must have explicit lifecycle.

Example:

comm_runtime_t* comm_runtime_create(...);
void comm_runtime_destroy(comm_runtime_t*);

No ambiguous ownership.


8. RAII Wrappers in High-Level Bindings

C API is manual.

Generated/manual language wrappers should convert to native resource models:

C++ → RAII class
Swift → deinit wrapper
Kotlin → Closeable
Python → context manager/finalizer
Dart → Finalizer/explicit close

9. Handle Registry vs Raw Pointer

Two possible designs:

Raw opaque pointer

fast
simple

but invalid pointer misuse is dangerous.

Integer handle registry

safer validation
generation checking
cross-thread use easier

Recommended for public FFI:

#![allow(unused)]
fn main() {
pub struct FfiHandle {
    index: u32,
    generation: u32,
}
}

Expose as 64-bit integer.


10. Handle Type

typedef uint64_t comm_handle_t;

Special value:

0 = invalid/null handle

11. Typed Handles

Avoid one untyped global namespace when possible.

C typedef aliases:

typedef comm_handle_t comm_runtime_handle_t;
typedef comm_handle_t comm_transfer_handle_t;
typedef comm_handle_t comm_subscription_handle_t;

Runtime validates object type internally.


12. Generation Counter

Handle generation prevents stale-handle reuse.

Example:

slot 42 generation 3
destroyed
slot 42 reused generation 4

old handle gen 3
→ invalid

13. Handle Registry

#![allow(unused)]
fn main() {
pub struct HandleRegistry {
    // bounded typed slabs / arenas
}
}

Requirements:

thread-safe
generation checked
bounded
no use-after-free

14. FFI Object Graph

Avoid returning nested borrowed pointers.

Prefer handles and copied/owned DTOs.

Example:

RuntimeHandle
TransferHandle
SubscriptionHandle

15. ABI Versioning

Expose:

uint32_t comm_abi_version_major(void);
uint32_t comm_abi_version_minor(void);

16. Major Version Rule

Breaking C ABI change:

major++

Examples:

function signature change
struct field reorder
enum value meaning change
ownership contract change

17. Minor Version Rule

Backward-compatible additions:

new function
new optional feature
new enum value where extensible

18. ABI Compatibility Query

comm_result_t comm_check_abi_compat(
    uint32_t required_major,
    uint32_t required_minor
);

19. Symbol Naming

Prefix all symbols:

comm_

Never export generic names like:

init
send
free

20. Symbol Visibility

Hide all non-public symbols.

Build shared library with only intended C API exports.


21. Header Generation

Maintain one canonical public header:

include/comm.h

Can be generated with:

cbindgen

but generation must be reviewed and ABI-tested.


22. C Header Rule

Public header should use only C-compatible types:

stdint.h
stddef.h
stdbool.h where appropriate

Avoid compiler-specific layout unless explicitly guarded.


23. Primitive Types

Use fixed-width integers:

uint8_t
uint16_t
uint32_t
uint64_t
int32_t

Avoid:

long
usize
isize

in stable ABI.


24. Boolean Type

Prefer a fixed-width integer representation where cross-binding ambiguity exists.

Do not rely on language-specific bool ABI assumptions everywhere.


25. Enums

Expose enums as fixed-width integer typedefs.

Example:

typedef uint32_t comm_runtime_state_t;

Constants:

#define COMM_RUNTIME_READY 1u
#define COMM_RUNTIME_DEGRADED 2u

This gives better forward compatibility.


26. Unknown Enum Values

Consumers must tolerate unknown values.

Bindings should map:

known enum
or
Unknown(raw)

where language supports.


27. Struct Layout

If exporting structs directly, require:

#![allow(unused)]
fn main() {
#[repr(C)]
}

Use direct structs only for:

small immutable POD-like DTOs

Avoid complex nested layouts.


28. Extensible Struct Pattern

Stable config structs can use:

typedef struct {
    uint32_t struct_size;
    uint32_t version;
    ...
} comm_runtime_config_t;

This supports adding fields later.


29. struct_size

Caller sets:

sizeof(comm_runtime_config_t)

Library reads only fields available in caller's version.


30. Strings

Use UTF-8 length-delimited bytes.

typedef struct {
    const uint8_t* ptr;
    size_t len;
} comm_bytes_view_t;

No NUL-termination requirement for the primary ABI.


31. Borrowed Inputs

For synchronous input:

caller owns memory
library reads only during the call

unless explicit transfer-of-ownership API says otherwise.


32. Owned Output Buffers

typedef struct {
    uint8_t* ptr;
    size_t len;
    size_t cap;
} comm_owned_buffer_t;

Must be released by Rust:

void comm_buffer_free(comm_owned_buffer_t buffer);

Never free with a foreign allocator.


33. Allocator Boundary

Memory allocated by Rust is freed by Rust.

Memory allocated by caller remains caller-owned unless explicit ownership transfer occurs.


34. Large Data Paths

Do not move multi-gigabyte files through generic copied buffers.

Prefer:

file path
file descriptor/handle
stream source
stream sink

35. Borrowed Callback Memory

If an event callback receives borrowed data:

valid only until callback returns

Provide owned-copy helpers where needed.


36. Callback API

typedef void (*comm_event_callback_t)(
    const comm_event_t* event,
    void* user_data
);

Rules:

callback may not block core networking
user_data is opaque
callback thread semantics are documented

37. Callback Dispatch

Recommended:

internal event
 ↓
bounded queue
 ↓
dedicated FFI dispatcher
 ↓
foreign callback

Do not call foreign callbacks while holding important runtime locks.


38. Callback Backpressure

Slow consumers must not block networking.

Use:

bounded queues
coalescing
drop stale ephemeral events
resync-required events

39. Subscription Handle

comm_result_t comm_subscribe(
    comm_runtime_handle_t runtime,
    uint32_t topic,
    comm_event_callback_t callback,
    void* user_data,
    comm_subscription_handle_t* out_subscription
);

Cancellation:

comm_result_t comm_subscription_cancel(
    comm_subscription_handle_t subscription
);

40. Polling Alternative

Provide event polling for runtimes where callbacks are awkward.

comm_result_t comm_poll_event(
    comm_subscription_handle_t subscription,
    comm_event_t* out_event
);

41. Async Model

Rust Future never crosses the C ABI.

Use:

operation handle
poll/status
callback completion
cancel

42. Operation Handle

typedef comm_handle_t comm_operation_handle_t;

Start operation:

comm_result_t comm_send_file_async(
    comm_runtime_handle_t runtime,
    ...,
    comm_operation_handle_t* out_operation
);

43. Operation Status

comm_result_t comm_operation_status(
    comm_operation_handle_t operation,
    comm_operation_status_t* out_status
);

44. Cancellation

comm_result_t comm_operation_cancel(
    comm_operation_handle_t operation
);

This maps to structured Rust cancellation.


45. High-Level Async Wrappers

Bindings convert operation handles into:

Kotlin suspend
Swift async/await
Python asyncio
Dart Future
C# Task
Java CompletableFuture

46. Error Model

Use stable numeric error codes.

typedef uint32_t comm_error_code_t;

Success:

0

47. Error Domains

Examples:

Runtime
Network
Identity
Storage
Files
DTN
Capability
Permission
Resource
Bootstrap
Diagnostics

48. Rich Error Information

An error object may expose:

domain
code
retryable
user-action hint
diagnostic ID

Do not make error strings the programmatic API.


49. No Panic Across FFI

Every exported function must prevent Rust unwinding across the ABI.

Use boundary panic protection where unwind strategy permits.

Unexpected panic maps to a stable internal error or process abort according to configured panic strategy.


50. In-Process vs Daemon FFI

Support both.

In-Process

Foreign App
 ↓
C ABI
 ↓
Rust Runtime

Daemon-Backed

Foreign App
 ↓
C ABI client
 ↓
Local IPC
 ↓
comm-daemon

Daemon mode provides stronger crash and language-runtime isolation.


51. Unified SDK Semantics

The same high-level operations should exist across both backends:

send message
send file
query state
subscribe
bootstrap
diagnostics

52. FFI Workspace

crates/
├── comm-ffi-types/
├── comm-ffi-core/
├── comm-ffi-daemon-client/
├── comm-ffi-platform/
└── comm-sdk-model/

bindings/
├── c/
├── cpp/
├── kotlin/
├── swift/
├── python/
├── dart/
├── csharp/
└── go/

include/
└── comm.h

53. comm-ffi-types

Contains only:

repr(C) DTOs
constants
versions
error codes

No runtime behavior.


54. comm-ffi-core

Owns:

handle registry
pointer validation
buffer helpers
callback dispatch
panic boundaries
runtime mappings

55. comm-ffi-daemon-client

Maps the same public API onto Part 16 IPC.


56. comm-sdk-model

Contains stable high-level Rust DTOs before conversion into C structures.

This decouples domain internals from ABI internals.


57. C++ Binding

Wrap C handles in RAII.

Properties:

move-only where ownership is unique
automatic release
typed results
no raw free()

58. Kotlin / Android Binding

Architecture:

Kotlin
 ↓
thin JNI layer
 ↓
C ABI / FFI adapter
 ↓
Rust Runtime

Keep JNI narrow.


59. Kotlin Coroutines

Map async operation handles to:

suspend fun

and events to:

Flow<Event>

with bounded buffering.


60. Android Platform Objects

Some objects cannot be represented portably:

Context
Uri
Network
ParcelFileDescriptor

Use a platform-specific JNI adapter.

Do not contaminate the generic C ABI with Android classes.


61. Android Large Files

Prefer:

ParcelFileDescriptor
→ duplicated raw FD
→ Rust FileSource

rather than copying through JVM arrays.


62. Swift Binding

Architecture:

Swift
 ↓
C module / wrapper
 ↓
C ABI
 ↓
Rust

Map operations to:

async throws

and events to:

AsyncStream

where practical.


63. Swift Memory

Convert Rust-owned buffers to Swift Data/String, then free through Rust API.


64. Python Binding

Options:

cffi
ctypes
PyO3 wrapper over service APIs

For stable ABI distribution, a C ABI-backed wrapper is attractive.


65. Python Async

Use:

asyncio Future

and ensure callbacks enter Python safely with GIL handling.


66. Dart / Flutter Binding

Use:

dart:ffi

Map:

operation handle → Future
subscription → Stream

Respect Dart isolate/threading rules.


67. Go Binding

Use cgo if needed, but daemon mode can be cleaner for many Go server applications.


68. C# Binding

Use P/Invoke.

Map operation handles to Task.


69. Node.js Binding

Use N-API wrapper or daemon-client wrapper.

Do not block the Node event loop with synchronous native network calls.


70. Thread-Safety Contract

Every handle type must document:

thread-safe
thread-confined
serialized internally

Recommended defaults:

runtime/client handles → thread-safe
callbacks → serialized per subscription
temporary builder objects → may be thread-confined

71. Reentrancy

Foreign callbacks may call query APIs.

Avoid invoking callbacks while holding global internal locks.


72. Async Runtime Ownership

Create one long-lived async runtime per in-process runtime instance, not per FFI call.


73. Runtime Lifecycle API

comm_result_t comm_runtime_create(
    const comm_runtime_config_t* config,
    comm_runtime_handle_t* out_runtime
);

comm_result_t comm_runtime_start(
    comm_runtime_handle_t runtime
);

comm_result_t comm_runtime_stop(
    comm_runtime_handle_t runtime
);

comm_result_t comm_handle_release(
    comm_handle_t handle
);

74. Shutdown Idempotency

Repeated stop/release must never double-free.

Return a stable invalid/already-closed result where appropriate.


75. Configuration DTO

Use versioned extensible C structs.

Example:

typedef struct {
    uint32_t struct_size;
    uint32_t api_version;
    uint32_t runtime_mode;
    uint32_t log_level;
    uint64_t memory_budget;
} comm_runtime_config_t;

76. Typed DTO vs Binary Envelope

Use typed C DTOs for:

common stable API

Use binary/versioned envelopes for:

extension-specific payloads
large evolving diagnostic data

77. Postcard at the FFI Edge

Postcard remains excellent internally, but foreign SDK consumers should not be forced to implement Postcard for basic operations.

Use it only for explicit advanced binary extension APIs.


78. JSON at the FFI Edge

JSON is acceptable for:

diagnostic export
external admin tooling
human/tool interoperability

Not as the main high-throughput core ABI.


79. RON at the FFI Edge

RON is suitable for:

configuration
developer tools
scenario files

not primary cross-language runtime communication.


80. Stable IDs

Expose fixed-size IDs.

Example:

typedef struct {
    uint8_t bytes[16];
} comm_id128_t;

Use 32-byte equivalent when domain IDs require it.


81. Time Types

Use documented fixed-width integer timestamps.

Example:

int64_t Unix milliseconds

Use monotonic time internally for durations, not across ABI.


82. Optional Values

Use explicit:

has_value
value

for C DTOs where no safe sentinel exists.


83. Arrays

Inputs:

const T* ptr;
size_t len;

Outputs:

owned buffer
or
explicit freeable array

All lengths validated before allocation.


84. Null Semantics

Every pointer argument must specify whether:

null allowed
null + len 0 allowed
null always invalid

85. FFI Security

Foreign callers are not automatically trusted.

Validate:

handle
pointer
length
enum value
struct_size
version

before expensive work.


86. Double Destroy

A second destroy/release returns:

InvalidHandle

not memory corruption.


87. Concurrent Destroy

Use registry state/reference counting so:

thread A uses
thread B closes

results in typed failure, never UAF.


88. Handle State

#![allow(unused)]
fn main() {
pub enum HandleState {
    Live,
    Closing,
    Closed,
}
}

89. Releasing a View vs Cancelling Work

Important:

release transfer handle
≠
cancel transfer

A GC finalizer must not accidentally cancel durable work.


90. Reacquiring Durable Operations

Foreign app should be able to query:

TransferId
MessageId
EmergencyId

after UI/process restart.


91. Event Model

Common event DTOs may use:

event type
sequence
version
payload

High-level bindings translate to native sealed enums/classes.


92. Event Ordering

Document:

ordered per subscription
global total order not guaranteed unless explicitly provided

93. Event Gap Detection

Sequence numbers allow:

gap detected
→ request snapshot

following Part 16 semantics.


94. Subscription Backpressure

Coalesce:

transfer progress
network metrics
presence

Preserve:

security state
terminal operation state
critical emergency events

95. Platform Vtable / Reverse FFI

Rust sometimes needs platform services.

Expose a narrow versioned vtable.

typedef struct {
    uint32_t struct_size;
    uint32_t version;
    void* user_data;
    comm_result_t (*open_file)(...);
    comm_result_t (*notify)(...);
} comm_platform_vtable_t;

96. Reverse FFI Rule

Rust requests semantic platform actions.

It should not embed Android/iOS UI policy.


97. Optional Hooks

Null optional function pointer means:

unsupported

Never crash.


98. Secure Store Bridge

For platform keys:

Android Keystore
Apple Keychain/Secure Enclave
TPM

prefer opaque key handles and signing APIs over exporting private key bytes.


99. Key Separation

Never pass private identity keys into Kotlin/Swift just because it is convenient.

Keep key access behind secure-store abstraction.


100. Proximity FFI

Expose neutral:

NearbyPeer
ProximityEvent
connect intent

not raw Android BluetoothDevice.


101. Bootstrap FFI

Expose:

create invitation
get QR payload
accept payload
get SAS
approve/reject

Camera/NFC I/O stays platform-specific.


102. Diagnostics FFI

Expose:

basic path/status DTOs
advanced diagnostics snapshot
network doctor
event stream

103. Emergency FFI

Expose high-level:

send_sos
cancel_emergency
ack_emergency

Do not allow raw unauthenticated setting of AuthorityCritical.


104. Extension FFI

Third-party extensions should use a generic namespaced API rather than adding a new exported symbol for every extension.

Conceptually:

comm_result_t comm_extension_call(
    comm_runtime_handle_t runtime,
    comm_bytes_view_t namespace_id,
    comm_bytes_view_t request,
    comm_operation_handle_t* out_operation
);

105. Plugin ABI Is Separate

Part 24 plugin/module ABI should be narrower than the full application ABI and designed for sandboxing.

Do not automatically expose all user data or runtime controls to plugins.


106. Native Artifact Matrix

Linux:

libcomm.so
libcomm.a optional
comm.h
pkg-config

Windows:

comm.dll
comm.lib
comm.h
PDB symbols

macOS:

libcomm.dylib
or framework/XCFramework packaging

Android:

.so per ABI
AAR wrapper

Apple mobile:

XCFramework
Swift Package wrapper

107. Android Packaging

Official Android SDK can publish an AAR containing:

Kotlin API
JNI bridge
native libraries

108. Apple Packaging

Prefer:

XCFramework
+
Swift Package

Final production signing/build validation requires Apple toolchains.


109. Python Packaging

Provide wheels for supported targets when practical.


110. Flutter Packaging

Provide a Flutter plugin package with native binaries and platform shims.


111. C/C++ Packaging

Provide:

header
shared/static library
CMake config
pkg-config
examples

112. SDK Versioning Dimensions

Keep separate:

SDK semantic version
C ABI version
daemon IPC version
wire protocol version
storage schema version

Do not conflate them.


113. Version Info API

Expose:

comm_version_info_t comm_version_info(void);

Include:

SDK version
ABI version
build ID

114. Feature Capability Query

SDK exposes built-in capabilities.

A binding can ask whether this build includes:

files
DTN
proximity
emergency
daemon backend

115. Official SDK ABI Policy

For official binaries, prefer one stable superset ABI.

Disabled features return:

Unsupported

rather than disappearing unpredictably.


116. Binding Generation

Potential tooling:

cbindgen
UniFFI
JNI code generation
Swift module maps

The tool is implementation detail.

The ABI contract must remain understandable independently.


117. Unsafe Code Concentration

Keep unsafe in a few modules:

ffi_ptr.rs
ffi_buffer.rs
ffi_callback.rs
ffi_handle.rs

Core communication crates should remain safe Rust wherever possible.


118. Unsafe Documentation

Every unsafe block documents:

preconditions
ownership
lifetime
threading
why operation is valid

119. Strict Lints

Enable:

unsafe_op_in_unsafe_fn
missing_safety_doc

and related lints.


120. FFI Test Matrix

Required:

C smoke
C++ RAII
Kotlin Android
Swift
Python
Dart/Flutter

as official bindings mature.


121. ABI Golden Tests

Persist expected:

sizeof
alignof
field offsets
enum numeric values
symbol list

for stable C types.


122. ABI Diff CI

Compare shared-library ABI against previous release.

Unexpected break:

CI failure

123. Header Diff CI

comm.h changes require explicit review.


124. Symbol Export CI

Ensure only approved symbols are exported.


125. C Smoke Test

Compile pure C example against released library.

This is mandatory for ABI confidence.


126. Fuzzing

Part 10 should fuzz:

config structs
enum values
byte views
handle sequences
operation lifecycle
event payload decoding

127. Sequence Fuzzing

Generate:

create
start
subscribe
send
cancel
release
destroy
use stale handle

Assert:

no panic
no UAF
no double free

128. Sanitizers

Run FFI harnesses under:

ASan
UBSan
TSan where supported

129. Miri

Use Miri for unsafe Rust helpers:

pointer conversions
buffer ownership
handle registry

130. Reentrancy Tests

Callback calls back into:

query runtime
cancel operation

No deadlock.


131. Slow Callback Test

Foreign callback intentionally blocks.

Expected:

core network continues
event queue bounded

132. Concurrent Destroy Test

One thread uses a handle while another closes it.

Expected:

typed error
no UAF

133. Panic Boundary Test

Inject internal panic in test build.

Expected:

no unwind crosses C boundary

134. Memory Leak Test

Repeated:

create/destroy
subscribe/cancel
operation handle acquire/release

must return handle counts to baseline.


135. Daemon Restart Test

Daemon-backed SDK:

daemon restarts
client reconnects
durable operation remains
subscriptions resync

136. Binding Compatibility Test

Old binding binary should work with newer compatible ABI release.


137. Documentation Requirements

Every public function documents:

ownership
nullability
threading
blocking behavior
callback behavior
error codes
version added

138. Example Applications

Provide:

examples/c
examples/cpp
examples/android-kotlin
examples/swift
examples/python
examples/flutter

139. C Example Scope

Show:

runtime start
subscribe
send message
shutdown

140. Kotlin Example Scope

Show:

service-scoped runtime
Flow events
suspend send
large-file FD transfer

141. Swift Example Scope

Show:

async send
AsyncStream events

142. Python Example Scope

Show:

asyncio
context manager
event subscription

143. Flutter Example Scope

Show:

Future send
Stream progress
dispose/reconnect

144. Distribution Manifest

Each SDK release should include:

native binaries
headers
binding package
checksums
version info
license notices
compatibility notes

145. Deprecation Policy

Mark API deprecated before removal.

Breaking removal waits for next ABI major.


146. Error-Code Stability

Never reuse an existing error code for different meaning.


147. Enum Stability

Never reuse retired enum numeric values.


148. Struct Stability

Do not reorder fields inside same ABI major.


149. 32-bit Considerations

If supporting 32-bit Android/embedded:

test size_t assumptions
pointer-width assumptions
alignment

Wire/protocol sizes remain fixed-width.


150. Endianness Boundary

In-process C ABI uses target-native representation.

Network/IPC serialization remains independently specified and canonical.


151. Performance

FFI should not become a per-byte or per-packet crossing.

Prefer coarse operations:

send chunk stream
start transfer
query snapshot
receive batched events

152. Minimize Crossing Frequency

Bad:

foreign call for every packet

Good:

foreign starts transfer
Rust owns hot path
foreign receives progress snapshots

153. Zero-Copy Priority

Most valuable zero/low-copy cases:

large file input
large file output
media buffers
diagnostic exports

Do not overcomplicate tiny message paths.


154. Media FFI

If external product supplies media frames:

buffer ownership
timestamp
format
lifetime

must be explicit.

Prefer buffer pool or frame handle abstraction over raw long-lived pointers.


155. Media Codec Boundary

Android hardware codecs may remain in Kotlin/platform side while Rust owns call/session logic.

Desktop AV1 software codec may stay fully Rust/native.

FFI should support both without forcing one codec implementation architecture.


156. Buffer Pool Handle

Advanced API may expose:

comm_buffer_handle_t

for reusable media/file buffers.

Add only after profiling shows value.


157. Main-Thread Safety

Generic C ABI must not assume UI thread.

Bindings handle dispatch.


158. Foreign GC Runtime

Never rely on foreign GC timing for durable operation completion.

Explicit close/release APIs are primary.


159. Resource Limits

Part 08 applies to FFI:

max handles
max subscriptions
max pending callbacks
max async ops

A foreign app cannot allocate infinite handles.


160. Diagnostics

Expose developer-only FFI counters:

live handles
callback queue depth
invalid handle calls

No raw pointer values.


161. Crash Recovery

In-process host crash ends runtime process.

Durable state recovers on next start.

Daemon-backed mode can survive host UI/process crash independently.


162. Security Boundary

FFI is a memory-safety boundary.

Treat all foreign inputs as hostile until validated.


163. Authorization Boundary

FFI caller having access to a function does not mean it has protocol authority.

Runtime still enforces:

identity roles
priority authorization
peer permissions
policy

164. Public API Example

comm_result_t comm_runtime_create(
    const comm_runtime_config_t* config,
    comm_runtime_handle_t* out_runtime
);

comm_result_t comm_send_message(
    comm_runtime_handle_t runtime,
    const comm_peer_ref_t* peer,
    comm_bytes_view_t text_utf8,
    comm_operation_handle_t* out_operation
);

comm_result_t comm_subscribe(
    comm_runtime_handle_t runtime,
    uint32_t topic,
    comm_event_callback_t callback,
    void* user_data,
    comm_subscription_handle_t* out_subscription
);

comm_result_t comm_subscription_cancel(
    comm_subscription_handle_t subscription
);

comm_result_t comm_handle_release(
    comm_handle_t handle
);

165. Initial Production Scope

Implement first:

ABI versioning
generation-checked opaque handles
stable error codes
UTF-8 byte views
owned output buffers
runtime lifecycle
async operation handles
subscriptions
bounded callback dispatcher
message API
file API
diagnostics API
bootstrap API
panic containment
C/C++ wrapper
Kotlin Android wrapper
Swift wrapper

Then:

Python
Dart/Flutter
C#
Go
daemon-backed SDK
generic extension API

Defer initially:

every language at once
complex cross-process shared-memory ABI
direct Rust-layout exposure

166. Implementation Phases

Phase 1 — ABI Foundation

versions
types
error model
handle registry
buffers

Phase 2 — Runtime Lifecycle

create
start
stop
release

Phase 3 — Async Operations

operation handles
status
cancel
completion

Phase 4 — Events

subscription
callback dispatcher
polling
backpressure

Phase 5 — Core APIs

messaging
files
diagnostics
bootstrap
emergency

Phase 6 — Mobile Bindings

Kotlin/JNI
Swift
platform service vtables

Phase 7 — Other Bindings

C++
Python
Dart
C#
Go
Node

Phase 8 — Daemon Backend

same public semantics
IPC-backed implementation

Phase 9 — Hardening

ABI diff
fuzz
ASan
UBSan
TSan
Miri
reentrancy
leak tests

167. Definition of Done

Part 19 is complete when:

  • no Rust layout is exposed as stable ABI
  • all long-lived objects use validated opaque handles
  • stale handles are rejected
  • ownership and free rules are explicit
  • Rust memory is always freed by Rust
  • async work uses operation handles rather than raw Rust Futures
  • callbacks are bounded and isolated from core network workers
  • callback threading and reentrancy are documented
  • no Rust panic unwinds across the C ABI
  • stable numeric errors exist
  • C, C++, Kotlin, Swift, Python, and Dart can all consume the same platform model
  • large file data can avoid unnecessary copies
  • daemon-backed and in-process SDK modes share semantics
  • Android/iOS objects stay in platform-specific bridges
  • private identity keys are not unnecessarily copied across FFI
  • ABI golden tests verify sizes, offsets, constants, and symbols
  • older compatible bindings work with newer ABI releases
  • fuzz, sanitizer, Miri, stale-handle, concurrent-destroy, reentrancy, and leak tests exist

168. Relationship to Earlier Parts

Part 19 exposes stable integration surfaces for:

01 — Protocol Extension System
02 — Multi-Device Identity
03 — Transport & Routing Policy Engine
04 — Offline Event Log
05 — Robust File / Blob Subsystem
06 — DTN / Store-Carry-Forward
07 — Capability Negotiation
08 — Resource Limits & Backpressure
09 — Crash Recovery
10 — Fuzzing & Protocol Test Suite
11 — Relay / Self-Hosted Infrastructure
12 — Multipath Networking
13 — Battery-Aware Scheduling
14 — Proximity Abstraction
15 — QR / NFC Bootstrap
16 — Daemon & Headless Runtime
17 — Emergency Priority Classes
18 — Network Diagnostics & Path Visualization

It directly prepares:

20 — Embedded Linux Node
21 — WASM-Compatible Components
22 — Third-Party Protocol Extensions
23 — External Interoperability Suite
24 — Plugin / Module Ecosystem

169. Final Architecture

                      RUST CORE
                         │
                  Stable SDK Model
                         │
                   comm-ffi-core
                         │
                     C ABI v1
          ┌──────────────┼───────────────┐
          │              │               │
         C++           Kotlin           Swift
          │              │               │
       Desktop        Android         iOS/macOS
          │
       Python
          │
       Dart/Flutter

Optional daemon-backed mode:

Foreign App
    │
Language Binding
    │
Stable C ABI
    │
FFI Daemon Client
    │
Local Secure IPC
    │
comm-daemon
    │
Communication Runtime

170. Final Principle

The FFI layer should make this possible:

A Flutter application sends files.

An Android Kotlin application uses nearby Bluetooth and NFC.

A Swift application uses the same identity and messaging engine.

A Python automation tool queries transfer state.

A C++ desktop product embeds messaging.

All of them reuse the same Rust communication platform.

None of those applications need to know:

how Arc works
how Tokio schedules futures
how Rust enums are laid out
how the internal database is structured

They see only:

stable handles
stable functions
stable errors
stable events
stable ownership rules

That is the purpose of Part 19: make the Rust communication engine reusable as a language-neutral SDK without sacrificing safety at the boundary.