use crate::debug::tracks::debug_tracks;
use crate::{Code, DynTrackProvider};
use nom::{AsBytes, InputIter, InputLength, InputTake, Offset, Slice};
use nom_locate::LocatedSpan;
use std::cell::RefCell;
use std::fmt::{Debug, Formatter};
use std::ops::{RangeFrom, RangeTo};
#[derive(Debug)]
pub enum TrackData<C, T>
where
C: Code,
{
Enter(C, LocatedSpan<T, ()>),
Exit(),
Ok(LocatedSpan<T, ()>, LocatedSpan<T, ()>),
Err(LocatedSpan<T, ()>, C, String),
Warn(LocatedSpan<T, ()>, &'static str),
Info(LocatedSpan<T, ()>, &'static str),
Debug(LocatedSpan<T, ()>, String),
}
pub trait TrackProvider<C, T>
where
C: Code,
{
fn track_span<'s>(&'s self, text: T) -> LocatedSpan<T, DynTrackProvider<'s, C, T>>
where
T: 's;
fn results(&self) -> TrackedDataVec<C, T>;
fn track(&self, data: TrackData<C, T>);
}
impl<'c, C, T> Debug for DynTrackProvider<'c, C, T>
where
C: Code,
{
fn fmt(&self, _: &mut Formatter<'_>) -> std::fmt::Result {
Ok(())
}
}
#[derive(Debug)]
pub struct TrackedData<C, I>
where
C: Code,
{
pub func: C,
pub callstack: Vec<C>,
pub track: TrackData<C, I>,
}
pub struct TrackedDataVec<C, I>(Vec<TrackedData<C, I>>)
where
C: Code;
impl<C, I> Debug for TrackedDataVec<C, I>
where
C: Code,
I: AsBytes + Clone + Debug,
I: Offset
+ InputTake
+ InputIter
+ InputLength
+ Slice<RangeFrom<usize>>
+ Slice<RangeTo<usize>>,
{
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
debug_tracks(f, f.width().into(), &self.0)
}
}
#[derive(Debug)]
pub struct StdTracker<C, T>
where
T: AsBytes + Clone,
C: Code,
{
data: RefCell<StdTracks<C, T>>,
}
#[derive(Debug)]
struct StdTracks<C, T>
where
T: AsBytes + Clone,
C: Code,
{
func: Vec<C>,
track: Vec<TrackedData<C, T>>,
}
impl<C, T> StdTracker<C, T>
where
T: AsBytes + Clone,
C: Code,
{
pub fn new() -> Self {
Self {
data: Default::default(),
}
}
fn push_func(&self, func: C) {
self.data.borrow_mut().func.push(func);
}
fn pop_func(&self) {
self.data.borrow_mut().func.pop();
}
fn func(&self) -> C {
*self
.data
.borrow()
.func
.last()
.expect("Vec<FnCode> is empty. forgot to trace.enter()")
}
fn callstack(&self) -> Vec<C> {
self.data.borrow().func.clone()
}
fn append_track(&self, track: TrackData<C, T>) {
let callstack = self.callstack();
let func = self.func();
self.data.borrow_mut().track.push(TrackedData {
func,
callstack,
track,
});
}
}
impl<C, T> TrackProvider<C, T> for StdTracker<C, T>
where
T: AsBytes + Clone,
C: Code,
{
fn track_span<'s>(&'s self, text: T) -> LocatedSpan<T, DynTrackProvider<'s, C, T>>
where
T: 's,
{
LocatedSpan::new_extra(text, self)
}
fn results(&self) -> TrackedDataVec<C, T> {
TrackedDataVec(self.data.replace(StdTracks::default()).track)
}
fn track(&self, data: TrackData<C, T>) {
match &data {
TrackData::Enter(func, _) => {
self.push_func(*func);
self.append_track(data);
}
TrackData::Exit() => {
self.append_track(data);
self.pop_func();
}
TrackData::Ok(_, _)
| TrackData::Err(_, _, _)
| TrackData::Warn(_, _)
| TrackData::Info(_, _)
| TrackData::Debug(_, _) => {
self.append_track(data);
}
}
}
}
impl<C, T> Default for StdTracker<C, T>
where
T: AsBytes + Clone,
C: Code,
{
fn default() -> Self {
Self::new()
}
}
impl<C, T> Default for StdTracks<C, T>
where
T: AsBytes + Clone,
C: Code,
{
fn default() -> Self {
Self {
func: Default::default(),
track: Default::default(),
}
}
}