use std::{collections::HashMap, sync::{LazyLock, RwLock, RwLockReadGuard, RwLockWriteGuard}}; use crate::prelude::*; pub static JOB_TABLE: LazyLock> = LazyLock::new(|| RwLock::new(JobTab::new())); pub static VAR_TABLE: LazyLock> = LazyLock::new(|| RwLock::new(VarTab::new())); pub struct JobTab { } impl JobTab { pub fn new() -> Self { Self {} } } pub struct VarTab { vars: HashMap, params: HashMap, } impl VarTab { pub fn new() -> Self { let vars = HashMap::new(); let params = Self::init_params(); Self { vars, params } } fn init_params() -> HashMap { let mut params = HashMap::new(); params.insert('?', "0".into()); // Last command exit status params.insert('#', "0".into()); // Number of positional parameters params.insert('0', std::env::current_exe().unwrap().to_str().unwrap().to_string()); // Name of the shell params.insert('$', Pid::this().to_string()); // PID of the shell params.insert('!', "".into()); // PID of the last background job (if any) params } pub fn vars(&self) -> &HashMap { &self.vars } pub fn vars_mut(&mut self) -> &mut HashMap { &mut self.vars } pub fn params(&self) -> &HashMap { &self.params } pub fn params_mut(&mut self) -> &mut HashMap { &mut self.params } pub fn get_var(&self, var: &str) -> String { if let Some(var) = self.vars.get(var).map(|s| s.to_string()) { var } else { std::env::var(var).unwrap_or_default() } } pub fn new_var(&mut self, var: &str, val: &str) { self.vars.insert(var.to_string(), val.to_string()); } pub fn set_param(&mut self, param: char, val: &str) { self.params.insert(param,val.to_string()); } pub fn get_param(&self, param: char) -> String { self.params.get(¶m).map(|s| s.to_string()).unwrap_or("0".to_string()) } } /// Read from the job table pub fn read_jobs) -> T>(f: F) -> T { let lock = JOB_TABLE.read().unwrap(); f(lock) } /// Write to the job table pub fn write_jobs) -> T>(f: F) -> T { let lock = &mut JOB_TABLE.write().unwrap(); f(lock) } /// Read from the variable table pub fn read_vars) -> T>(f: F) -> T { let lock = VAR_TABLE.read().unwrap(); f(lock) } /// Write to the variable table pub fn write_vars) -> T>(f: F) -> T { let lock = &mut VAR_TABLE.write().unwrap(); f(lock) } pub fn get_status() -> i32 { read_vars(|v| v.get_param('?')).parse::().unwrap() } pub fn set_status(code: i32) { write_vars(|v| v.set_param('?', &code.to_string())) }