diff --git a/.github/workflows/website.yml b/.github/workflows/website.yml
index 4177dac..72e2413 100644
--- a/.github/workflows/website.yml
+++ b/.github/workflows/website.yml
@@ -17,4 +17,8 @@ jobs:
with:
python-version: '3.14'
- run: python src/website/build.py
- - run: node --check src/website/site.js
+ - run: python src/website/validate.py
+ - run: |
+ node --check src/website/site.js
+ node --check src/website/theme.js
+ node --check src/website/docs.js
diff --git a/src/website/.openai/hosting.json b/src/website/.openai/hosting.json
deleted file mode 100644
index c0e67da..0000000
--- a/src/website/.openai/hosting.json
+++ /dev/null
@@ -1 +0,0 @@
-{"project_id":"appgprj_6aa7a5ea0a5c8191bae88aa00dac4409","static":{"directory":"dist"}}
diff --git a/src/website/README.md b/src/website/README.md
index 682a9d7..cbfa9c2 100644
--- a/src/website/README.md
+++ b/src/website/README.md
@@ -1,12 +1,22 @@
# Interprocess website
-A static landing page with language examples and links to the library and protocol. No runtime framework or external dependencies.
+A static landing page and developer documentation for all six language APIs. No runtime framework or external dependencies.
```sh
python3 src/website/build.py
python3 -m http.server --directory src/website/dist
```
-The Website workflow validates the static build on pull requests and main. The public site at cloudtoid.com uses Sites hosting; `.openai/hosting.json` identifies it. Keep registry availability and the preview/release notice accurate when publishing packages.
+Cloudflare Pages publishes this site directly from `cloudtoid/interprocess`. Changes under `src/website/**` on `main` trigger production deployments; other branches receive previews linked from GitHub. Project: `cloudtoid`; build command: `python3 src/website/build.py`; output directory: `src/website/dist`. The Website GitHub Actions workflow also validates the build and JavaScript syntax. Failed builds do not replace the last successful deployment.
+
+Keep package availability and installation commands current when releasing packages. Benchmarks change only after new measurements.
The header and footer use the official blue wordmarks from [cloudtoid/assets](https://github.com/cloudtoid/assets/tree/master/logos), served locally. The black and white variants follow the selected color theme.
+
+## Developer documentation
+
+`docs/pages.json` defines page titles, descriptions, navigation, and URLs. Edit the corresponding HTML fragments under `docs/`; `docs/template.html` supplies the shared layout. `build.py` renders the pages into `dist/docs/`, creates the sitemap and robots.txt, and adds canonical, social, and structured metadata. API content is authored against the public implementations; it is not generated from source comments. Update the reference alongside API changes, including waiting, error, ownership, and truncation behavior. Link to generated ecosystem references where available.
+
+Run `python3 src/website/validate.py` after building to check local links, anchors, metadata, and sitemap coverage. CI runs this check. All reference text and navigation work without JavaScript; `docs.js` enhances code blocks with highlighting and copy buttons. The homepage's language guide links point to these pages.
+
+The social preview uses `assets/social-card.png`; its editable SVG source is alongside it. SEO metadata uses `https://cloudtoid.com` as the canonical origin. Publishing makes the sitemap available at `/sitemap.xml`; search-engine indexing happens independently of deployment.
diff --git a/src/website/assets/social-card.png b/src/website/assets/social-card.png
new file mode 100644
index 0000000..a0ce71d
Binary files /dev/null and b/src/website/assets/social-card.png differ
diff --git a/src/website/assets/social-card.svg b/src/website/assets/social-card.svg
new file mode 100644
index 0000000..1aa23ae
--- /dev/null
+++ b/src/website/assets/social-card.svg
@@ -0,0 +1,11 @@
+
diff --git a/src/website/build.py b/src/website/build.py
index 24c4b92..534afae 100644
--- a/src/website/build.py
+++ b/src/website/build.py
@@ -1,11 +1,94 @@
-"""Build the static site for Sites, without runtime dependencies."""
+"""Build the static marketing site and developer reference, without dependencies."""
+from html import escape
+import json
from pathlib import Path
+import re
import shutil
+from string import Template
+
root = Path(__file__).resolve().parent
output = root / 'dist'
output.mkdir(exist_ok=True)
-for name in ('index.html', 'style.css', 'site.js', 'theme.js'):
+base = 'https://cloudtoid.com'
+pages = json.loads((root / 'docs/pages.json').read_text())
+home = (root / 'index.html').read_text()
+favicon = re.search(r']+>', home).group()
+
+
+def metadata(title, description, path, kind='website'):
+ url = base + path
+ tags = [f'']
+ for key, value in {
+ 'og:type': kind, 'og:site_name': 'Cloudtoid Interprocess',
+ 'og:title': title, 'og:description': description, 'og:url': url,
+ 'og:image': base + '/assets/social-card.png',
+ 'og:image:width': '1200', 'og:image:height': '630',
+ 'og:image:alt': 'Cloudtoid Interprocess: fast shared-memory queues across six languages',
+ }.items():
+ tags.append(f'')
+ tags.append('')
+ return '\n'.join(tags)
+
+
+home_title = re.search(r'
Other archive suffixes are darwin-x64, linux-arm64, linux-x64, and win32-x64. Replace the suffix in both archive names. Linux prebuilt libraries require glibc 2.34 or later.
+
On Windows, extract the archive, set PKG_CONFIG_PATH to its lib/pkgconfig directory, and add its lib directory to PATH for the DLL. Link against the import library. The header can also be included from C++.
+
On Unix, compile a C program with pkg-config; the SDK flags include the runtime library search path:
+
cc example.c -o example $(pkg-config --cflags --libs cloudtoid-interprocess)
+./example
Functions returning int32_t status use CIP_OK = 1 for success, CIP_UNAVAILABLE = 0 for full/empty/timeout or temporary recovery, and CIP_ERROR = -1 for failure. An empty message is still CIP_OK with length zero.
Create or join a queue and write the handle to output on success. Strings are UTF-8 and NUL-terminated. Path may be NULL for the temporary directory; Windows ignores it. Capacity must match all participants.
+
void cip_publisher_close(cip_publisher *handle)
+
void cip_subscriber_close(cip_subscriber *handle)
+
Release a handle exactly once, after every concurrent call has returned. Close(NULL) is safe. A non-null handle cannot be reused or closed again after release.
Copies one message. CIP_UNAVAILABLE means no room or recovery admission unavailable. Input memory must remain valid for the call; a NULL data pointer is allowed only with length zero.
Copies and consumes a message into an owned buffer. Timeout is milliseconds: -1 waits indefinitely, 0 attempts once, and a positive value bounds the wait. Other negative values are invalid. CIP_UNAVAILABLE means no ready message before the timeout.
+
void cip_buffer_free(cip_buffer buffer)
+
Free each successful receive result exactly once, including empty messages. Do not free a result from an unsuccessful receive or invent a buffer to pass here. Copying the struct does not create a second ownership right.
Tries once and copies into caller-owned storage. On success, copied is the number of bytes written. An undersized buffer truncates and consumes the message. NULL data requires capacity zero. Use the status to distinguish an empty message from no message.
+
Error details
+
const char *cip_last_error(void)
+
Diagnostic text in thread-local storage, valid until the next error on that thread. Read or copy it immediately after CIP_ERROR, on the same OS thread.
+
int32_t cip_last_error_kind(void)
+
Returns a cip_error_kind: CIP_NO_ERROR = 0, CIP_INVALID_ARGUMENT = 1, CIP_CAPACITY_MISMATCH = 2, CIP_PUBLISHER_LIMIT = 3, CIP_EXHAUSTED = 4, CIP_CORRUPT = 5, CIP_IO_ERROR = 6, or CIP_INTERNAL_ERROR = 7. Error state is diagnostic state, not a substitute for checking each function's return status.
+
Concurrency and shutdown
+
Handles support concurrent operations, but closing concurrently with an operation is unsafe. Use bounded receive timeouts, signal your worker to stop, join it, then close the handle. There is no cancellation object or batch-send function in the C ABI. Open after fork; inherited handles must not be used in the child.
+
Prebuilt SDKs contain shared libraries. For static linking, build cloudtoid-interprocess-ffi from source and define CIP_STATIC on Windows. See the source-build instructions.
diff --git a/src/website/docs/concepts.html b/src/website/docs/concepts.html
new file mode 100644
index 0000000..067e7b4
--- /dev/null
+++ b/src/website/docs/concepts.html
@@ -0,0 +1,26 @@
+
One queue, multiple publishers, competing subscribers. These rules apply across every language binding.
+
Queue identity
+
All participants must use the same name, capacity, and Unix backing directory. Windows ignores the path; its mapping and lease objects are session-local, so participants must share a Windows session and compatible permissions.
+
Use an explicit absolute path for cross-language Unix applications: runtime temporary directories can differ. Names must also be unique across directories because the notification semaphore uses the name, not the backing path.
+
Names must be nonempty, must not be . or .., and cannot contain slash or NUL.
Windows also rejects backslashes.
macOS allows at most 24 UTF-8 bytes; Linux allows 245. Short ASCII names of at most 24 bytes are portable.
+
Transient lifetime
+
A queue remains usable while at least one publisher or subscriber is attached. Closing a reader does not destroy a queue retained by other participants. After all endpoints close or their processes exit, unread messages are lost. Opening the same name again creates a fresh, empty queue.
+
+
On Unix, stale files may remain after a crash until the next opener cleans them up. Their presence does not mean that messages can be resumed.
+
Delivery and ordering
+
Subscribers compete for messages: under ordinary operation, each message is consumed by one subscriber. This is a work-sharing queue, not broadcast. To deliver a copy to every consumer, use separate queues.
+
Delivery follows reservation order. An unfinished earlier reservation can delay later messages. Successful sequential sends preserve order; concurrent calls have no defined relative order. Batch sends commit a prefix and may interleave with other publishers; a batch is not a transaction.
+
The queue transports bytes, without a serializer. Agree on encoding, schema, and byte order in your application. Empty messages are valid. Distinguish an empty payload from the API's “no message” result.
+
Capacity and backpressure
+
Capacity is the circular message buffer size in bytes. It must exceed 16 and be divisible by 8. Total mapped storage is 262400 + capacity bytes, including the header and publisher table. Each queue supports up to 2,048 connected publisher objects.
+
Records include metadata and alignment, so the entire buffer is not available for payload bytes. A nonblocking send can report unavailable because space is exhausted or recovery temporarily blocks admission. Choose a retry deadline, bounded backoff, or an application-level overflow policy. Retrying cannot make an inherently oversized message fit.
+
Receive-into APIs copy at most the supplied buffer length. An undersized buffer truncates and consumes the message; the remainder cannot be read later. Size reusable buffers for the largest payload you accept.
+
Waiting and cancellation
+
“Try” methods do not wait for a message or free space. An unavailable receive may also mean a reader owns consumption or the next record is not ready. Open, close, recovery checks, and wrapper synchronization can still involve operating-system work.
+
Rust and C offer blocking receives with timeouts. Python waits with the GIL released and checks Python signals between bounded waits. .NET accepts a cancellation token on blocking Dequeue. Node.js and Go check immediately, then use adaptive timer backoff from 1 to 10 ms while idle. Their idle-to-active latency can include that interval plus scheduling delay. Prefer one receive loop per subscriber.
+
Crashes and recovery
+
Recovery reclaims abandoned work only after checking participant liveness. Paused live owners are not expired just because time passes. Messages can be lost during recovery, including completed messages behind an abandoned reservation. The queue does not provide durable acknowledgements or exactly-once effects.
+
Publisher reservations use native 64-bit atomics. The complete queue is not formally lock-free: readers serialize consumption, live paused owners can block progress, and creation and destruction use OS locks. Open native endpoints after fork(); do not use inherited endpoints in the child.
+
Upgrades and long-lived queues
+
v3 is incompatible with the v1/v2 shared-memory layout. Drain the old queue, stop all participants, and upgrade them together using a fresh queue. The physical buffer wraps; logical counters do not. Counter exhaustion is an explicit error and requires a fresh queue after participants finish.
Requires .NET 10 or later and a 64-bit process on a supported platform.
+
dotnet add package Cloudtoid.Interprocess
+
Send and receive
+
using Cloudtoid.Interprocess;
+
+var options = new QueueOptions("example", capacity: 65536);
+var factory = new QueueFactory();
+using var subscriber = factory.CreateSubscriber(options);
+using var publisher = factory.CreatePublisher(options);
+
+if (!publisher.TryEnqueue("hello"u8))
+ throw new InvalidOperationException("Queue is full or recovering");
+
+byte[] buffer = new byte[256];
+using var cancellation = new CancellationTokenSource(TimeSpan.FromSeconds(1));
+ReadOnlyMemory<byte> message = subscriber.Dequeue(buffer, cancellation.Token);
+Console.WriteLine(System.Text.Encoding.UTF8.GetString(message.Span));
+
QueueOptions
+
QueueOptions(string queueName, long capacity)
+
QueueOptions(string queueName, string path, long capacity)
+
Immutable queue configuration. The first overload uses Path.GetTempPath(). Windows ignores the backing path. Capacity is message-buffer bytes, greater than 16 and divisible by 8. Read-only properties are string QueueName, string Path, and long Capacity.
Create or join the transient queue as a publisher or subscriber. Both returned interfaces implement IDisposable. At most 2,048 publisher objects may be connected to a queue.
Registers IQueueFactory with the service collection. Call services.AddInterprocessQueue() and resolve IQueueFactory through dependency injection.
+
IPublisher
+
bool TryEnqueue(ReadOnlySpan<byte> message)
+
Copies the bytes into shared memory without waiting for space. Returns false when the message does not fit or recovery temporarily closes admission; true means the message was committed. A notification semaphore reaching its limit does not fail an already committed send.
+
ISubscriber
+
bool TryDequeue(out ReadOnlyMemory<byte> message)
+
Tries once, allocating a byte array for a received message. False means no ready message, an active reader owns consumption, or the next message is unfinished.
+
bool TryDequeue(Memory<byte> buffer, out ReadOnlyMemory<byte> message)
+
Copies into your buffer. On success the returned memory references the filled part of that buffer; consume it before reusing or modifying the buffer. An undersized buffer truncates and consumes the message. A true result with zero length is a real empty message.
Blocks until a message arrives, cancellation is requested, disposal is observed, or a failure occurs. Allocates a result array. Use CancellationToken.None to wait without application cancellation.
Blocking receive into caller-owned storage, with the same truncation and buffer-lifetime rules as TryDequeue with a buffer.
+
Failures and cancellation
+
Cancellation and subscriber disposal throw OperationCanceledException from receive operations. Sending through a disposed publisher throws ObjectDisposedException. Invalid options are rejected by argument validation. A publisher-limit failure throws InvalidOperationException; counter exhaustion throws OverflowException. Queue opening and access can also fail because of capacity mismatch, permissions, I/O, or invalid shared state.
+
False from TryEnqueue/TryDequeue is not an exception. Apply a bounded retry policy if the application needs to wait. TryDequeue has no cancellation token because it does not wait for a message.
+
Cleanup and concurrency
+
Use using for each endpoint. Disposal stops new calls and waits for admitted calls to finish before releasing resources; waiting readers observe disposal on retry. Consumption is serialized across subscribers. A stalled live participant is not treated as crashed simply because a deadline passes.
+
The API is synchronous; there is no DequeueAsync or batch-enqueue API. Reusing receive buffers avoids per-message result-array allocation. See queue lifetime before handing off between processes.
diff --git a/src/website/docs/go.html b/src/website/docs/go.html
new file mode 100644
index 0000000..6cff76a
--- /dev/null
+++ b/src/website/docs/go.html
@@ -0,0 +1,69 @@
+
Use Go byte slices and context cancellation over the native C ABI. Endpoints support concurrent calls and explicit cleanup.
Requires Go 1.24 or later, cgo enabled, a C compiler, and pkg-config. Install the C SDK first and set PKG_CONFIG_PATH to its lib/pkgconfig directory. On Windows, add the SDK's lib directory to PATH and use a cgo-compatible compiler.
+
go get github.com/cloudtoid/interprocess/src/go/v3@latest
+
The module's package name is interprocess. On Unix, the pkg-config flags include the installed library's runtime search path.
type Options struct {
+ Name, Path string
+ Capacity int
+}
+
Name identifies the queue. Empty Path uses the OS temporary directory; Windows ignores it. Capacity is message-buffer bytes, greater than 16 and divisible by 8. Options must match all other participants.
+
Publisher
+
OpenPublisher(o Options) (*Publisher, error)
+
Creates or joins the transient queue and registers a publisher. Defer Close after a successful open.
Returns bytes copied, whether a message was consumed, and an error. The boolean distinguishes an empty queue from an empty message. An undersized buffer truncates and consumes the entire message.
Waits for a message, closure, or context cancellation. Returns ctx.Err() for cancellation or deadline expiry. Pass context.Background() for an indefinite wait; do not pass a nil context.
+
(*Subscriber).Close() error
+
Waits for current native calls before releasing the handle. Outstanding receives observe ErrClosed on their next attempt. Repeated close is safe.
+
Errors
+
Use errors.Is with ErrInvalidArgument, ErrCapacityMismatch, ErrPublisherLimit, ErrExhausted, ErrCorrupt, ErrIO, ErrInternal, or ErrClosed. Full queues are reported through the send boolean, not a sentinel error. Context errors are context.Canceled or context.DeadlineExceeded.
+
Concurrency and scheduling
+
Do not copy endpoints after first use. Always close them; concurrent operations are protected against handle release. Each idle Receive uses a Go timer with 1–10 ms adaptive backoff, interrupted by context cancellation. It does not keep an OS thread blocked in cgo while idle. Prefer one receive loop per subscriber and distribute work after receiving.
+
This binding has no batch-send method. For lifetime and delivery guarantees, see queue concepts.
diff --git a/src/website/docs/node.html b/src/website/docs/node.html
new file mode 100644
index 0000000..54b20bb
--- /dev/null
+++ b/src/website/docs/node.html
@@ -0,0 +1,47 @@
+
Send typed byte arrays and receive Node Buffers, with promises and AbortSignal for waiting.
Requires Node.js 18 or later. Platform binaries install as optional packages; do not omit optional dependencies. TypeScript users need TypeScript 5.2 or later for the Symbol.dispose declarations. Linux prebuilt binaries require glibc 2.34 or later.
+
npm install @cloudtoid/interprocess
+
Send and receive
+
Save as example.mjs and run with node example.mjs. CommonJS can instead use require('@cloudtoid/interprocess').
+
import { Publisher, Subscriber } from '@cloudtoid/interprocess';
+
+const subscriber = new Subscriber('example', 65536);
+const publisher = new Publisher('example', 65536);
+try {
+ if (!publisher.trySend(Buffer.from('hello'))) {
+ throw new Error('Queue is full or recovering');
+ }
+ const message = await subscriber.receive({
+ signal: AbortSignal.timeout(1000)
+ });
+ console.log(message.toString('utf8'));
+} finally {
+ publisher.close();
+ subscriber.close();
+}
+
Publisher
+
new Publisher(name: string, capacity: number, path?: string)
+
Creates or joins a queue. The optional Unix directory defaults to the OS temporary directory and is ignored on Windows. All participants must use matching identity and capacity.
+
trySend(data: Uint8Array): boolean
+
Accepts Uint8Array, including Buffer. Returns true after committing the message, or false when full or recovering. Other failures throw.
+
trySendBatch(messages: Uint8Array[]): number
+
Returns the committed prefix length. A short count can mean full capacity, recovery, or a mid-batch error. Retry the unsent suffix to surface a persistent error. An error before any commit throws immediately. The batch is not atomic.
+
close(): void / [Symbol.dispose](): void
+
Releases the publisher. Repeated close is safe; operations after close throw ERR_CLOSED.
+
Subscriber
+
new Subscriber(name: string, capacity: number, path?: string)
+
Opens a competing subscriber with the same configuration rules as Publisher.
+
tryReceive(): Buffer | null
+
Consumes a ready message and returns an owned Buffer. null means no message is ready. An empty Buffer is a real message.
Checks immediately, then waits until a message arrives, the signal aborts, the endpoint closes, or an error occurs. Cancellation rejects with signal.reason. Use AbortSignal.timeout(milliseconds) for a deadline.
+
close(): void / [Symbol.dispose](): void
+
Releases the endpoint. Pending receives reject when they next observe closure. Repeated close is safe.
+
Errors
+
Queue failures expose an error.code: ERR_INVALID_ARGUMENT, ERR_CAPACITY_MISMATCH, ERR_PUBLISHER_LIMIT, ERR_EXHAUSTED, ERR_CORRUPT, ERR_IO, or ERR_CLOSED. Binding-level type errors can also occur for invalid JavaScript arguments.
+
ERR_NATIVE_UNAVAILABLE means the native addon could not load. Check the platform package, optional dependencies, and Linux glibc requirement, or build from source. Cancellation uses the signal's reason rather than a queue error code.
+
Scheduling and cleanup
+
Idle receives use timer backoff of 1, 2, 4, 8, then 10 ms, without occupying libuv workers. A new receive starts with an immediate check. Scheduling can delay timers and cancellation beyond those intervals. Prefer one receive loop per subscriber instead of many pending receives.
+
Always close both endpoints in a finally block or use explicit resource management where your runtime supports it. No public receive-into API is exposed by this binding. See transient queue lifetime before splitting publishers and subscribers into separate processes.
diff --git a/src/website/docs/overview.html b/src/website/docs/overview.html
new file mode 100644
index 0000000..83eaf2d
--- /dev/null
+++ b/src/website/docs/overview.html
@@ -0,0 +1,26 @@
+
Move bytes between processes with a shared-memory queue. Pick the API that fits your language; every implementation speaks the same v3 protocol.
Install the package for your language. Go also needs the C SDK.
Choose a short queue name and a capacity, such as 65536 bytes. On Unix, choose an explicit shared directory when processes use different runtimes.
Open a subscriber and a publisher using the same identity and capacity.
Send bytes. Check the result: a full queue needs an application-level retry or backpressure policy.
Receive bytes and close each endpoint when its work is finished.
+
+
Which receive should I use?
+
Use a nonblocking receive when your application already controls scheduling. Use a waiting receive when you want the library to wait for work. Reuse caller-owned buffers in Rust, Go, C, or .NET to avoid allocating a result buffer on each receive.
+
Language
Try once
Wait for work
+
Rust
try_recv()
recv() / recv_timeout(Duration)
+
Node.js
tryReceive()
await receive({ signal })
+
Go
TryReceive()
Receive(ctx)
+
C
cip_receive(handle, 0, &buffer)
cip_receive(handle, timeout_ms, &buffer)
+
Python
try_receive()
receive(timeout=seconds)
+
.NET
TryDequeue(out message)
Dequeue(cancellation)
+
+
Platforms and compatibility
+
The protocol targets little-endian, 64-bit Linux, macOS, and Windows on x86-64 and ARM64. Prebuilt package availability varies: check your language's installation section. All connected processes must use protocol v3. Package versions can differ while remaining compatible with that protocol.
+
Rust provides the native core behind C, Node.js, Python, and Go. .NET implements the same protocol independently. See queue concepts for delivery guarantees and benchmarks for measured throughput and latency.
diff --git a/src/website/docs/pages.json b/src/website/docs/pages.json
new file mode 100644
index 0000000..558e90e
--- /dev/null
+++ b/src/website/docs/pages.json
@@ -0,0 +1,10 @@
+[
+ {"slug":"", "label":"Overview", "title":"Developer documentation", "description":"Build fast cross-process messaging with Cloudtoid Interprocess. Installation guides and API references for Rust, Node.js, Go, C, Python, and .NET."},
+ {"slug":"concepts", "label":"Queue concepts", "title":"Queue lifetime, delivery, and interoperability", "description":"Understand transient queue lifetime, competing subscribers, capacity, message ordering, crash recovery, and cross-language compatibility in protocol v3."},
+ {"slug":"rust", "label":"Rust", "title":"Rust API reference", "description":"Install cloudtoid-interprocess and use Options, Publisher, and Subscriber. Reference for batch sends, reusable receive buffers, blocking waits, and errors."},
+ {"slug":"node", "label":"Node.js", "title":"Node.js & TypeScript API reference", "description":"Install @cloudtoid/interprocess. Send Uint8Array messages, receive Buffers, cancel with AbortSignal, and close endpoints using the Node.js API."},
+ {"slug":"go", "label":"Go", "title":"Go API reference", "description":"Use Cloudtoid Interprocess from Go with cgo. Configure Options, send and receive byte slices, reuse buffers, and cancel receives with context.Context."},
+ {"slug":"c", "label":"C", "title":"C API reference", "description":"Install the Cloudtoid Interprocess C SDK. Reference for handles, status codes, receive timeouts, owned buffers, and safe shutdown."},
+ {"slug":"python", "label":"Python", "title":"Python API reference", "description":"Build Cloudtoid Interprocess for Python. Send bytes and buffer objects, receive with timeouts, use context managers, and handle queue exceptions."},
+ {"slug":"dotnet", "label":".NET", "title":".NET API reference", "description":"Install Cloudtoid.Interprocess from NuGet. Use QueueFactory, QueueOptions, IPublisher, and ISubscriber with reusable buffers and CancellationToken."}
+]
diff --git a/src/website/docs/python.html b/src/website/docs/python.html
new file mode 100644
index 0000000..ea9f621
--- /dev/null
+++ b/src/website/docs/python.html
@@ -0,0 +1,39 @@
+
Send Python bytes and buffer objects through the shared Rust engine. Use context managers to keep endpoint lifetimes explicit.
The Python package is not yet published on PyPI. Requires Python 3.9 or later, Git, Rust, and a native linker. Run in an activated virtual environment:
from cloudtoid_interprocess import Publisher, Subscriber
+
+with Subscriber("example", 65536) as subscriber:
+ with Publisher("example", 65536) as publisher:
+ if not publisher.try_send(b"hello"):
+ raise RuntimeError("Queue is full or recovering")
+ message = subscriber.receive(timeout=1.0)
+ if message is None:
+ raise TimeoutError("No message arrived")
+ print(message.decode("utf-8"))
+
Publisher
+
Publisher(name, capacity, path=None)
+
Creates or joins the queue. name is a string, capacity is integer message-buffer bytes, and path is an optional filesystem path for Unix storage. The default is the OS temporary directory; Windows ignores path.
+
try_send(data) -> bool
+
Accepts bytes and objects implementing the buffer protocol, including bytearray and memoryview. Non-bytes inputs are snapshotted before sending. Returns False when full or recovering, True on commit; other failures raise.
+
try_send_batch(messages) -> int
+
Pass a list of bytes-like messages. Returns the committed prefix length. A short count can mean full capacity, recovery, or a mid-batch error. Retry only the unsent suffix. Errors before any commit are raised immediately; the batch is not transactional.
+
close() -> None
+
Releases the endpoint. Repeated close is safe. Publisher supports with via __enter__ and __exit__; leaving the block closes it without suppressing exceptions.
+
Subscriber
+
Subscriber(name, capacity, path=None)
+
Creates or joins the queue with the same configuration rules as Publisher.
+
try_receive() -> bytes | None
+
Consumes one ready message and returns bytes. None means no message is ready. b"" is a valid empty message, so test message is not None rather than truthiness.
+
receive(timeout=None) -> bytes | None
+
Blocks until delivery or timeout. Timeout is a finite nonnegative number of seconds; None waits indefinitely and zero attempts once. Returns None on timeout. Negative, infinite, and NaN timeout values raise ValueError.
+
close() -> None
+
Releases the subscriber. Repeated close is safe. Subscriber also supports with. A concurrent close waits for the current bounded native wait before releasing the handle.
+
Exceptions
+
InterprocessError
Base for queue-specific exceptions below, not for every possible API failure.
CapacityMismatchError
Existing capacity differs; also a ValueError.
PublisherLimitError
No publisher slot is available; also a RuntimeError.
CorruptQueueError
Shared state is invalid; also a RuntimeError.
ValueError
Invalid configuration, invalid timeout, or a closed endpoint.
OverflowError
Counter exhaustion or an integer outside a native argument's range.
OSError
Operating-system failure.
TypeError
Invalid argument type or unsupported buffer object.
+
Waiting, signals, and lifetime
+
Receive releases the GIL while waiting and checks Python signals between native waits of at most 100 ms, subject to scheduling. A received message is returned rather than discarded to report a later signal. There is no native asyncio API; use a worker thread with bounded timeouts for orderly shutdown. Cancelling an asyncio wrapper does not stop its already-running blocking call.
+
No public receive-into method is exposed. Close endpoints with context managers and keep their lifetimes overlapping across processes; see transient lifetime.
diff --git a/src/website/docs/rust.html b/src/website/docs/rust.html
new file mode 100644
index 0000000..2c5053e
--- /dev/null
+++ b/src/website/docs/rust.html
@@ -0,0 +1,46 @@
+
Use the native Rust core directly: send byte slices, receive owned vectors, or reuse your own storage.
Requires Rust 1.87 or later on a supported little-endian 64-bit platform.
+
cargo add cloudtoid-interprocess
+
Send and receive
+
This complete example keeps both endpoints alive. Separate processes use the same options; on Unix, add .with_path("/absolute/shared/directory") when their temporary directories differ.
+
use cloudtoid_interprocess::{Options, Publisher, Subscriber};
+
+fn main() -> cloudtoid_interprocess::Result<()> {
+ let options = Options::new("example", 65536);
+ let subscriber = Subscriber::open(&options)?;
+ let publisher = Publisher::open(&options)?;
+ publisher.try_send(b"hello")?;
+ let message = subscriber.try_recv()?.expect("message is ready");
+ assert_eq!(message, b"hello");
+ Ok(())
+}
Creates configuration using the OS temporary directory. Validation happens when opening an endpoint. Public fields are name: String, path: PathBuf, and capacity: usize. The struct is non-exhaustive; use the constructor rather than a struct literal.
+
with_path(self, path: impl Into<PathBuf>) -> Self
+
Sets the Unix backing directory. Windows ignores this option. Capacity is bytes, greater than 16 and divisible by 8; see identity rules.
Creates or joins the queue and registers a publisher. MAX_PUBLISHERS is 2048.
+
try_send(&self, message: &[u8]) -> Result<()>
+
Copies a message into the queue without waiting for space. Ok(()) means committed; Error::Full means full or temporarily recovering. Other errors must be handled separately.
Returns the committed prefix length. A short count, including zero, can indicate full capacity, recovery, or a mid-batch error. Retry only the unsent suffix to observe persistent errors. Errors before any commit are returned immediately. Batches can interleave with other publishers.
Blocks for up to the timeout, subject to scheduling and operation overhead. None means timeout. A zero duration attempts once. Received vectors belong to the caller.
+
Errors
+
Result<T> aliases std::result::Result<T, Error>. Error is non-exhaustive and implements Display and std::error::Error. Use error.is_full() for retryable admission failures.
+
Full
No space or recovery admission unavailable.
Invalid(&'static str)
Invalid options or message length.
CapacityMismatch
Existing queue capacity differs.
PublisherLimit
All publisher registrations are occupied.
Exhausted
A lifetime counter cannot advance; use a fresh queue.
Corrupt
Invalid shared queue state.
Io(std::io::Error)
An OS operation failed; available through the error source.
+
Waiting and cleanup
+
Endpoints release registrations on Drop. Keep at least one endpoint alive to retain the queue. Open endpoints after fork(). Blocking receives have no async-runtime integration: use a blocking worker with bounded timeouts if you need controlled shutdown from an async application. Aborting an async task does not cancel a Rust blocking receive already running on a worker.
+
+
diff --git a/src/website/index.html b/src/website/index.html
index df10b0f..86595ab 100644
--- a/src/website/index.html
+++ b/src/website/index.html
@@ -5,14 +5,14 @@
Cloudtoid Interprocess — Fast queues across processes and languages
-
+
Skip to content
- / interprocess
+ / interprocess
@@ -21,7 +21,7 @@
Interprocessv3
Fast, lightweight queues across processes and languages.
Rust · C · Python · Node.js · Go · .NET
Connect multiple publisher and subscriber processes through a shared circular buffer. Native atomic reservations, reusable memory, and no broker service. Built for high throughput on a single machine.
Preallocate queue storage and reuse receive buffers. The measured .NET send-and-receive path allocates 0 bytes per operation, reducing garbage-collection pressure.
02
Move bytes with very little work.
Native 64-bit atomic reservations and coalesced wakeups keep coordination lean. Send your existing binary format without a required serializer or wire protocol.
03
Keep the operating cost small.
No additional messaging service, broker machine, or per-message license fee. Run your processes on the same host and choose how much memory the queue uses.
-
LANGUAGE INTERFACES
One queue. Six language interfaces.
Rust, C, Python, Node.js, Go, and .NET can exchange messages through the same open v3 protocol. Pick the right language for each process.
Inspect the memory layout, atomic ordering, resource lifetime, and crash recovery. Build on an MIT-licensed implementation with tests across every publisher/subscriber language pair.
Built for volatile queues on one machine. For durable jobs, add application-level acknowledgements and persistence.