use std::cell::{Ref, RefCell, RefMut};
use crate::record::LogRecord;
thread_local! {
pub static SCOPE_STACK: ScopeStack = const { ScopeStack::new() };
}
#[derive(Debug, Clone)]
pub struct ScopeFrame {
local: Vec<LogRecord>,
}
#[derive(Debug)]
pub struct ScopeStack {
inner: RefCell<Vec<ScopeFrame>>,
}
impl ScopeFrame {
pub const fn new() -> Self {
Self { local: Vec::new() }
}
pub fn push(&mut self, record: impl Into<LogRecord>) {
self.local.push(record.into());
}
pub fn records(&self) -> impl ExactSizeIterator<Item = &LogRecord> + Clone {
self.local.iter()
}
}
#[cfg(test)]
impl ScopeFrame {
pub fn find(&self, key: &str) -> Option<&crate::LogValue> {
self.local
.iter()
.find(|r| r.key() == key)
.map(crate::record::LogRecord::value)
}
pub fn is_empty(&self) -> bool {
self.local.is_empty()
}
}
impl ScopeStack {
pub const fn new() -> Self {
Self {
inner: RefCell::new(Vec::new()),
}
}
pub fn push(&self, frame: ScopeFrame) {
self.inner.borrow_mut().push(frame);
}
pub fn pop(&self) -> Option<ScopeFrame> {
self.inner.borrow_mut().pop()
}
pub fn top(&self) -> Option<Ref<'_, ScopeFrame>> {
let inner = self.inner.borrow();
if inner.is_empty() {
None
} else {
Some(Ref::map(inner, |inner| inner.last().unwrap()))
}
}
pub fn top_mut(&self) -> Option<RefMut<'_, ScopeFrame>> {
let inner = self.inner.borrow_mut();
if inner.is_empty() {
None
} else {
Some(RefMut::map(inner, |inner| inner.last_mut().unwrap()))
}
}
}
impl Default for ScopeStack {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
impl ScopeStack {
pub fn len(&self) -> usize {
self.inner.borrow().len()
}
pub fn is_empty(&self) -> bool {
self.inner.borrow().is_empty()
}
}