Skip to main content

DifferentialRenderer

Struct DifferentialRenderer 

Source
pub struct DifferentialRenderer { /* private fields */ }
Expand description

The main differential rendering manager.

This is the central component that orchestrates the differential rendering system. It tracks component states, manages dirty regions, and provides the API for determining what needs to be re-rendered.

§Architecture

┌────────────────────┐
│  DifferentialRenderer  │
├──────────┬─────────┤
│ Components│DirtyRegions│
│ HashMap   │    Vec     │
│           │            │
│ - States  │ - Areas    │
│ - Deps    │ - Priority │
│ - Versions│ - Metadata │
└──────────┴──────────┘

§Memory Complexity

  • Components: O(n) where n is the number of registered components
  • Dirty Regions: O(k) where k is bounded by max_dirty_regions
  • Total: O(n + k) with configurable upper bounds

§Performance Guarantees

  • Component lookup: O(1) average, O(n) worst case (HashMap)
  • Region intersection: O(k) where k is current dirty regions
  • Memory bounded: Hard limits prevent unbounded growth
  • Cleanup: Automatic eviction of stale data

§Thread Safety

Not thread-safe. Designed for single-threaded UI event loops. Use external synchronization if multi-threaded access is needed.

§Invariants

The following invariants are maintained and checked in debug builds:

  • All dirty regions have positive area
  • Component dependency graph is acyclic (DAG)
  • Version numbers are monotonic within each component
  • Memory usage stays within configured limits

Implementations§

Source§

impl DifferentialRenderer

Source

pub fn new() -> Self

Create a new differential renderer

Source

pub fn with_config(config: DifferentialConfig) -> Self

Create a new differential renderer with custom config

Source

pub fn register_component(&mut self, id: String, area: Rect)

Register a component

Source

pub fn unregister_component(&mut self, id: &str)

Unregister a component

Source

pub fn update_component_area(&mut self, id: &str, area: Rect)

Update component area

Source

pub fn mark_component_dirty(&mut self, id: &str)

Mark a component as dirty

Source

pub fn mark_region_dirty(&mut self, rect: Rect, component_id: Option<String>)

Mark a region as dirty for re-rendering.

This is the core API for indicating that a rectangular area needs to be updated. The system will automatically handle region merging and memory management.

§Parameters
  • rect: The rectangular area that needs updating
  • component_id: Optional ID of the component that owns this region
§Behavior
  1. Size Filtering: Skips regions smaller than min_region_area
  2. Region Merging: Attempts to merge with existing regions if enabled
  3. Memory Management: Enforces max_dirty_regions limit via LRU eviction
  4. Validation: Ensures region has positive area and valid coordinates
§Performance
  • Best case: O(1) if no merging occurs
  • Average case: O(k) where k is existing dirty regions
  • Worst case: O(k*log(k)) when sorting for eviction
§Examples
use hojicha_rendering::differential::DifferentialRenderer;
use ratatui::layout::Rect;

let mut renderer = DifferentialRenderer::new();

// Mark a region for a specific component
renderer.mark_region_dirty(
    Rect::new(10, 10, 20, 20),
    Some("my_component".to_string())
);

// Mark a generic region
renderer.mark_region_dirty(Rect::new(0, 0, 100, 100), None);
Source

pub fn needs_render(&self, rect: Rect) -> bool

Check if a rectangular region needs rendering.

This is the primary API for determining whether a given area needs to be re-rendered based on dirty region tracking.

§Algorithm
  1. Return true if differential rendering is disabled
  2. Return true if full refresh interval has elapsed
  3. Return true if region intersects any dirty regions
  4. Return false otherwise (region is clean)
§Performance
  • Time Complexity: O(k) where k is the number of dirty regions
  • Space Complexity: O(1)
  • Early termination: Stops on first intersection found
§Parameters
  • rect: The rectangular area to check
§Returns

true if the region should be re-rendered, false if it can be skipped.

§Examples
use hojicha_rendering::differential::DifferentialRenderer;
use ratatui::layout::Rect;

let mut renderer = DifferentialRenderer::new();
let check_area = Rect::new(0, 0, 50, 50);

// Initially clean
assert!(!renderer.needs_render(check_area));

// Mark overlapping area dirty
renderer.mark_region_dirty(Rect::new(25, 25, 50, 50), None);
assert!(renderer.needs_render(check_area));  // Now needs render
Source

pub fn component_needs_render(&self, id: &str) -> bool

Check if a component needs rendering

Source

pub fn mark_component_rendered(&mut self, id: &str, checksum: Option<Checksum>)

Mark a component as rendered

Source

pub fn clear_dirty_regions(&mut self, rect: Rect)

Clear dirty regions for a specific area

Source

pub fn force_full_refresh(&mut self)

Force a full refresh

Source

pub fn get_dirty_regions(&self) -> &[DirtyRegion]

Get the list of dirty regions

Source

pub fn get_stats(&self) -> &RenderStats

Get rendering statistics

Source

pub fn reset_stats(&mut self)

Reset statistics

Source

pub fn cleanup(&mut self)

Cleanup old dirty regions

Source

pub fn record_render(&mut self, differential: bool, skipped: bool)

Record a render operation

Source

pub fn set_enabled(&mut self, enabled: bool)

Enable or disable differential rendering

Source

pub fn is_enabled(&self) -> bool

Check if differential rendering is enabled

Source

pub fn config(&self) -> &DifferentialConfig

Get the current configuration

Source

pub fn update_config(&mut self, config: DifferentialConfig)

Update configuration

Source

pub fn dirty_region_count(&self) -> usize

Get the number of dirty regions (for testing/debugging)

Source

pub fn has_component(&self, id: &str) -> bool

Check if a component exists (for testing)

Source

pub fn add_component_dependency( &mut self, component_id: &str, dependency_id: &str, )

Add a dependency between components (for testing)

Trait Implementations§

Source§

impl Default for DifferentialRenderer

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

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, 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> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
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.