use std::{collections::VecDeque, mem}; use anyhow::{Context, Result}; use hashbrown::HashMap; use mlua::Function; #[derive(Debug, Default)] pub struct Runtime { frames: VecDeque, blocks: HashMap>, pub blocking: bool, } #[derive(Debug)] pub struct RuntimeFrame { id: String, } impl Runtime { pub fn new_isolate(id: &str) -> Self { Self { frames: VecDeque::from([RuntimeFrame { id: id.to_owned() }]), ..Default::default() } } pub fn push(&mut self, id: &str) { self.frames.push_back(RuntimeFrame { id: id.to_owned() }); } pub fn pop(&mut self) -> Result { self.frames.pop_back().context("Runtime stack underflow") } pub fn critical_push(&mut self, id: &str, blocking: bool) -> bool { self.push(id); mem::replace(&mut self.blocking, blocking) } pub fn critical_pop(&mut self, blocking: bool) -> Result { self.blocking = blocking; self.pop() } pub fn current(&self) -> Result<&str> { self.frames.back().map(|f| f.id.as_str()).context("No current runtime frame") } pub fn current_module(&self) -> Result<&str> { let s = self.current()?; Ok(s.split('.').next().unwrap_or(s)) } pub fn current_owned(&self) -> Result { self.current().map(ToOwned::to_owned) } pub fn get_block(&self, id: &str, calls: usize) -> Option { self.blocks.get(id).and_then(|v| v.get(calls)).cloned() } pub fn put_block(&mut self, f: &Function) -> Option { let cur = self.frames.back().filter(|f| f.id != "init")?; let blocks = self.blocks.entry_ref(&cur.id).or_default(); blocks.push(f.clone()); Some(blocks.len() - 1) } }