Trait Model

Source
pub trait Model:
    Send
    + Sized
    + 'static {
    // Required methods
    fn init() -> (Self, Option<Cmd>);
    fn update(&mut self, msg: Msg) -> Option<Cmd>;
    fn view(&self) -> String;
}
Expand description

The Model trait defines the core interface for bubbletea-rs applications.

This trait provides a direct 1-to-1 mapping from Go’s Model interface with identical method signatures and behavior. Models represent your application’s state and logic, following the Model-View-Update pattern.

§Trait Bounds

  • Send: Ensures the model can be safely transferred between threads
  • Sized: Ensures the model has a known size at compile time
  • 'static: Ensures the model doesn’t contain non-static references

These bounds are required for async safety and Tokio integration.

§Example

use bubbletea_rs::{Model, Msg, Cmd, KeyMsg};

struct Counter {
    value: i32,
}

impl Model for Counter {
    fn init() -> (Self, Option<Cmd>) {
        (Self { value: 0 }, None)
    }
     
    fn update(&mut self, msg: Msg) -> Option<Cmd> {
        if let Some(key_msg) = msg.downcast_ref::<KeyMsg>() {
            match key_msg.key {
                crossterm::event::KeyCode::Up => self.value += 1,
                crossterm::event::KeyCode::Down => self.value -= 1,
                _ => {}
            }
        }
        None
    }
     
    fn view(&self) -> String {
        format!("Counter: {} (↑/↓ to change)", self.value)
    }
}

Required Methods§

Source

fn init() -> (Self, Option<Cmd>)

Initialize the model with its initial state and optional startup command.

This method is called once when the application starts and should return the initial state of your model along with an optional command to execute immediately after initialization.

§Returns

A tuple containing:

  • Self: The initialized model with its starting state
  • Option<Cmd>: An optional command to run immediately (e.g., loading data)
§Example
fn init() -> (Self, Option<Cmd>) {
    // Start with a count of 0 and no initial command
    (MyModel { count: 0 }, None)
}
Source

fn update(&mut self, msg: Msg) -> Option<Cmd>

Update the model in response to a received message.

This method is called whenever a message is received by your application. It should update the model’s state based on the message content and optionally return a command to execute as a side effect.

§Arguments
  • msg - The message to process. Use msg.downcast_ref::<T>() to check for specific message types.
§Returns

An optional command to execute after the update. Return None if no side effects are needed.

§Example
fn update(&mut self, msg: Msg) -> Option<Cmd> {
    if let Some(key_msg) = msg.downcast_ref::<KeyMsg>() {
        match key_msg.key {
            crossterm::event::KeyCode::Up => {
                self.count += 1;
                // No command needed for this update
                None
            }
            _ => None,
        }
    } else {
        None
    }
}
Source

fn view(&self) -> String

Render the current model state as a string for terminal display.

This method is called whenever the terminal needs to be redrawn. It should return a string representation of the current model state that will be displayed to the user.

§Returns

A String containing the rendered view. This can include:

  • ANSI escape codes for colors and styling
  • Newlines for multi-line layouts
  • Unicode characters for advanced formatting
§Performance Notes

This method may be called frequently during redraws, so avoid expensive computations. Consider caching formatted strings if the rendering is complex.

§Example
fn view(&self) -> String {
    format!(
        "Welcome to {}!\n\nCount: {}\n\nPress ↑/↓ to change",
        self.name,
        self.count
    )
}

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.

Implementors§