Skip to main content

frame_host/
spec.rs

1//! The embedding seam's application contract (design §4.2): everything an
2//! embedding application supplies; frame-host supplies nothing.
3//!
4//! An [`AppSpec`] carries the application's component installs, its stated
5//! runtime policy (no field has a default — frame supplies no lifecycle
6//! defaults), a post-start readiness proof, and the application's fact
7//! announcements. [`crate::application::run_application`] boots the full
8//! stack around it; frame-host's own binary is the first consumer
9//! ([`crate::app`]), the generated scaffold the second.
10
11use frame_core::component::ComponentMeta;
12use frame_core::registry::ComponentRegistry;
13use frame_core::runtime::RuntimePolicy;
14use thiserror::Error;
15
16use crate::announcer::Announcer;
17
18/// A typed failure raised by the embedding application's own hooks (the
19/// readiness proof or the fact announcement), carried into
20/// [`crate::error::HostError::Application`].
21#[derive(Debug, Error)]
22#[error("{detail}")]
23pub struct AppError {
24    detail: String,
25}
26
27impl AppError {
28    /// Wraps the application's own failure detail.
29    #[must_use]
30    pub fn new(detail: impl Into<String>) -> Self {
31        Self {
32            detail: detail.into(),
33        }
34    }
35}
36
37/// One component the application installs: its manifest, its compiled
38/// bytecode, and any support (e.g. FFI) modules that must be loaded before
39/// the component starts and unloaded in order at teardown.
40pub struct ComponentInstall {
41    /// The component's full manifest (identity, children, supervision,
42    /// declared capability needs).
43    pub meta: ComponentMeta,
44    /// The component's compiled BEAM bytecode.
45    pub bytecode: Vec<u8>,
46    /// Compiled support modules loaded before the component starts, in the
47    /// given order, and unloaded in reverse order at teardown.
48    pub support_modules: Vec<Vec<u8>>,
49}
50
51/// The post-start readiness proof, run once before the bus boots: the
52/// application's own bounded check that its components are genuinely live
53/// (e.g. a mailbox liveness probe).
54pub type ReadinessProbe = Box<dyn FnOnce(&ComponentRegistry) -> Result<(), AppError> + Send>;
55
56/// The application's boot-time fact announcement, run once after the
57/// announcer connects: the application publishes its own real facts (e.g. a
58/// stored entity id) through the announcer.
59pub type FactAnnouncement =
60    Box<dyn FnOnce(&ComponentRegistry, &Announcer) -> Result<(), AppError> + Send>;
61
62/// Everything an embedding application supplies; frame-host supplies nothing
63/// (design §4.2).
64pub struct AppSpec {
65    /// Component registrations: metadata + component bytecode + support
66    /// modules. Must be non-empty — a host with nothing to host is refused
67    /// as a typed composition error at boot.
68    pub components: Vec<ComponentInstall>,
69    /// Runtime policy (threads, operation timeout) — stated by the
70    /// application, no defaults.
71    pub policy: RuntimePolicy,
72    /// Post-start proof run once before the bus boots and serving begins.
73    pub readiness: ReadinessProbe,
74    /// Application-announced facts, published once the announcer is
75    /// connected. Skipped with a loud log when no `[frame].channel` is
76    /// declared (no announcer exists to carry them).
77    pub announce: FactAnnouncement,
78}