use std::cell::RefCell;
#[derive(Debug)]
pub(crate) struct ErrorStore<T> {
data: RefCell<ErrorStoreData<T>>,
}
impl<T> ErrorStore<T> {
pub(crate) fn new() -> Self {
Self { data: RefCell::new(ErrorStoreData::default()) }
}
pub(crate) fn into_inner(self) -> Vec<T> {
std::mem::take(&mut self.data.borrow_mut().errors)
}
pub(crate) fn sink(&mut self) -> ErrorSink<'_, T> {
let new_id = self.data.borrow_mut().register_sink(None);
ErrorSink { data: &self.data, id: new_id }
}
}
#[derive(Debug)]
pub(crate) struct ErrorSink<'a, T> {
data: &'a RefCell<ErrorStoreData<T>>,
id: usize,
}
impl<'a, T> ErrorSink<'a, T> {
pub(crate) fn push(&self, error: T) {
self.data.borrow_mut().push(self.id, error);
}
pub(crate) fn has_errors(&self) -> bool {
self.data.borrow().sinks[self.id].has_errors
}
pub(crate) fn new(&self) -> ErrorSink<'a, T> {
let mut errors = self.data.borrow_mut();
let new_id = errors.register_sink(Some(self.id));
Self { data: self.data, id: new_id }
}
}
#[derive(Debug)]
struct ErrorStoreData<T> {
errors: Vec<T>,
sinks: Vec<ErrorSinkData>,
}
impl<T> Default for ErrorStoreData<T> {
fn default() -> Self {
Self { errors: Vec::new(), sinks: Vec::new() }
}
}
impl<T> ErrorStoreData<T> {
fn push(&mut self, id: usize, error: T) {
self.errors.push(error);
self.sinks[id].has_errors = true;
let mut curr = id;
while let Some(parent) = self.sinks[curr].parent {
self.sinks[parent].has_errors = true;
curr = parent;
}
}
fn register_sink(&mut self, parent: Option<usize>) -> usize {
let id = self.sinks.len();
self.sinks.push(ErrorSinkData::new(parent));
id
}
}
#[derive(Debug)]
struct ErrorSinkData {
parent: Option<usize>,
has_errors: bool,
}
impl ErrorSinkData {
fn new(parent: Option<usize>) -> Self {
Self { parent, has_errors: false }
}
}