Skip to content

Rust — FFI / Native Bindings

The nnrp-ffi crate exposes Rust protocol semantics as a C-compatible ABI (#[repr(C)]) for C#, Python, Unity, and future language bindings. Preview3 now includes stable value handles, buffer views, callback/polling events, error families, and runtime-backed client/server handle entrypoints.

Cargo.toml

toml
[dependencies]
nnrp-ffi = "1.0.0-preview.3.1"

[lib]
crate-type = ["cdylib", "staticlib", "rlib"]

Build Outputs

TargetCommandOutputUse Case
Windows DLLcargo build --release -p nnrp-ffinnrp_ffi.dllC# P/Invoke, Python ctypes, Unity
Linux SOcargo build --release -p nnrp-ffilibnnrp_ffi.soC# LibraryImport, Python ctypes
macOS dylibcargo build --release -p nnrp-ffilibnnrp_ffi.dylibSame
Native packagepython scripts/package_native_artifacts.pynative library + nnrp_ffi.h + manifest.jsonNode native loaders, C ABI consumers, release artifacts
Raw WASMcargo build --target wasm32-unknown-unknown -p nnrp-ffinnrp_ffi.wasmLow-level compile target; not a complete browser SDK

Native link libraries are for C#/Python/Unity and Node.js backend native addons. Packages include a manifest.json that declares the platform, architecture, library name, header, and required exported nnrp_* symbols; Node loaders should validate the manifest before loading the native library. Browser scenarios cannot load native link libraries and require a dedicated WASM/JS/TS wrapper layer.

Core ABI Types

c
typedef struct {
    uint8_t major;
    uint8_t wire_format;
} NnrpProtocolVersion;

typedef struct {
    uint32_t kind;
    uint64_t id;
    uint32_t generation;
    uint32_t flags;
} NnrpHandle;

typedef struct {
    const uint8_t* ptr;
    uintptr_t len;
} NnrpBufferView;

Non-empty buffer views must provide non-null pointers. The callee borrows memory only for the duration of the call and does not retain the pointer after returning.

Status, Diagnostics, and Events

TypeDescription
NnrpFfiStatusCodeABI status values such as Ok, InvalidArgument, NotFound, AlreadyExists, WouldBlock, and ProtocolError
NnrpErrorFamilyCross-language family for core/runtime errors
NnrpFfiStatusABI status code, error family, protocol error code, and detail code
NnrpFfiDiagnosticStatus plus related connection/session/operation/frame ids
NnrpEventKindConnectionOpened, SessionOpened, SubmitAccepted, ResultPushed, ResultDropped, FlowUpdated, Error, and others
NnrpEventOne callback/polling event with handles, frame id, borrowed payload, and diagnostic
NnrpCallbackSinkCallback delivery entrypoint
NnrpPollResultPolling delivery result

The NnrpEvent* passed to a callback is valid only while the callback is running. Bindings must copy values and payloads they need to retain.

Request Types

TypeDescription
NnrpConnectionBootstrapCompatibility entry for constructing a connection handle
NnrpClientConnectRequestCreate a client connection handle
NnrpServerBindRequestCreate a server handle
NnrpSessionOpenRequestOpen a session on a client connection
NnrpSubmitRequestClient submit, creating an operation handle
NnrpClientCancelRequestClient cancel
NnrpServerAcceptRequestServer accept, creating a server session handle
NnrpServerReceiveSubmitRequestServer-side submit receive, creating an operation handle
NnrpServerSendResultRequestServer-side result event
NnrpServerFlowUpdateRequestServer-side flow-update event
NnrpControlRequestGeneric control-plane request

Exported Functions

FunctionDescription
nnrp_current_protocol_versionReturn the current protocol version
nnrp_connection_bootstrapCompatibility wrapper for creating a client connection handle
nnrp_client_connectCreate a client connection handle and enqueue ConnectionOpened
nnrp_session_openCompatibility wrapper for opening a client session
nnrp_client_open_sessionCreate a client session handle and enqueue SessionOpened
nnrp_submitCompatibility wrapper for submit
nnrp_client_submitCreate an operation handle and enqueue SubmitAccepted
nnrp_session_closeCompatibility wrapper for closing a session
nnrp_client_closeClose a client session and enqueue SessionClosed
nnrp_client_cancelEnqueue cancel/drop-related events
nnrp_client_await_eventPoll one event from a connection/session-associated queue
nnrp_server_bindCreate a server handle and enqueue ConnectionOpened
nnrp_server_acceptCreate a server session handle and enqueue SessionOpened
nnrp_server_receive_submitCreate a server operation handle and enqueue SubmitAccepted
nnrp_server_send_resultEnqueue ResultPushed
nnrp_server_send_flow_updateEnqueue FlowUpdated
nnrp_server_closeClose a server session and enqueue SessionClosed
nnrp_controlValidate a control request and enqueue Control
nnrp_poll_emptyReturn an empty polling result with WouldBlock
nnrp_dispatch_eventDeliver one borrowed event through a callback

C# P/Invoke Example

csharp
[LibraryImport("nnrp_ffi", EntryPoint = "nnrp_current_protocol_version")]
public static partial NnrpProtocolVersion CurrentProtocolVersion();

[StructLayout(LayoutKind.Sequential)]
public struct NnrpProtocolVersion
{
    public byte Major;
    public byte WireFormat;
}

Python ctypes Example

python
import ctypes

class NnrpProtocolVersion(ctypes.Structure):
    _fields_ = [("major", ctypes.c_uint8), ("wire_format", ctypes.c_uint8)]

lib = ctypes.CDLL("./libnnrp_ffi.so")
lib.nnrp_current_protocol_version.restype = NnrpProtocolVersion
version = lib.nnrp_current_protocol_version()

nnrp-conformance Crate

nnrp-conformance hosts Rust-backed conformance case execution and adapter helpers. Downstream SDKs should consume the versioned nnrp-conformance baseline through suite-owned manifests, plans, and result schemas.

Current Boundary

The FFI layer exposes a cross-language handle/event control plane. It does not hand Rust async runtime objects, socket pointers, or long-lived borrowed payload ownership to callers; bindings should call follow-up functions through handles and copy any callback/polling data they need to keep.

Raw nnrp_ffi.wasm is only a low-level ABI compilation artifact. A browser-facing SDK still needs wasm-bindgen, .d.ts declarations, a JS/TS session wrapper, and WebSocket/WebTransport transport adapters; nnrp-rs owns only the WASM/native primitives, while npm layout, the Node native loader, and browser transport adapters belong in nnrp-js.

WARNING

  1. Do not retain borrowed buffer or event pointers after return. They are valid only for the duration of the call or callback.
  2. Null pointers are rejected for non-empty buffers and required output arguments. Callers should still validate before crossing the FFI boundary.
  3. Handles carry kind / id / generation. Bindings should store all three, not only the raw id.

NNRP Documentation