phoxal 0.18.0

Phoxal — production-oriented autonomous robot framework (engine, model, typed bus, contracts).
Documentation
//! # phoxal
//!
//! A production-oriented framework for autonomous robots.
//!
//! Phoxal gives a robot a small, strongly-typed core: a contract bus over
//! [Zenoh](https://zenoh.io), a single dated API version per robot graph, and a
//! runtime authoring model where one struct of typed handles plus a couple of
//! attribute macros is a complete participant. The framework owns the awkward
//! parts - argument parsing, bus connection, scheduling, query serving,
//! shutdown, and health - so the code you write is the robot's behavior, not its
//! plumbing.
//!
//! Three ideas hold it together:
//!
//! - **A typed contract bus.** Every message is a plain serde body bound to one
//!   contract family and one API version. Handles are body-typed
//!   ([`Publisher<T>`](bus::Publisher), [`Subscriber<T>`](bus::Subscriber),
//!   [`Latest<T>`](bus::Latest), [`Querier<Req, Resp>`](bus::Querier)), so the
//!   compiler - not a runtime check - rejects sending the wrong type on a topic.
//! - **One dated API version per graph.** API versions are dated modules
//!   ([`api::y2026_1`], …), not semver crates. A runtime authors against exactly
//!   one of them; mixing bodies from two versions is a compile error.
//! - **Runtimes are authored, not wired.** You write a struct and an `impl`; the
//!   [`#[derive(Runtime)]`](macro@Runtime) and [`#[phoxal::runtime]`](macro@runtime)
//!   macros derive the static metadata, and [`run`] turns the type into a binary.
//!
//! ## Author a runtime
//!
//! A runtime is one struct of typed handles and one annotated inherent `impl`.
//! The struct declares the contracts it uses (as handle fields) and its one API
//! version; the `impl` declares the lifecycle. This is the whole getting-started
//! surface:
//!
//! ```ignore
//! use phoxal::api::y2026_1 as api;   // select ONE dated API version
//! use phoxal::prelude::*;
//!
//! #[derive(phoxal::Runtime)]
//! #[phoxal(id = "avoid-obstacles", api = y2026_1)]
//! struct AvoidObstacles {
//!     state:  Latest<api::drive::State>,    // keep-last view of the drive state
//!     target: Publisher<api::drive::Target>, // commanded drive target
//! }
//!
//! #[phoxal::runtime]
//! impl AvoidObstacles {
//!     #[setup]
//!     async fn setup(ctx: &mut SetupContext<Self>) -> Result<Self> {
//!         Ok(Self {
//!             // api-local topic builders bind each handle to this API version
//!             state:  ctx.subscribe(api::topic::new().drive().state()).latest().await?,
//!             target: ctx.publisher(api::topic::new().drive().target()).await?,
//!         })
//!     }
//!
//!     #[step(hz = 50)]
//!     async fn step(&mut self, step: StepContext) -> Result<()> {
//!         let now = step.time();
//!         self.target.publish_at(now, api::drive::Target {
//!             linear_x_mps: 0.2,
//!             angular_z_radps: 0.0,
//!             curvature_limit_radpm: None,
//!         }).await?;
//!         Ok(())
//!     }
//! }
//!
//! fn main() -> phoxal::Result<()> { phoxal::run::<AvoidObstacles>() }
//! ```
//!
//! What each piece does:
//!
//! - `use phoxal::api::y2026_1 as api;` and `#[phoxal(api = y2026_1)]` pick the
//!   runtime's single API version. Every handle body type comes through `api::…`;
//!   switching versions is a one-line edit at the top plus the attribute.
//! - Handle fields name version-local bodies ([`Publisher<api::drive::Target>`](bus::Publisher),
//!   [`Latest<api::drive::State>`](bus::Latest)). A body from another API version
//!   does not compile.
//! - All handles are built in `#[setup]` from api-local topic builders
//!   (`api::topic::new().drive().state()`); long-lived ones become struct fields.
//! - `#[step(hz = ...)]` is the scheduled control loop; the runner owns timing and
//!   delivers logical time via [`StepContext`](runtime::StepContext). Query servers
//!   use `#[server]` / `#[server_snapshot]`, and `#[shutdown]` runs graceful
//!   cleanup before the bus closes.
//! - `fn main() -> phoxal::Result<()> { phoxal::run::<R>() }` is the default
//!   blocking entrypoint. For a custom Tokio main, call
//!   [`phoxal::tokio::run::<R>().await`](tokio::run).
//!
//! The runner also exposes an `emit-apis` subcommand
//! (`cargo run --example runtime_control_loop emit-apis`) that prints a runtime's
//! static metadata as one JSON document and exits, without opening the bus. Worked
//! examples live in `phoxal/examples/`.
//!
//! ## Where to look next
//!
//! - [`api`] - the dated API-version modules (`y2026_1`, …): version-local wire
//!   bodies, the [`ApiVersion`](api::ApiVersion) / [`ContractBody`](api::ContractBody)
//!   traits, and the api-local topic builders, all generated by
//!   [`phoxal_api_tree!`](macro@phoxal_macros::phoxal_api_tree).
//! - [`prelude`] - everything a runtime author imports with
//!   `use phoxal::prelude::*;`: the handle types, [`SetupContext`](runtime::SetupContext) /
//!   [`StepContext`](runtime::StepContext), and [`Result`].
//! - [`mod@runtime`] - the authoring surface behind the macros: the static metadata
//!   traits, the contexts, the clock and scheduler, and the runner
//!   ([`run`] / [`tokio::run`]).
//! - [`bus`] - the Zenoh-native `bus_abi` boundary: the key scheme, the
//!   MessagePack codec, the [`BusMetadata`](bus::BusMetadata) attachment, and the
//!   body-typed handles.
//! - [`model`] - the authored manifest schemas (`robot.yaml`, `structure.urdf`,
//!   `component.yaml`, …) that runtimes and the CLI parse.
//! - The **official runtime set** ships alongside this crate in the workspace
//!   `runtime/` tree (`drive`, `localize`, `map`, `safety`, …): full platform
//!   runtimes authored on exactly this surface, useful as reference reading.

// Generated macro output refers to the framework as `::phoxal::…`; make that path
// resolve to this crate so the macros work both inside and outside the engine.
extern crate self as phoxal;

pub mod api;
pub mod bus;
pub mod model;
pub mod runtime;
pub mod util;

/// The framework result type (`anyhow`-backed). Authoring code uses bare
/// `Result<T>` via the [`prelude`].
pub use anyhow::Result;

/// Derive the static metadata for a runtime struct. See the crate docs.
pub use phoxal_macros::Runtime;

/// The bare `#[phoxal::runtime]` attribute for a runtime's inherent impl.
pub use phoxal_macros::runtime;

#[doc(inline)]
pub use phoxal_macros::phoxal_api_tree;

/// Re-exported so runtime config types can derive/implement
/// `phoxal::schemars::JsonSchema`, which feeds `emit-apis` config schemas.
pub use schemars;

/// Run a runtime to completion on a framework-owned blocking Tokio runtime.
///
/// This is the default binary entrypoint:
/// `fn main() -> phoxal::Result<()> { phoxal::run::<Runtime>() }`.
pub use runtime::run;

/// Async host runner entrypoints for custom Tokio mains
/// (`phoxal::tokio::run::<Runtime>().await`).
pub mod tokio {
    #[doc(inline)]
    pub use crate::runtime::run_async as run;
}

/// Everything a runtime author imports with `use phoxal::prelude::*;`.
pub mod prelude {
    pub use crate::Result;
    pub use crate::bus::{Latest, Publisher, Querier, QueryError, ServerResult, Subscriber};
    pub use crate::runtime::{LogicalTime, SetupContext, ShutdownContext, Snapshot, StepContext};
}