hibana 0.9.6

Choreography-derived runtime enforcement kernel for no_std Rust multiparty protocols
Documentation
#![no_std]
#![deny(clippy::wildcard_enum_match_arm)]
#![deny(unsafe_op_in_unsafe_fn)]
#![deny(private_bounds)]
#![deny(private_interfaces)]
#![deny(rustdoc::broken_intra_doc_links)]
#![deny(rustdoc::private_intra_doc_links)]
#![doc(html_no_source)]
#![recursion_limit = "256"]

//! Hibana is a Rust 2024 `no_std` / no-alloc-oriented runtime whose
//! choreography-derived enforcement kernel executes compact per-role protocol
//! descriptors.
//!
//! The crate intentionally has two faces:
//!
//! - app authors use [`g`] and [`Endpoint`];
//! - protocol implementors use [`runtime`] and [`runtime::program`].
//!
//! Everything starts from one global choreography and ends in a compact
//! role-local endpoint:
//!
//! ```text
//! g choreography -> project role program -> attach endpoint -> drive endpoint
//! ```
//!
//! ## App path
//!
//! Start with the complete two-role example from a Hibana repository checkout:
//!
//! ```text
//! cargo run --example ping_pong
//! ```
//!
//! The [runnable source](https://github.com/hibanaworks/hibana/blob/main/examples/ping_pong.rs)
//! defines one [`g`] choreography, projects both roles, attaches their endpoints,
//! and executes the protocol. Application code then drives the endpoint that its
//! protocol crate attached.
//!
//! The endpoint API is deliberately small:
//!
//! - [`Endpoint::send`] sends the next projected message;
//! - [`Endpoint::recv`] receives a message after descriptor evidence matches;
//! - [`Endpoint::offer`] observes a route branch;
//! - [`RouteBranch::label`] reports the selected arm's first logical label;
//! - [`RouteBranch::recv`] receives the first payload in a selected receive arm;
//! - [`RouteBranch::send`] sends the first payload in a selected send arm.
//!
//! A route branch whose selected arm begins with a send is handled by
//! [`RouteBranch::send`]. Dropping the returned future restores the branch
//! preview before any progress commits.
//! Successful sends, receives, and route branch first-step operations consume
//! progress.
//!
//! ```rust,ignore
//! let branch = server.offer().await?;
//! match branch.label() {
//!     10 => {
//!         let value = branch.recv::<g::Msg<10, [u8; 4]>>().await?;
//!     }
//!     11 => {
//!         branch.recv::<g::Msg<11, ()>>().await?;
//!     }
//!     label => panic!("unexpected route label {label}"),
//! }
//! ```
//!
//! ## Protocol path
//!
//! Protocol crates compose prefixes around an app choreography, project a
//! role-local witness, bind transport state, and return an attached endpoint.
//!
//! ```rust,ignore
//! use hibana::{g, runtime};
//! use hibana::runtime::program::{RoleProgram, project};
//!
//! let program = g::seq(transport_prefix, app);
//! let role0: RoleProgram<0> = project(&program);
//!
//! // `runtime_slab: &mut [u8]` is supplied from the measured deployment budget.
//! let mut kit_storage = runtime::SessionKitStorage::<MyTransport>::uninit();
//! let kit = kit_storage.init();
//! let rv = kit.rendezvous(runtime_slab, transport)?;
//! let endpoint = rv.enter(sid, &role0)?;
//! ```
//!
//! Runtime capacities are derived from Hibana's wire/domain limits and
//! projected descriptors, not chosen by callers.
//! Hidden timeout fuses are not protocol API or attach config.
//! Protocol-invisible carrier watchdogs live inside the transport implementation:
//! terminal I/O waits are reported as [`runtime::transport::TransportError`]
//! from `poll_send` or `poll_recv`, not as Hibana timeout branches.
//!
//! [`runtime::transport::Transport`] owns I/O readiness, wire buffers, and
//! ingress demux evidence. [`runtime::resolver`] owns dynamic resolver input.
//! None of those layers become app concepts.
//!
//! ## Payloads, receive evidence, and resolvers
//!
//! Payload types implement [`runtime::wire::WireEncode`] for sends and
//! [`runtime::wire::WirePayload`] for receives. Decoded values may borrow from
//! the received frame. Built-in exact codecs cover `()`, integers, `bool`,
//! byte slices, and fixed byte arrays.
//!
//! Branch choice is either an in-band protocol message, a projected first
//! visible endpoint operation confirmed by descriptor-checked receive evidence,
//! or an explicit resolver decision. Transport evidence is descriptor evidence
//! only; it is not route authority and it does not create a public
//! branch-authority catalogue.
//!
//! ## Boundary contract
//!
//! Hibana keeps the public API small because the projection boundary carries the
//! proof work:
//!
//! - route shape, ambiguous simultaneous endpoint operations, and intrinsic
//!   route controller mismatch are rejected before runtime;
//! - parallel composition rejects empty arms and ambiguous simultaneous endpoint
//!   operations;
//! - labels are choreography identities, while transport frame labels are
//!   descriptor facts;
//! - endpoint progress is affine: successful sends, receives, and route branch
//!   first-step operations commit progress, while dropped previews restore the
//!   endpoint;
//! - `EndpointError` fails closed, carries compact endpoint operation evidence,
//!   and never authorizes hidden progress.
//!
#[cfg(test)]
extern crate self as hibana;

#[cfg(test)]
extern crate std;

#[cfg(all(test, hibana_repo_tests))]
mod test_support;

// ============================================================================
// Public modules (application-facing)
// ============================================================================

pub mod g;
/// Global-to-Local projection (MPST theory layer)
mod global;
/// Runtime surface for protocol implementors.
pub mod runtime;

mod session;

mod runtime_core;

mod transport;

mod local;

/// Session endpoints (affine-typed consuming futures)
mod endpoint;

mod observe;

// ============================================================================
// Private modules
// ============================================================================
mod eff;

#[cold]
#[inline(never)]
#[track_caller]
pub(crate) const fn invariant() -> ! {
    panic!()
}

#[inline]
#[track_caller]
pub(crate) fn invariant_some<T>(value: Option<T>) -> T {
    match value {
        Some(value) => value,
        None => invariant(),
    }
}

#[inline]
#[track_caller]
pub(crate) fn invariant_ok<T, E>(value: Result<T, E>) -> T {
    match value {
        Ok(value) => value,
        Err(_) => invariant(),
    }
}

/// Rendezvous owner for local session, lane, and route state.
///
/// Application code uses [`Endpoint`] for choreography execution and
/// [`runtime::SessionKit`] for runtime coordination. This module stays internal;
/// tests reach it through crate-private coverage, not through a third public
/// face.
mod rendezvous;

// ============================================================================
// Re-exports (curated public API)
// ============================================================================

// Endpoint facade
pub use endpoint::{Endpoint, EndpointError, RouteBranch};