use crate::process::{Process, ProcessId, ProcessKind, ProcessState}; use std::collections::HashMap; #[derive(Debug, Default)] pub struct ProcessManager { next_id: u32, processes: HashMap, } impl ProcessManager { pub fn new() -> Self { Self { next_id: 1, processes: HashMap::new() } } pub fn spawn_vm_game(&mut self, app_id: u32, title: impl Into) -> ProcessId { self.spawn(app_id, title, ProcessKind::VmGame) } pub fn spawn_vm_shell(&mut self, app_id: u32, title: impl Into) -> ProcessId { self.spawn(app_id, title, ProcessKind::VmShell) } pub fn spawn_native_shell(&mut self, app_id: u32, title: impl Into) -> ProcessId { self.spawn(app_id, title, ProcessKind::NativeShell) } fn spawn(&mut self, app_id: u32, title: impl Into, kind: ProcessKind) -> ProcessId { let id = ProcessId(self.next_id); self.next_id += 1; let mut process = Process::new(id, app_id, title, kind); process.mark_running(); self.processes.insert(id, process); id } pub fn get(&self, id: ProcessId) -> Option<&Process> { self.processes.get(&id) } pub fn get_mut(&mut self, id: ProcessId) -> Option<&mut Process> { self.processes.get_mut(&id) } pub fn contains(&self, id: ProcessId) -> bool { self.processes.contains_key(&id) } pub fn all(&self) -> impl Iterator { self.processes.values() } pub fn mark_running(&mut self, id: ProcessId) -> bool { self.transition(id, ProcessState::Running) } pub fn mark_suspended(&mut self, id: ProcessId) -> bool { self.transition(id, ProcessState::Suspended) } pub fn mark_stopped(&mut self, id: ProcessId) -> bool { self.transition(id, ProcessState::Stopped) } pub fn mark_crashed(&mut self, id: ProcessId) -> bool { self.transition(id, ProcessState::Crashed) } pub fn remove_stopped(&mut self) { self.processes.retain(|_, process| process.state != ProcessState::Stopped); } fn transition(&mut self, id: ProcessId, state: ProcessState) -> bool { let Some(process) = self.get_mut(id) else { return false; }; process.state = state; true } } #[cfg(test)] mod tests { use super::*; #[test] fn spawn_vm_game_creates_running_process() { let mut manager = ProcessManager::new(); let id = manager.spawn_vm_game(42, "Amazing Game"); let process = manager.get(id).expect("process should exist"); assert_eq!(process.id, id); assert_eq!(process.app_id, 42); assert_eq!(process.title, "Amazing Game"); assert_eq!(process.kind, ProcessKind::VmGame); assert_eq!(process.state, ProcessState::Running); } #[test] fn spawn_vm_shell_creates_running_process() { let mut manager = ProcessManager::new(); let id = manager.spawn_vm_shell(42, "Amazing Shell"); let process = manager.get(id).expect("process should exist"); assert_eq!(process.id, id); assert_eq!(process.app_id, 42); assert_eq!(process.title, "Amazing Shell"); assert_eq!(process.kind, ProcessKind::VmShell); assert_eq!(process.state, ProcessState::Running); } #[test] fn spawn_native_shell_creates_running_process() { let mut manager = ProcessManager::new(); let id = manager.spawn_native_shell(42, "Amazing Shell"); let process = manager.get(id).expect("process should exist"); assert_eq!(process.id, id); assert_eq!(process.app_id, 42); assert_eq!(process.title, "Amazing Shell"); assert_eq!(process.kind, ProcessKind::NativeShell); assert_eq!(process.state, ProcessState::Running); } #[test] fn mark_suspended_updates_process_state() { let mut manager = ProcessManager::new(); let id = manager.spawn_vm_game(42, "Amazing Game"); assert!(manager.mark_suspended(id)); let process = manager.get(id).expect("process should exist"); assert_eq!(process.state, ProcessState::Suspended); } #[test] fn mark_stopped_updates_process_state() { let mut manager = ProcessManager::new(); let id = manager.spawn_vm_game(42, "Amazing Game"); assert!(manager.mark_stopped(id)); let process = manager.get(id).expect("process should exist"); assert_eq!(process.state, ProcessState::Stopped); } #[test] fn unknown_process_transition_returns_false() { let mut manager = ProcessManager::new(); assert!(!manager.mark_stopped(ProcessId(999))); } #[test] fn remove_stopped_keeps_running_processes() { let mut manager = ProcessManager::new(); let running = manager.spawn_vm_game(1, "Running"); let stopped = manager.spawn_vm_game(2, "Stopped"); manager.mark_stopped(stopped); manager.remove_stopped(); assert!(manager.get(running).is_some()); assert!(manager.get(stopped).is_none()); } }