rusty_emu/plans/observer_pattern_and_ui_layout.md

8.4 KiB

Observer Pattern and UI Layout Configuration Implementation Plan

Overview

This plan implements two key improvements to the rusty_emu project:

  1. Observer Pattern: Replace inefficient polling with event-driven state updates
  2. UI Layout Configuration: Enable configurable GUI layouts from JSON config files

Current Issues

Performance Issues

  • Console polls system state at 100ms intervals (inefficient)
  • GUI uses try_lock() but still has potential contention
  • No way to configure GUI layout from JSON config

Architecture Limitations

  • Tight coupling between components and UI
  • No standardized way to notify UI of state changes
  • Hardcoded UI layouts

Solution Architecture

Observer Pattern Implementation

graph TD
    A[SystemObserver Trait] --> B[CPU Observer]
    A --> C[RAM Observer]
    A --> D[ROM Observer]
    
    B --> E[ConfigurableSystem]
    C --> E
    D --> E
    
    E --> F[Console UI]
    E --> G[GUI Interface]
    
    F --> H[Event-driven Updates]
    G --> H

UI Layout Configuration

graph LR
    A[SystemConfig JSON] --> B[UI Layout Section]
    B --> C[Component Positions]
    B --> D[Component Sizes]
    B --> E[Display Options]
    
    C --> F[GUI Renderer]
    D --> F
    E --> F

Implementation Details

1. SystemObserver Trait (Fine-grained with Filtering)

#[derive(Debug, Clone)]
pub enum ObserverFilter {
    All,
    CpuOnly,
    MemoryOnly,
    StateChangesOnly,
    RegisterChangesOnly,
}

pub trait SystemObserver: Send + Sync {
    fn get_filter(&self) -> ObserverFilter { return ObserverFilter::All; }
    
    fn on_state_change(&self, component: &str, old_state: ComponentState, new_state: ComponentState);
    fn on_ram_change(&self, chip: &str, bank: usize, address: u8, old_value: u8, new_value: u8);
    fn on_rom_change(&self, chip: &str, address: u16, old_value: u8, new_value: u8);
    fn on_cpu_register_change(&self, cpu: &str, register: &str, old_value: u8, new_value: u8);
    fn on_cpu_pc_change(&self, cpu: &str, old_pc: u16, new_pc: u16);
    fn on_cpu_instruction_executed(&self, cpu: &str, instruction: u8, pc: u16);
}

2. Enhanced SystemConfig

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SystemConfig {
    pub name: String,
    pub description: String,
    pub version: String,
    pub metadata: HashMap<String, serde_json::Value>,
    pub components: HashMap<String, ComponentConfig>,
    pub connections: HashMap<String, ConnectionConfig>,
    pub layout: Option<LayoutConfig>,
    // NEW: UI Layout configuration
    pub ui_layout: Option<UiLayoutConfig>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UiLayoutConfig {
    pub console: Option<ConsoleLayoutConfig>,
    pub gui: Option<GuiLayoutConfig>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GuiLayoutConfig {
    pub components: HashMap<String, ComponentLayoutConfig>,
    pub grid_size: Option<[usize; 2]>,
    pub refresh_rate_ms: Option<u64>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ComponentLayoutConfig {
    pub position: [usize; 2],
    pub size: [usize; 2],
    pub visible: Option<bool>,
    pub display_format: Option<String>,
}

3. Observer Registration in ConfigurableSystem

pub struct ConfigurableSystem {
    config: SystemConfig,
    components: HashMap<String, Arc<Mutex<Box<dyn Component>>>>,
    is_running: Arc<Mutex<bool>>,
    component_handles: Arc<Mutex<Option<ComponentHandles>>>,
    // NEW: Observer registry
    observers: Arc<Mutex<Vec<Box<dyn SystemObserver>>>>,
}

4. Component Integration

Each component will notify observers of state changes:

  • Intel4004 CPU: Register changes, PC changes, instruction execution
  • Intel4001 ROM: Memory reads, address changes
  • Intel4002 RAM: Memory reads/writes, I/O changes

5. UI Updates

Console Updates (Performance Target: 50% CPU reduction, sub-10ms responsiveness)

  • Replace 100ms polling with event-driven updates using observer pattern
  • Observer receives notifications and updates display immediately
  • Implement filtering to reduce unnecessary UI updates
  • Target: Reduce CPU usage by 50% compared to current polling
  • Target: Update responsiveness to under 10ms for state changes

GUI Updates

  • Use layout configuration from JSON for component positioning/sizing
  • Position components according to config (basic implementation)
  • Show/hide components based on config visibility settings
  • Use observer pattern for real-time updates
  • Support configurable refresh rates from UI layout config

Configuration Examples

Enhanced JSON Config

{
  "name": "IntelMcs4",
  "description": "Basic MCS-4 System with CPU, Clock, 2 ROMs, and 1 RAM",
  "version": "1.0",
  "metadata": {
    "author": "RustyEmu",
    "created": "2024-01-01",
    "cpu_speed": 750000,
    "architecture": "mcs4",
    "rom_count": 2,
    "ram_count": 1
  },
  "components": {
    "CPU_4004": {
      "single": {
        "component_type": "intel_4004",
        "name": "CPU_4004",
        "properties": {
          "clock_speed": 750000
        }
      }
    }
    // ... other components
  },
  "connections": {
    // ... existing connections
  },
  "layout": {
    "grid_size": [10, 10],
    "positions": {
      "cpu": [1, 1],
      "clock": [0, 0],
      "rom1": [2, 0],
      "rom2": [3, 0],
      "ram": [2, 2]
    }
  },
  "ui_layout": {
    "console": {
      "refresh_rate_ms": 50,
      "show_ram": true,
      "show_registers": true,
      "show_system_info": true
    },
    "gui": {
      "grid_size": [20, 20],
      "components": {
        "CPU_4004": {
          "position": [1, 1],
          "size": [20, 10],
          "visible": true,
          "display_format": "hex"
        },
        "RAM_4002": {
          "position": [3, 2],
          "size": [25, 15],
          "visible": true,
          "display_format": "hex"
        },
        "ROM_4001_1": {
          "position": [2, 0],
          "size": [20, 8],
          "visible": true,
          "display_format": "hex"
        }
      },
      "refresh_rate_ms": 60
    }
  }
}

Benefits

Performance Improvements

  • Reduced CPU usage: Event-driven vs polling
  • Better responsiveness: Immediate updates vs 100ms delays
  • Less contention: Observer pattern reduces lock contention

User Experience

  • Configurable layouts: Users can customize UI arrangement
  • Persistent settings: Layouts saved in config files
  • Flexible display options: Show/hide components, change formats

Architecture Benefits

  • Loose coupling: Components don't depend on UI
  • Extensibility: Easy to add new observers
  • Maintainability: Clear separation of concerns

Implementation Steps

  1. Add SystemObserver trait to system_config.rs
  2. Extend SystemConfig with UI layout configuration
  3. Add observer registration to ConfigurableSystem
  4. Implement observer notifications in Intel4004 CPU
  5. Implement observer notifications in Intel4001 ROM
  6. Implement observer notifications in Intel4002 RAM
  7. Update console.rs to use observer pattern
  8. Update GUI to use observer pattern and layout configuration
  9. Add UI layout configuration to existing JSON configs
  10. Test the observer pattern and UI layout system
  11. Update documentation with new features

Testing Strategy

Unit Tests

  • Test observer registration and notification
  • Test UI layout configuration parsing
  • Test component state change notifications

Integration Tests

  • Test console with observer pattern
  • Test GUI with layout configuration
  • Test end-to-end state change propagation

Performance Tests

  • Measure CPU usage reduction
  • Test responsiveness improvements
  • Validate lock contention reduction

Backward Compatibility

  • Existing configs without ui_layout section will use defaults (console: 100ms, current GUI layout)
  • Observer pattern is additive - doesn't break existing code, components work without observers
  • ConfigurableSystem will handle missing ui_layout gracefully with sensible defaults
  • Gradual migration path: existing configs continue to work, new configs get enhanced features
  • No breaking changes to existing JSON configs - only additive new section

Future Enhancements

  • Multiple observer types: Different observers for different concerns
  • Layout templates: Predefined layouts for different use cases
  • Dynamic layout editing: Runtime layout modification
  • Observer filtering: Selective notification based on component types