Program

Struct Program 

Source
pub struct Program<M: Model> { /* private fields */ }
Expand description

The main program that runs your application

Implementations§

Source§

impl<M: Model> Program<M>
where M::Message: Clone,

Source

pub fn new(model: M) -> Result<Self>

Create a new program with the given model

Source

pub fn with_options(model: M, options: ProgramOptions) -> Result<Self>

Create a new program with custom options

Source

pub fn with_filter<F>(self, filter: F) -> Self
where F: Fn(&M, Event<M::Message>) -> Option<Event<M::Message>> + Send + Sync + 'static,

Set a message filter function

Source

pub fn with_priority_config(self, config: PriorityConfig) -> Self

Configure the priority event processor

Source

pub fn event_stats(&self) -> EventStats

Get current event processing statistics

Source

pub fn event_stats_string(&self) -> String

Get a formatted string of event statistics (useful for debugging)

Source

pub fn printf(&self, args: Arguments<'_>)

Print formatted text to stderr

Source

pub fn println(&self, text: &str)

Print a line to stderr

Source

pub fn quit(&self)

Send a quit message to the running program

Source

pub fn kill(&self)

Force kill the program immediately

This method forcefully terminates the program without any cleanup. Unlike quit() which sends a quit message through the event loop, kill() immediately stops execution.

§Use Cases
  • Emergency shutdown when the program is unresponsive
  • Testing scenarios requiring immediate termination
  • Signal handlers that need to stop the program immediately
§Example
// In a signal handler or emergency shutdown
program.kill();
§Note

This bypasses normal cleanup procedures. Prefer quit() for graceful shutdown.

Source

pub fn metrics(&self) -> AdvancedEventStats

Get advanced performance metrics

Source

pub fn resource_stats(&self) -> ResourceStats

Get resource usage statistics

Source

pub fn metrics_json(&self) -> String

Export metrics in JSON format

Source

pub fn metrics_prometheus(&self) -> String

Export metrics in Prometheus format

Source

pub fn metrics_text(&self) -> String

Export metrics in plain text format

Source

pub fn metrics_dashboard(&self) -> String

Display metrics dashboard (for debugging)

Source

pub fn reset_metrics(&self)

Reset all metrics

Source

pub fn resize_queue(&self, new_size: usize) -> Result<()>

Dynamically resize the event queue

Source

pub fn queue_capacity(&self) -> usize

Get current queue capacity

Source

pub fn enable_auto_scaling(&mut self, config: AutoScaleConfig) -> &mut Self

Enable auto-scaling with the specified configuration

Source

pub fn with_auto_scaling(self) -> Self

Enable auto-scaling with default configuration

Source

pub fn disable_auto_scaling(&mut self) -> &mut Self

Disable auto-scaling

Source

pub fn sender(&self) -> Option<SyncSender<Event<M::Message>>>

Get a sender for injecting events from external sources

This allows external async tasks to send messages to the program’s event loop. The sender is thread-safe and can be cloned for use in multiple threads.

§Example
let mut program = Program::new(model)?;
let sender = program.sender();

std::thread::spawn(move || {
    loop {
        std::thread::sleep(Duration::from_secs(1));
        let _ = sender.send(Event::User(Msg::Tick));
    }
});

program.run()?;
Source

pub fn send_message(&self, msg: M::Message) -> Result<()>

Send a user message to the program

Convenience method that wraps the message in Event::User.

§Example
program.send_message(Msg::DataLoaded(data))?;
Source

pub fn wait(&self)

Wait for the program to finish

Source

pub fn release_terminal(&mut self) -> Result<()>

Release the terminal

Source

pub fn restore_terminal(&mut self) -> Result<()>

Restore the terminal

Source

pub fn init_async_bridge(&mut self) -> SyncSender<Event<M::Message>>

Initialize the async message bridge for external event injection

This sets up channels for external systems to send messages into the program’s event loop. Must be called before run() if you need external message injection.

§Use Cases
  • WebSocket Integration: Forward messages from WebSocket connections
  • File Watchers: Send events when files change
  • Timers: Implement custom scheduling beyond tick/every
  • Database Listeners: Forward change notifications
  • IPC: Receive messages from other processes
  • HTTP Responses: Send results from async HTTP requests
§Thread Safety

The returned sender can be cloned and shared across multiple threads safely. Messages are queued with a capacity of 100 by default.

§Example
use hojicha_runtime::{Program, Event};
use hojicha_core::{Model, Cmd};

#[derive(Clone, Debug)]
struct MyModel;

#[derive(Clone, Debug)]  
enum MyMsg { Hello }

impl Model for MyModel {
    type Message = MyMsg;
    fn init(&mut self) -> Cmd<Self::Message> { Cmd::noop() }
    fn update(&mut self, _msg: Event<Self::Message>) -> Cmd<Self::Message> { Cmd::noop() }
    fn view(&self) -> String { "test".to_string() }
}

let mut program = Program::new(MyModel).unwrap();
let sender = program.init_async_bridge();

// Send an external event from another thread
sender.send(Event::User(MyMsg::Hello)).ok();
Source

pub fn subscribe<S>(&mut self, stream: S) -> Subscription
where S: Stream<Item = M::Message> + Send + 'static, M::Message: Send + 'static,

Subscribe to an async stream of events

Connects any futures::Stream to your program’s event loop. Each item from the stream is automatically wrapped in Event::User and sent to your model’s update function.

§Use Cases
  • WebSocket/SSE: Stream real-time messages
  • File Watching: Monitor file system changes
  • Periodic Tasks: Custom intervals and scheduling
  • Database Changes: Listen to change streams
  • Sensor Data: Process continuous data streams
§Cancellation

The returned Subscription handle allows graceful cancellation. The subscription is also automatically cancelled when dropped.

§Examples
§Timer Stream
use tokio_stream::wrappers::IntervalStream;
use std::time::Duration;

let interval = tokio::time::interval(Duration::from_secs(1));
let stream = IntervalStream::new(interval)
    .map(|_| Msg::Tick);
let subscription = program.subscribe(stream);
§WebSocket Stream
let ws_stream = websocket.messages()
    .filter_map(|msg| msg.ok())
    .map(|msg| Msg::WebSocketMessage(msg));
let subscription = program.subscribe(ws_stream);
§File Watcher Stream
let file_stream = watch_file("/path/to/file")
    .map(|event| Msg::FileChanged(event));
let subscription = program.subscribe(file_stream);
Source

pub fn spawn_cancellable<F, Fut, T>(&self, f: F) -> AsyncHandle<T>
where F: FnOnce(CancellationToken) -> Fut, Fut: Future<Output = T> + Send + 'static, T: Send + 'static,

Spawn a cancellable async operation

Spawns a long-running async task with cooperative cancellation support. The task receives a CancellationToken for checking cancellation status.

§Use Cases
  • Background Processing: Data analysis, file processing
  • Network Operations: Long polling, streaming downloads
  • Periodic Tasks: Health checks, metrics collection
  • Resource Monitoring: CPU/memory monitoring
  • Cleanup Tasks: Temporary file cleanup, cache management
§Cancellation Pattern

Tasks should periodically check the cancellation token and exit gracefully when cancelled. Use tokio::select! for responsive cancellation.

§Examples
§Background File Processing
let handle = program.spawn_cancellable(|token| async move {
    for file in large_file_list {
        if token.is_cancelled() {
            return Err("Cancelled");
        }
        process_file(file).await?;
    }
    Ok("All files processed")
});
§Long Polling
let handle = program.spawn_cancellable(|token| async move {
    loop {
        tokio::select! {
            _ = token.cancelled() => {
                break Ok("Polling cancelled");
            }
            result = poll_server() => {
                handle_result(result)?;
            }
        }
    }
});

// Cancel when user navigates away
if user_navigated_away {
    handle.cancel().await;
}
Source

pub fn spawn_cancellable_cmd<F, Fut>(&mut self, f: F) -> AsyncHandle<()>
where F: FnOnce(CancellationToken, SyncSender<Event<M::Message>>) -> Fut, Fut: Future<Output = ()> + Send + 'static, M::Message: Send + 'static,

Spawn a cancellable async operation that sends messages

Similar to spawn_cancellable but specifically for operations that produce messages for the program.

§Example
let handle = program.spawn_cancellable_cmd(|token, sender| async move {
    while !token.is_cancelled() {
        let data = fetch_data().await;
        let _ = sender.send(Event::User(Msg::DataReceived(data)));
        tokio::time::sleep(Duration::from_secs(1)).await;
    }
});
Source

pub fn spawn<Fut>(&mut self, fut: Fut)
where Fut: Future<Output = Option<M::Message>> + Send + 'static, M::Message: Send + 'static,

Spawn a simple async task that produces a message

This is a simplified version of spawn_cancellable for tasks that don’t need cancellation support. The task runs to completion and sends its result.

§Example
program.spawn(async {
    let data = fetch_data().await;
    Some(Msg::DataLoaded(data))
});
Source

pub fn subscribe_interval<F>( &mut self, interval: Duration, callback: F, ) -> Subscription
where F: FnMut() -> M::Message + Send + 'static, M::Message: Send + 'static,

Subscribe to an interval timer with a simple callback

This is a simplified API for the common case of periodic events.

§Example
program.subscribe_interval(Duration::from_secs(1), || Msg::Tick);
Source

pub fn subscribe_with_error<S, T, E, F, G>( &mut self, stream: S, on_item: F, on_error: G, ) -> Subscription
where S: Stream<Item = Result<T, E>> + Send + 'static, F: Fn(T) -> M::Message + Send + 'static, G: Fn(E) -> M::Message + Send + 'static, M::Message: Send + 'static,

Subscribe to a stream with automatic error handling

This helper automatically converts stream items and errors to messages.

§Example
program.subscribe_with_error(
    my_stream,
    |item| Msg::Data(item),
    |error| Msg::Error(error.to_string())
);
Source

pub fn run_with_timeout(self, timeout: Duration) -> Result<()>

Run the program with a timeout (useful for testing)

The program will automatically exit after the specified duration. Returns Ok(()) if the timeout was reached or the program exited normally.

Source

pub fn run_until<F>(self, condition: F) -> Result<()>
where F: FnMut(&M) -> bool + 'static,

Run the program until a condition is met (useful for testing)

The condition function is called after each update with the current model state. The program exits when the condition returns true.

Source

pub fn run(self) -> Result<()>

Run the program until it exits

Trait Implementations§

Source§

impl<M: Model> Drop for Program<M>

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more

Auto Trait Implementations§

§

impl<M> Freeze for Program<M>
where M: Freeze,

§

impl<M> !RefUnwindSafe for Program<M>

§

impl<M> Send for Program<M>
where M: Send,

§

impl<M> !Sync for Program<M>

§

impl<M> Unpin for Program<M>
where M: Unpin,

§

impl<M> !UnwindSafe for Program<M>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Inspectable for T

Source§

fn inspect(self, label: &str) -> Self
where Self: Debug,

Inspect this value with a label
Source§

fn inspect_if(self, condition: bool, label: &str) -> Self
where Self: Debug,

Conditionally inspect this value
Source§

fn inspect_with<F>(self, label: &str, f: F) -> Self
where F: FnOnce(&Self) -> String,

Inspect with a custom formatter
Source§

fn tap<F>(self, f: F) -> Self
where F: FnOnce(&Self),

Tap into the value for side effects
Source§

fn tap_if<F>(self, condition: bool, f: F) -> Self
where F: FnOnce(&Self),

Conditionally tap into the value
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> Message for T
where T: Send + 'static,