pub struct Engine { /* private fields */ }Expand description
The main Hypen engine that orchestrates reactive UI rendering.
§Architecture: Shared Engine, Namespaced State
Multi-module applications share a single Engine instance. Each module
registers its state under a lowercase-name prefix (e.g., search) so the
engine holds one merged state tree. The SDK layer (HypenModuleInstance in
TypeScript, ModuleInstance in Kotlin/Swift/Go) manages module lifecycles,
action routing, and cross-module communication – the engine itself only sees
a flat JSON state and resolves @{state.xxx} bindings against it.
§Multi-module Applications
-
One shared engine – all modules register their namespaced state into it. There is NOT one engine per module.
-
SDK-managed module instances – each SDK maintains multiple module instances (e.g.,
HypenModuleInstancein TypeScript), each with its own state tracking (Proxy in TS, ObservableState in Kotlin/Swift/Go). -
Cross-module communication uses
HypenGlobalContext:// In Search's action handler: const app = context.getModule<AppState>("App"); const currentView = app.getState().currentView; app.setState({ showSearch: true }); -
State binding scope: Each module’s template binds to its own state via the namespace prefix. Cross-module data flows through the global context, keeping each module’s reactive graph self-contained.
§Design Rationale
Keeping one shared engine avoids duplicating the parser, reconciler, and dependency graph per module. Namespaced state keys ensure modules don’t shadow each other’s fields while the engine’s path-based dependency tracker naturally scopes re-renders to only the affected module’s bindings.
Implementations§
Source§impl Engine
impl Engine
pub fn new() -> Self
Sourcepub fn register_component(&mut self, component: Component)
pub fn register_component(&mut self, component: Component)
Register a custom component
Sourcepub fn set_component_resolver<F>(&mut self, resolver: F)
pub fn set_component_resolver<F>(&mut self, resolver: F)
Set the component resolver for dynamic component loading The resolver receives (component_name, context_path) and should return ResolvedComponent { source, path } or None
Sourcepub fn register_resource(&mut self, name: &str, svg: &str)
pub fn register_resource(&mut self, name: &str, svg: &str)
Register a single resource from raw SVG content.
Sourcepub fn register_resources(&mut self, map: IndexMap<String, String>)
pub fn register_resources(&mut self, map: IndexMap<String, String>)
Register multiple resources from a name -> SVG map.
Sourcepub fn resource_registry(&self) -> &ResourceRegistry
pub fn resource_registry(&self) -> &ResourceRegistry
Get access to the resource registry
Sourcepub fn resource_registry_mut(&mut self) -> &mut ResourceRegistry
pub fn resource_registry_mut(&mut self) -> &mut ResourceRegistry
Get mutable access to the resource registry
Sourcepub fn icon_registry(&self) -> &ResourceRegistry
pub fn icon_registry(&self) -> &ResourceRegistry
Backwards-compatible alias
Sourcepub fn icon_registry_mut(&mut self) -> &mut ResourceRegistry
pub fn icon_registry_mut(&mut self) -> &mut ResourceRegistry
Backwards-compatible alias
Sourcepub fn set_module(&mut self, module: ModuleInstance)
pub fn set_module(&mut self, module: ModuleInstance)
Set the primary module instance (backward-compatible single-module API).
Sourcepub fn register_module(
&mut self,
name: impl Into<String>,
module: ModuleInstance,
)
pub fn register_module( &mut self, name: impl Into<String>, module: ModuleInstance, )
Register a named module for multi-module apps.
The engine scopes @{state.xxx} bindings to this module’s state when
rendering a component whose source starts with module <name> { ... }.
The name should be lowercase (e.g., "search").
Also registers the module’s declared actions in the action->module map
so that update_state after dispatch_action automatically routes
to the correct module.
Sourcepub fn get_module_state(&self, name: &str) -> Option<&Value>
pub fn get_module_state(&self, name: &str) -> Option<&Value>
Get a named module’s state (for reconciler lookups).
Sourcepub fn modules(&self) -> &IndexMap<String, ModuleInstance>
pub fn modules(&self) -> &IndexMap<String, ModuleInstance>
Get access to all registered modules (for reconciler).
Sourcepub fn set_render_callback<F>(&mut self, callback: F)
pub fn set_render_callback<F>(&mut self, callback: F)
Set the render callback
Sourcepub fn on_action<F>(&mut self, action_name: impl Into<String>, handler: F)
pub fn on_action<F>(&mut self, action_name: impl Into<String>, handler: F)
Register an action handler
Sourcepub fn render(&mut self, element: &Element)
pub fn render(&mut self, element: &Element)
Render an element tree (initial render or full re-render).
This accepts a flat Element. For sources that use ForEach, When,
or If, prefer [render_ir_node] which preserves first-class control flow.
Sourcepub fn render_ir_node(&mut self, ir_node: &IRNode)
pub fn render_ir_node(&mut self, ir_node: &IRNode)
Render an IRNode tree (initial render or full re-render).
Unlike [render], this accepts an IRNode (from ast_to_ir_node()),
which preserves ForEach, When, and If as first-class control-flow nodes.
This is the same path used by the WASM engine.
Sourcepub fn notify_state_change(&mut self, change: &StateChange)
pub fn notify_state_change(&mut self, change: &StateChange)
Handle a state change notification from a host that keeps its own state.
Use this when the host already mutated its own state copy and just
wants the engine to invalidate and re-render the affected nodes.
Engine-owned state should go through [update_state] / [update_state_sparse]
instead.
Uses an Arc-identity guard: if the primary module’s state Arc is
literally the same allocation as at the last notify_state_change
render, the call is a no-op. This catches SDK Proxy microtasks
re-firing after an explicit update_state already processed the
same change.
The guard uses Weak::upgrade + Arc::ptr_eq rather than raw
pointer equality so a dropped-and-reallocated Arc at the same
address can never be mistaken for the one we saw before.
Sourcepub fn update_state(&mut self, scope: Option<&str>, state_patch: Value)
pub fn update_state(&mut self, scope: Option<&str>, state_patch: Value)
Apply a state patch and re-render affected nodes.
scope selects the target module:
None→ primary module set viaset_moduleSome(name)→ named module registered via [register_module]
Skips rendering if the patch produces no actual state change.
Sourcepub fn update_state_sparse(
&mut self,
scope: Option<&str>,
paths: &[String],
values: &Value,
)
pub fn update_state_sparse( &mut self, scope: Option<&str>, paths: &[String], values: &Value, )
Apply a sparse state patch (path-value pairs) and re-render affected nodes.
See [update_state] for scope semantics.
Sourcepub fn dispatch_action(&mut self, action: Action) -> Result<(), EngineError>
pub fn dispatch_action(&mut self, action: Action) -> Result<(), EngineError>
Dispatch an action to its registered handler.
Sourcepub fn action_scope_for(&self, action_name: &str) -> Option<String>
pub fn action_scope_for(&self, action_name: &str) -> Option<String>
Look up which named module (by lowercased name) owns a given action.
Returns Some(name) when the action was registered via
[register_module]. Returns None for both “primary-module actions”
(declared on the module set via [set_module]) and “unknown actions”
— in both cases callers should route follow-up update_state calls
to the primary slot (scope None), which is the correct default.
Callers that host action handlers outside the engine (e.g., the Rust
SDK’s RemoteSession) can use this to route an incoming dispatch to
the correct module’s state without having to call
dispatch_action.
Sourcepub fn component_registry(&self) -> &ComponentRegistry
pub fn component_registry(&self) -> &ComponentRegistry
Get access to the component registry
Sourcepub fn component_registry_mut(&mut self) -> &mut ComponentRegistry
pub fn component_registry_mut(&mut self) -> &mut ComponentRegistry
Get mutable access to the component registry
Sourcepub fn resources(&self) -> &ResourceCache
pub fn resources(&self) -> &ResourceCache
Get access to the resource cache
Sourcepub fn resources_mut(&mut self) -> &mut ResourceCache
pub fn resources_mut(&mut self) -> &mut ResourceCache
Get mutable access to the resource cache
Sourcepub fn set_context(&mut self, name: &str, data: Value)
pub fn set_context(&mut self, name: &str, data: Value)
Set (or replace) a named data source context.
Registers the provider in the dependency graph (if not already known),
stores the data, and re-renders every node bound to @name.*.
This is the single entry point for all data source writes –
sparse merging (if needed) should happen at the SDK layer before
calling this method with the merged object.
§Example
engine.set_context("spacetime", json!({
"message": [{ "id": 1, "text": "Hello" }],
"user": [{ "id": 1, "name": "Alice" }]
}));Sourcepub fn remove_context(&mut self, name: &str)
pub fn remove_context(&mut self, name: &str)
Remove a data source context entirely.
Drops the provider’s state and re-renders bound nodes (they resolve to null).
Sourcepub fn data_sources(&self) -> &IndexMap<String, Value>
pub fn data_sources(&self) -> &IndexMap<String, Value>
Get read access to the data sources map.
Trait Implementations§
Auto Trait Implementations§
impl Freeze for Engine
impl !RefUnwindSafe for Engine
impl Send for Engine
impl Sync for Engine
impl Unpin for Engine
impl UnsafeUnpin for Engine
impl !UnwindSafe for Engine
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Erasable for T
impl<T> Erasable for T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> Paint for Twhere
T: ?Sized,
impl<T> Paint for Twhere
T: ?Sized,
Source§fn fg(&self, value: Color) -> Painted<&T>
fn fg(&self, value: Color) -> Painted<&T>
Returns a styled value derived from self with the foreground set to
value.
This method should be used rarely. Instead, prefer to use color-specific
builder methods like red() and
green(), which have the same functionality but are
pithier.
§Example
Set foreground color to white using fg():
use yansi::{Paint, Color};
painted.fg(Color::White);Set foreground color to white using white().
use yansi::Paint;
painted.white();Source§fn bright_black(&self) -> Painted<&T>
fn bright_black(&self) -> Painted<&T>
Source§fn bright_red(&self) -> Painted<&T>
fn bright_red(&self) -> Painted<&T>
Source§fn bright_green(&self) -> Painted<&T>
fn bright_green(&self) -> Painted<&T>
Source§fn bright_yellow(&self) -> Painted<&T>
fn bright_yellow(&self) -> Painted<&T>
Source§fn bright_blue(&self) -> Painted<&T>
fn bright_blue(&self) -> Painted<&T>
Source§fn bright_magenta(&self) -> Painted<&T>
fn bright_magenta(&self) -> Painted<&T>
Source§fn bright_cyan(&self) -> Painted<&T>
fn bright_cyan(&self) -> Painted<&T>
Source§fn bright_white(&self) -> Painted<&T>
fn bright_white(&self) -> Painted<&T>
Source§fn bg(&self, value: Color) -> Painted<&T>
fn bg(&self, value: Color) -> Painted<&T>
Returns a styled value derived from self with the background set to
value.
This method should be used rarely. Instead, prefer to use color-specific
builder methods like on_red() and
on_green(), which have the same functionality but
are pithier.
§Example
Set background color to red using fg():
use yansi::{Paint, Color};
painted.bg(Color::Red);Set background color to red using on_red().
use yansi::Paint;
painted.on_red();Source§fn on_primary(&self) -> Painted<&T>
fn on_primary(&self) -> Painted<&T>
Source§fn on_magenta(&self) -> Painted<&T>
fn on_magenta(&self) -> Painted<&T>
Source§fn on_bright_black(&self) -> Painted<&T>
fn on_bright_black(&self) -> Painted<&T>
Source§fn on_bright_red(&self) -> Painted<&T>
fn on_bright_red(&self) -> Painted<&T>
Source§fn on_bright_green(&self) -> Painted<&T>
fn on_bright_green(&self) -> Painted<&T>
Source§fn on_bright_yellow(&self) -> Painted<&T>
fn on_bright_yellow(&self) -> Painted<&T>
Source§fn on_bright_blue(&self) -> Painted<&T>
fn on_bright_blue(&self) -> Painted<&T>
Source§fn on_bright_magenta(&self) -> Painted<&T>
fn on_bright_magenta(&self) -> Painted<&T>
Source§fn on_bright_cyan(&self) -> Painted<&T>
fn on_bright_cyan(&self) -> Painted<&T>
Source§fn on_bright_white(&self) -> Painted<&T>
fn on_bright_white(&self) -> Painted<&T>
Source§fn attr(&self, value: Attribute) -> Painted<&T>
fn attr(&self, value: Attribute) -> Painted<&T>
Enables the styling Attribute value.
This method should be used rarely. Instead, prefer to use
attribute-specific builder methods like bold() and
underline(), which have the same functionality
but are pithier.
§Example
Make text bold using attr():
use yansi::{Paint, Attribute};
painted.attr(Attribute::Bold);Make text bold using using bold().
use yansi::Paint;
painted.bold();Source§fn rapid_blink(&self) -> Painted<&T>
fn rapid_blink(&self) -> Painted<&T>
Source§fn quirk(&self, value: Quirk) -> Painted<&T>
fn quirk(&self, value: Quirk) -> Painted<&T>
Enables the yansi Quirk value.
This method should be used rarely. Instead, prefer to use quirk-specific
builder methods like mask() and
wrap(), which have the same functionality but are
pithier.
§Example
Enable wrapping using .quirk():
use yansi::{Paint, Quirk};
painted.quirk(Quirk::Wrap);Enable wrapping using wrap().
use yansi::Paint;
painted.wrap();Source§fn clear(&self) -> Painted<&T>
👎Deprecated since 1.0.1: renamed to resetting() due to conflicts with Vec::clear().
The clear() method will be removed in a future release.
fn clear(&self) -> Painted<&T>
renamed to resetting() due to conflicts with Vec::clear().
The clear() method will be removed in a future release.
Source§fn whenever(&self, value: Condition) -> Painted<&T>
fn whenever(&self, value: Condition) -> Painted<&T>
Conditionally enable styling based on whether the Condition value
applies. Replaces any previous condition.
See the crate level docs for more details.
§Example
Enable styling painted only when both stdout and stderr are TTYs:
use yansi::{Paint, Condition};
painted.red().on_yellow().whenever(Condition::STDOUTERR_ARE_TTY);