kparse/
provider.rs

1use crate::debug::tracks::debug_tracks;
2use crate::{Code, DynTrackProvider};
3use nom::{AsBytes, InputIter, InputLength, InputTake, Offset, Slice};
4use nom_locate::LocatedSpan;
5use std::cell::RefCell;
6use std::fmt::{Debug, Formatter};
7use std::ops::{RangeFrom, RangeTo};
8
9/// Data packet for the Tracker.
10#[derive(Debug)]
11pub enum TrackData<C, T>
12where
13    C: Code,
14{
15    /// Enter function
16    Enter(C, LocatedSpan<T, ()>),
17    /// Exit function
18    Exit(),
19    /// Ok result
20    Ok(LocatedSpan<T, ()>, LocatedSpan<T, ()>),
21    /// Err result
22    Err(LocatedSpan<T, ()>, C, String),
23    /// Warning
24    Warn(LocatedSpan<T, ()>, &'static str),
25    /// General info
26    Info(LocatedSpan<T, ()>, &'static str),
27    /// Debug info
28    Debug(LocatedSpan<T, ()>, String),
29}
30
31/// Provides the tracking functionality backend.
32pub trait TrackProvider<C, T>
33where
34    C: Code,
35{
36    /// Create a span with this TrackingProvider attached.
37    fn track_span<'s>(&'s self, text: T) -> LocatedSpan<T, DynTrackProvider<'s, C, T>>
38    where
39        T: 's;
40
41    /// Extract the tracking results.
42    /// Removes the result from the context.
43    fn results(&self) -> TrackedDataVec<C, T>;
44
45    /// Collects the tracking data. Use Track.xxx()
46    fn track(&self, data: TrackData<C, T>);
47}
48
49impl<'c, C, T> Debug for DynTrackProvider<'c, C, T>
50where
51    C: Code,
52{
53    fn fmt(&self, _: &mut Formatter<'_>) -> std::fmt::Result {
54        Ok(())
55    }
56}
57
58#[derive(Debug)]
59pub struct TrackedData<C, I>
60where
61    C: Code,
62{
63    pub func: C,
64    pub callstack: Vec<C>,
65    pub track: TrackData<C, I>,
66}
67
68pub struct TrackedDataVec<C, I>(Vec<TrackedData<C, I>>)
69where
70    C: Code;
71
72impl<C, I> Debug for TrackedDataVec<C, I>
73where
74    C: Code,
75    I: AsBytes + Clone + Debug,
76    I: Offset
77        + InputTake
78        + InputIter
79        + InputLength
80        + Slice<RangeFrom<usize>>
81        + Slice<RangeTo<usize>>,
82{
83    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
84        debug_tracks(f, f.width().into(), &self.0)
85    }
86}
87
88#[derive(Debug)]
89pub struct StdTracker<C, T>
90where
91    T: AsBytes + Clone,
92    C: Code,
93{
94    data: RefCell<StdTracks<C, T>>,
95}
96
97#[derive(Debug)]
98struct StdTracks<C, T>
99where
100    T: AsBytes + Clone,
101    C: Code,
102{
103    func: Vec<C>,
104    track: Vec<TrackedData<C, T>>,
105}
106
107impl<C, T> StdTracker<C, T>
108where
109    T: AsBytes + Clone,
110    C: Code,
111{
112    /// Creates a context for a given span.
113    pub fn new() -> Self {
114        Self {
115            data: Default::default(),
116        }
117    }
118
119    // enter function
120    fn push_func(&self, func: C) {
121        self.data.borrow_mut().func.push(func);
122    }
123
124    // leave current function
125    fn pop_func(&self) {
126        self.data.borrow_mut().func.pop();
127    }
128
129    // current function
130    fn func(&self) -> C {
131        *self
132            .data
133            .borrow()
134            .func
135            .last()
136            .expect("Vec<FnCode> is empty. forgot to trace.enter()")
137    }
138
139    fn callstack(&self) -> Vec<C> {
140        self.data.borrow().func.clone()
141    }
142
143    fn append_track(&self, track: TrackData<C, T>) {
144        let callstack = self.callstack();
145        let func = self.func();
146        self.data.borrow_mut().track.push(TrackedData {
147            func,
148            callstack,
149            track,
150        });
151    }
152}
153
154impl<C, T> TrackProvider<C, T> for StdTracker<C, T>
155where
156    T: AsBytes + Clone,
157    C: Code,
158{
159    /// Create a new Span from this context using the original str.
160    fn track_span<'s>(&'s self, text: T) -> LocatedSpan<T, DynTrackProvider<'s, C, T>>
161    where
162        T: 's,
163    {
164        LocatedSpan::new_extra(text, self)
165    }
166
167    /// Extract the tracking results.
168    ///
169    /// Removes the result from the context.
170    fn results(&self) -> TrackedDataVec<C, T> {
171        TrackedDataVec(self.data.replace(StdTracks::default()).track)
172    }
173
174    fn track(&self, data: TrackData<C, T>) {
175        match &data {
176            TrackData::Enter(func, _) => {
177                self.push_func(*func);
178                self.append_track(data);
179            }
180            TrackData::Exit() => {
181                self.append_track(data);
182                self.pop_func();
183            }
184            TrackData::Ok(_, _)
185            | TrackData::Err(_, _, _)
186            | TrackData::Warn(_, _)
187            | TrackData::Info(_, _)
188            | TrackData::Debug(_, _) => {
189                self.append_track(data);
190            }
191        }
192    }
193}
194
195impl<C, T> Default for StdTracker<C, T>
196where
197    T: AsBytes + Clone,
198    C: Code,
199{
200    fn default() -> Self {
201        Self::new()
202    }
203}
204
205impl<C, T> Default for StdTracks<C, T>
206where
207    T: AsBytes + Clone,
208    C: Code,
209{
210    fn default() -> Self {
211        Self {
212            func: Default::default(),
213            track: Default::default(),
214        }
215    }
216}