module_util/evaluator/trace.rs
1//! Evaluation module trace.
2
3use core::iter::FusedIterator;
4use core::slice;
5
6use alloc::vec::Vec;
7
8///////////////////////////////////////////////////////////////////////////////
9
10/// A stack-like structure to hold the module backtrace during evaluation.
11///
12/// A module trace is to the evaluator what [`Backtrace`] is to a program. In
13/// the trace, modules are stored in import-order. This means that the module
14/// where the error was caused is always the last one in the trace.
15///
16/// [`Backtrace`]: std::backtrace::Backtrace
17#[derive(Debug, Clone)]
18pub struct Trace<T>(Vec<T>);
19
20impl<T> Default for Trace<T> {
21 fn default() -> Self {
22 Self::empty()
23 }
24}
25
26impl<T> From<Vec<T>> for Trace<T> {
27 fn from(x: Vec<T>) -> Self {
28 Self(x)
29 }
30}
31
32impl<T> From<Trace<T>> for Vec<T> {
33 fn from(x: Trace<T>) -> Self {
34 x.0
35 }
36}
37
38impl<T> Trace<T> {
39 /// Create a new empty [`Trace`].
40 #[must_use]
41 pub const fn empty() -> Self {
42 Self(Vec::new())
43 }
44
45 /// Get the number of modules in the trace.
46 #[must_use]
47 pub fn len(&self) -> usize {
48 self.0.len()
49 }
50
51 /// Check whether the trace is empty.
52 #[must_use]
53 pub fn is_empty(&self) -> bool {
54 self.0.is_empty()
55 }
56
57 /// Get a reference to the current module.
58 ///
59 /// The current module is always the one that was [`push`]ed last. Returns
60 /// [`None`] if the trace is empty.
61 ///
62 /// [`push`]: Trace::push
63 #[must_use]
64 pub fn current(&self) -> Option<&T> {
65 self.0.last()
66 }
67
68 /// Add a module to the trace.
69 ///
70 /// Pushing a module makes that module the "deepest" level of the trace.
71 /// See: [`Trace`].
72 ///
73 /// # Example
74 ///
75 /// ```rust
76 /// # use module_util::evaluator::trace::Trace;
77 /// let mut trace = Trace::empty();
78 /// trace.push("module 1");
79 /// trace.push("module 2");
80 /// trace.push("module 3");
81 ///
82 /// assert_eq!(
83 /// trace.iter().copied().collect::<Vec<_>>(),
84 /// &[
85 /// "module 1",
86 /// "module 2",
87 /// "module 3"
88 /// ]
89 /// );
90 /// ```
91 pub fn push(&mut self, id: T) {
92 self.0.push(id);
93 }
94
95 /// Remove the last module from the trace and return it.
96 ///
97 /// Also see: [`push`].
98 ///
99 /// # Example
100 /// ```rust
101 /// # use module_util::evaluator::trace::Trace;
102 /// let mut trace = Trace::empty();
103 /// trace.push("module 1");
104 /// trace.push("module 2");
105 /// trace.push("module 3");
106 ///
107 /// assert_eq!(trace.pop(), Some("module 3"));
108 /// assert_eq!(trace.pop(), Some("module 2"));
109 /// assert_eq!(trace.pop(), Some("module 1"));
110 /// assert_eq!(trace.pop(), None);
111 /// ```
112 ///
113 /// [`push`]: Trace::push
114 pub fn pop(&mut self) -> Option<T> {
115 self.0.pop()
116 }
117
118 /// Get an iterator over all modules in the trace.
119 ///
120 /// The returned iterator traverses the trace from the deepest module to the
121 /// shallowest. The returned iterator implements [`DoubleEndedIterator`] so
122 /// you can use [`Iterator::rev`].
123 ///
124 /// # Example
125 ///
126 /// ```rust
127 /// # use module_util::evaluator::trace::Trace;
128 /// let mut trace = Trace::empty();
129 /// trace.push("module 1");
130 /// trace.push("module 2");
131 /// trace.push("module 3");
132 ///
133 /// let mut iter = trace.iter();
134 /// assert_eq!(iter.next().copied(), Some("module 1"));
135 /// assert_eq!(iter.next().copied(), Some("module 2"));
136 /// assert_eq!(iter.next().copied(), Some("module 3"));
137 /// assert_eq!(iter.next().copied(), None);
138 /// ```
139 #[must_use]
140 pub fn iter(&self) -> Iter<'_, T> {
141 Iter(self.0.iter())
142 }
143}
144
145impl<'a, T> IntoIterator for &'a Trace<T> {
146 type Item = &'a T;
147 type IntoIter = Iter<'a, T>;
148
149 fn into_iter(self) -> Self::IntoIter {
150 self.iter()
151 }
152}
153
154///////////////////////////////////////////////////////////////////////////////
155
156/// Borrowing iterator over [`Trace`].
157///
158/// See: [`Trace::iter`].
159#[derive(Debug, Clone)]
160pub struct Iter<'a, T>(slice::Iter<'a, T>);
161
162impl<'a, T> Iterator for Iter<'a, T> {
163 type Item = &'a T;
164
165 fn next(&mut self) -> Option<Self::Item> {
166 self.0.next()
167 }
168
169 fn size_hint(&self) -> (usize, Option<usize>) {
170 self.0.size_hint()
171 }
172}
173
174impl<T> DoubleEndedIterator for Iter<'_, T> {
175 fn next_back(&mut self) -> Option<Self::Item> {
176 self.0.next_back()
177 }
178}
179
180impl<T> ExactSizeIterator for Iter<'_, T> {
181 fn len(&self) -> usize {
182 self.0.len()
183 }
184}
185
186impl<T> FusedIterator for Iter<'_, T> {}