1use serde_json::Value;
2use std::sync::Arc;
3
4pub enum ContextFrame {
12 Indexed { data: Value, index: usize },
14 Keyed {
16 data: Value,
17 index: usize,
18 key: String,
19 },
20 Reduce { current: Value, accumulator: Value },
22 Data(Value),
24}
25
26impl ContextFrame {
27 #[inline]
29 pub fn data(&self) -> &Value {
30 match self {
31 Self::Indexed { data, .. } | Self::Keyed { data, .. } | Self::Data(data) => data,
32 Self::Reduce { current, .. } => current,
33 }
34 }
35
36 #[inline]
38 pub fn get_index(&self) -> Option<usize> {
39 match self {
40 Self::Indexed { index, .. } | Self::Keyed { index, .. } => Some(*index),
41 _ => None,
42 }
43 }
44
45 #[inline]
47 pub fn get_key(&self) -> Option<&str> {
48 match self {
49 Self::Keyed { key, .. } => Some(key.as_str()),
50 _ => None,
51 }
52 }
53
54 #[inline]
56 pub fn get_reduce_current(&self) -> Option<&Value> {
57 match self {
58 Self::Reduce { current, .. } => Some(current),
59 _ => None,
60 }
61 }
62
63 #[inline]
65 pub fn get_reduce_accumulator(&self) -> Option<&Value> {
66 match self {
67 Self::Reduce { accumulator, .. } => Some(accumulator),
68 _ => None,
69 }
70 }
71}
72
73pub enum ContextFrameRef<'a> {
75 Frame(&'a ContextFrame),
77 Root(&'a Arc<Value>),
79}
80
81impl<'a> ContextFrameRef<'a> {
82 pub fn data(&self) -> &Value {
84 match self {
85 ContextFrameRef::Frame(frame) => frame.data(),
86 ContextFrameRef::Root(root) => root,
87 }
88 }
89
90 #[inline]
92 pub fn get_index(&self) -> Option<usize> {
93 match self {
94 ContextFrameRef::Frame(frame) => frame.get_index(),
95 ContextFrameRef::Root(_) => None,
96 }
97 }
98
99 #[inline]
101 pub fn get_key(&self) -> Option<&str> {
102 match self {
103 ContextFrameRef::Frame(frame) => frame.get_key(),
104 ContextFrameRef::Root(_) => None,
105 }
106 }
107
108 #[inline]
110 pub fn get_reduce_current(&self) -> Option<&Value> {
111 match self {
112 ContextFrameRef::Frame(frame) => frame.get_reduce_current(),
113 ContextFrameRef::Root(_) => None,
114 }
115 }
116
117 #[inline]
119 pub fn get_reduce_accumulator(&self) -> Option<&Value> {
120 match self {
121 ContextFrameRef::Frame(frame) => frame.get_reduce_accumulator(),
122 ContextFrameRef::Root(_) => None,
123 }
124 }
125
126 #[inline]
129 pub fn metadata(&self) -> Option<&std::collections::HashMap<String, Value>> {
130 None
131 }
132}
133
134pub struct ContextStack {
136 root: Arc<Value>,
138 frames: Vec<ContextFrame>,
140}
141
142impl ContextStack {
143 pub fn new(root: Arc<Value>) -> Self {
145 Self {
146 root,
147 frames: Vec::new(),
148 }
149 }
150
151 pub fn push(&mut self, data: Value) {
153 self.frames.push(ContextFrame::Data(data));
154 }
155
156 #[inline]
158 pub fn push_with_index(&mut self, data: Value, index: usize) {
159 self.frames.push(ContextFrame::Indexed { data, index });
160 }
161
162 #[inline]
164 pub fn push_with_key_index(&mut self, data: Value, index: usize, key: String) {
165 self.frames.push(ContextFrame::Keyed { data, index, key });
166 }
167
168 #[inline]
170 pub fn replace_top_key_data(&mut self, data: Value, index: usize, key: String) {
171 if let Some(frame) = self.frames.last_mut() {
172 *frame = ContextFrame::Keyed { data, index, key };
173 }
174 }
175
176 #[inline]
178 pub fn take_top_data(&mut self) -> Value {
179 if let Some(frame) = self.frames.last_mut() {
180 match frame {
181 ContextFrame::Indexed { data, .. }
182 | ContextFrame::Keyed { data, .. }
183 | ContextFrame::Data(data) => std::mem::replace(data, Value::Null),
184 ContextFrame::Reduce { current, .. } => std::mem::replace(current, Value::Null),
185 }
186 } else {
187 Value::Null
188 }
189 }
190
191 #[inline]
193 pub fn replace_top_data(&mut self, data: Value, index: usize) {
194 if let Some(frame) = self.frames.last_mut() {
195 *frame = ContextFrame::Indexed { data, index };
196 }
197 }
198
199 #[inline]
201 pub fn push_reduce(&mut self, current: Value, accumulator: Value) {
202 self.frames.push(ContextFrame::Reduce {
203 current,
204 accumulator,
205 });
206 }
207
208 #[inline]
210 pub fn replace_reduce_data(&mut self, current: Value, accumulator: Value) {
211 if let Some(frame) = self.frames.last_mut() {
212 *frame = ContextFrame::Reduce {
213 current,
214 accumulator,
215 };
216 }
217 }
218
219 pub fn pop(&mut self) -> Option<ContextFrame> {
221 self.frames.pop()
222 }
223
224 pub fn get_at_level(&self, level: isize) -> Option<ContextFrameRef<'_>> {
232 let levels_up = level.unsigned_abs();
233
234 if levels_up == 0 {
235 return Some(self.current());
236 }
237
238 let frame_count = self.frames.len();
239
240 if levels_up >= frame_count {
241 return Some(ContextFrameRef::Root(&self.root));
242 }
243
244 let target_index = frame_count - levels_up;
245 self.frames.get(target_index).map(ContextFrameRef::Frame)
246 }
247
248 pub fn current(&self) -> ContextFrameRef<'_> {
250 if let Some(frame) = self.frames.last() {
251 ContextFrameRef::Frame(frame)
252 } else {
253 ContextFrameRef::Root(&self.root)
254 }
255 }
256
257 pub fn root(&self) -> ContextFrameRef<'_> {
259 ContextFrameRef::Root(&self.root)
260 }
261
262 pub fn depth(&self) -> usize {
264 self.frames.len()
265 }
266}