181 lines
5.1 KiB
Rust
181 lines
5.1 KiB
Rust
use crate::process::{Process, ProcessId, ProcessKind, ProcessState};
|
|
use std::collections::HashMap;
|
|
|
|
#[derive(Debug, Default)]
|
|
pub struct ProcessManager {
|
|
next_id: u32,
|
|
processes: HashMap<ProcessId, Process>,
|
|
}
|
|
|
|
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<String>) -> ProcessId {
|
|
self.spawn(app_id, title, ProcessKind::VmGame)
|
|
}
|
|
|
|
pub fn spawn_vm_shell(&mut self, app_id: u32, title: impl Into<String>) -> ProcessId {
|
|
self.spawn(app_id, title, ProcessKind::VmShell)
|
|
}
|
|
|
|
pub fn spawn_native_shell(&mut self, app_id: u32, title: impl Into<String>) -> ProcessId {
|
|
self.spawn(app_id, title, ProcessKind::NativeShell)
|
|
}
|
|
|
|
fn spawn(&mut self, app_id: u32, title: impl Into<String>, 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<Item = &Process> {
|
|
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());
|
|
}
|
|
}
|