2026-08-31 21:01:50 +09:00
2026-08-31 21:01:50 +09:00
2026-08-31 21:01:50 +09:00
2026-08-31 21:01:50 +09:00
2026-08-31 21:01:50 +09:00

wip-rs

Rust building blocks for the Web Interface Protocol (WIP).

Interface authoring

Applications depend on wip-interface, normally imported as wip:

use wip_interface as wip;

#[derive(wip::WipType)]
struct Message {
    /// Message body.
    text: String,
}

#[wip::interface]
pub trait Messenger {
    /// Sends a message.
    ///
    /// # Returns
    /// Whether the application accepted the message.
    fn send(
        &self,
        /// Message to send.
        message: Message,
    ) -> wip::OperationResult<bool>;
}

The interface attribute and WipType derive are re-exported by the facade; users do not import wip-interface-macros directly. The generated MessengerDefinition constructs an InterfaceDescriptor, decodes named arguments, encodes results, validates both boundaries, and provides typed dispatch for any T: Messenger.

Type mapping

Rust Protocol
() as an operation result no returned value
bool boolean
integer primitives JavaScript-lossless integer
f32, f64 finite number
String string
wip::Bytes bytes
wip::wip_protocol::JsonValue JSON
wip::Entry<K, V> entry
Vec<T> list
named-field #[derive(wip::WipType)] struct named record
all-unit #[derive(wip::WipType)] enum named enum
all-newtype #[derive(wip::WipType)] enum named tagged union

Option<T> is accepted only for a direct DTO field or operation parameter and means that the named value may be omitted. It is not protocol null. Domain failures are modeled in the application result (usually a derived union) and returned through Ok; wip::HostError is only for host/runtime failures.

Rust doc comments become descriptor metadata. For an operation, a # Returns section documents the return declaration; text before that section documents the operation itself.

The supported interface slice is deliberately non-generic: public traits, &self, named parameters, and OperationResult<T>. Generic traits or methods, associated items, custom lifetimes, inheritance, default method bodies, and other receiver forms are rejected at their source spans.

Host publication and dispatch

Applications use wip-host to register generated definitions and explicitly choose the ordered interface set for each object publication:

let mut interfaces = wip_host::InterfaceRegistry::new();
let messenger = interfaces.register(MessengerDefinition, None)?;

let published = wip_host::PublishedObject::new(request_scoped_object)
    .expose(&messenger)?;
let protocol_object = published.protocol_object();

expose compiles only when the object implements the generated definition's interface trait. Implementing a trait does not expose it automatically, empty interface sets are valid, insertion order is preserved, and duplicate references are rejected. Registry references are opaque; descriptor names and Rust type names are not used as wire identity.

Dispatch is qualified by interface reference and operation name. The host checks current object identity and validator policy, current interface membership, interface validator, descriptor operation, arguments, and result while retaining the selected object and registered artifact. Host-private fields and backend handles are never projected by WipObject.

Providers remain responsible for backend atomicity. Enter a transaction, lock, stable-handle scope, or conditional-update primitive before constructing and dispatching the request-scoped PublishedObject, and retain it until dispatch returns. The runtime never validates one object and then resolves a second snapshot, but it cannot make an arbitrary external backend atomic by itself.

S
Description
No description provided
Readme
1 MiB
Languages
Rust 100%