<div align="center">
# π Nylon Ring
**Ultra-Fast ABI-Stable HostβPlugin Interface for Rust**
[](https://github.com/AssetsArt/nylon-ring/actions/workflows/ci.yml)
[](https://crates.io/crates/nylon-ring)
[](https://docs.rs/nylon-ring)
[](LICENSE)
*Build fast native plugins with an explicit C-compatible ABI.*
[Features](#-features) β’ [Quick Start](#-quick-start) β’ [Performance](#-performance) β’ [System Overview](#-system-overview)
</div>
---
## π Features
- **Stable ABI v1** β C-compatible types, fixed status values, version and
structure-size validation.
- **Flexible calls** β fire-and-forget, async unary, synchronous fast path, and
bounded streaming with backpressure.
- **Safe lifecycle** β in-flight call guards, graceful unload/reload, timeouts,
and automatic request cleanup.
- **Cross-language validation** β Rust examples plus a buildable
[C plugin](https://github.com/AssetsArt/nylon-ring/tree/main/examples/c-plugin).
The workspace provides:
- [`nylon-ring`](https://crates.io/crates/nylon-ring) β ABI types, vtables, and
the `define_plugin!` macro.
- [`nylon-ring-host`](https://crates.io/crates/nylon-ring-host) β dynamic loading,
routing, streaming, lifecycle controls, and metrics.
MSRV: Rust 1.88.
---
## π Quick start
### Install
```toml
# Plugin
[dependencies]
nylon-ring = "0.1.0"
# Host
[dependencies]
nylon-ring-host = "0.1.0"
```
Plugin crates must also build as a dynamic library:
```toml
[lib]
crate-type = ["cdylib"]
```
### Host
```rust,no_run
use nylon_ring_host::{NrStatus, NylonRingHost};
# async fn run() -> Result<(), Box<dyn std::error::Error>> {
let mut host = NylonRingHost::new();
host.load("example", "target/release/libexample_plugin.so")?;
let plugin = host.plugin("example").expect("plugin was loaded");
let (status, response) = plugin.call_response("echo", b"hello").await?;
assert_eq!(status, NrStatus::Ok);
assert_eq!(response, b"hello");
# Ok(())
# }
```
Other call patterns:
```rust,ignore
plugin.call("notify", b"payload").await?;
plugin.call_response_fast("echo", b"hello").await?;
plugin.call_response_timeout("echo", b"hello", timeout).await?;
let (sid, stream) = plugin.call_stream("events", b"start").await?;
```
See the complete [Rust plugin example](https://github.com/AssetsArt/nylon-ring/tree/main/examples/ex-nyring-plugin)
and [Rust host example](https://github.com/AssetsArt/nylon-ring/tree/main/examples/ex-nyring-host).
Run the workspace demo:
```bash
cargo run --release --package ex-nyring-host
```
---
## π Performance
Release-build snapshot on an Apple M1 Pro.
### Single-stream (Criterion)
| Fire-and-forget | 40.798 ns | 24.511M calls/s |
| Synchronous fast path | 58.917 ns | 16.973M calls/s |
| Standard unary | 116.99 ns | 8.548M calls/s |
| Unary + 128-byte payload | 126.03 ns | 7.934M calls/s |
| Unary + 1 KiB payload | 184.96 ns | 5.407M calls/s |
| Unary + 4 KiB payload | 259.62 ns | 3.852M calls/s |
### Multi-core (10 workers)
| Fire-and-forget | 125.12M calls/s |
| Synchronous fast path | 88.67M calls/s |
| Standard unary | 19.72M calls/s |
### ABI primitives (Criterion)
| `NrStr::new` | 0.735 ns |
| `NrBytes::as_slice` | 0.311 ns |
| `NrVec::from_vec` | 15.318 ns |
| `NrVec::into_vec` | 24.544 ns |
These are reference measurements, not cross-platform guarantees. Reproduce them
with:
```bash
cargo bench --package nylon-ring
cargo bench --package nylon-ring-host
```
---
## π System overview
```text
+------------------------------------------------------+
| ββ LoadedPlugin + in-flight call gate |
| ββ HostContext |
| ββ thread-local synchronous slot |
| ββ sharded async request router |
| ββ bounded stream queues |
+-------------------------+----------------------------+
| C ABI v1
| NrPluginVTable / NrHostVTable
+-------------------------+----------------------------+
+------------------------------------------------------+
```
The host validates and initializes a library, assigns each call a session ID,
then routes plugin callbacks to the matching unary request or stream. Call guards
keep the library loaded until active work finishes; graceful unload/reload stops
new calls and waits for existing calls to drain.
---
## π‘ Safety
- Host and plugin must use the same target and ABI version.
- `NrStr` and `NrBytes` are borrowed; copy them before retaining their data.
- Owned `NrVec<T>` values carry the producer's drop callback, avoiding
cross-allocator frees.
- Plugins must stop worker threads and callbacks during shutdown.
- Only load trusted native libraries; this is not a security sandbox.
See the full [ABI evolution and compatibility policy](https://github.com/AssetsArt/nylon-ring/blob/main/docs/ABI_EVOLUTION.md).
---
## Development
```bash
cargo fmt --all -- --check
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo test --workspace --all-targets --all-features
```
Publishing is handled by GitHub Actions in dependency order using the
organization-level `RUST_TOKEN` secret.
## License
[MIT](LICENSE)