1use crate::error::Error;
2use crate::error::Result;
3use crate::model::{Object, ObjectView, ScalarCow, Value, ValueCow, ValueView};
4
5use super::Registers;
6
7pub struct StackFrame<P, O> {
9 parent: P,
10 name: Option<crate::model::KString>,
11 data: O,
12}
13
14impl<P: super::Runtime, O: ObjectView> StackFrame<P, O> {
15 pub fn new(parent: P, data: O) -> Self {
17 Self {
18 parent,
19 name: None,
20 data,
21 }
22 }
23
24 pub fn with_name<S: Into<crate::model::KString>>(mut self, name: S) -> Self {
26 self.name = Some(name.into());
27 self
28 }
29}
30
31impl<P: super::Runtime, O: ObjectView> super::Runtime for StackFrame<P, O> {
32 fn partials(&self) -> &dyn super::PartialStore {
33 self.parent.partials()
34 }
35
36 fn name(&self) -> Option<crate::model::KStringRef<'_>> {
37 self.name
38 .as_ref()
39 .map(|n| n.as_ref())
40 .or_else(|| self.parent.name())
41 }
42
43 fn roots(&self) -> std::collections::BTreeSet<crate::model::KStringCow<'_>> {
44 let mut roots = self.parent.roots();
45 roots.extend(self.data.keys());
46 roots
47 }
48
49 fn try_get(&self, path: &[ScalarCow<'_>]) -> Option<ValueCow<'_>> {
50 let key = path.first()?;
51 let key = key.to_kstr();
52 let data = &self.data;
53 if data.contains_key(key.as_str()) {
54 crate::model::try_find(data.as_value(), path)
55 } else {
56 self.parent.try_get(path)
57 }
58 }
59
60 fn get(&self, path: &[ScalarCow<'_>]) -> Result<ValueCow<'_>> {
61 let key = path.first().ok_or_else(|| {
62 Error::with_msg("Unknown variable").context("requested variable", "nil")
63 })?;
64 let key = key.to_kstr();
65 let data = &self.data;
66 if data.contains_key(key.as_str()) {
67 crate::model::find(data.as_value(), path).map(|v| v.into_owned().into())
68 } else {
69 self.parent.get(path)
70 }
71 }
72
73 fn set_global(
74 &self,
75 name: crate::model::KString,
76 val: crate::model::Value,
77 ) -> Option<crate::model::Value> {
78 self.parent.set_global(name, val)
79 }
80
81 fn set_index(&self, name: crate::model::KString, val: Value) -> Option<Value> {
82 self.parent.set_index(name, val)
83 }
84
85 fn get_index<'a>(&'a self, name: &str) -> Option<ValueCow<'a>> {
86 self.parent.get_index(name)
87 }
88
89 fn registers(&self) -> &super::Registers {
90 self.parent.registers()
91 }
92}
93
94pub struct GlobalFrame<P> {
96 parent: P,
97 data: std::cell::RefCell<Object>,
98}
99
100impl<P: super::Runtime> GlobalFrame<P> {
101 pub fn new(parent: P) -> Self {
103 Self {
104 parent,
105 data: Default::default(),
106 }
107 }
108}
109
110impl<P: super::Runtime> super::Runtime for GlobalFrame<P> {
111 fn partials(&self) -> &dyn super::PartialStore {
112 self.parent.partials()
113 }
114
115 fn name(&self) -> Option<crate::model::KStringRef<'_>> {
116 self.parent.name()
117 }
118
119 fn roots(&self) -> std::collections::BTreeSet<crate::model::KStringCow<'_>> {
120 let mut roots = self.parent.roots();
121 roots.extend(self.data.borrow().keys().map(|k| k.clone().into()));
122 roots
123 }
124
125 fn try_get(&self, path: &[ScalarCow<'_>]) -> Option<ValueCow<'_>> {
126 let key = path.first()?;
127 let key = key.to_kstr();
128 let data = self.data.borrow();
129 if data.contains_key(key.as_str()) {
130 crate::model::try_find(data.as_value(), path).map(|v| v.into_owned().into())
131 } else {
132 self.parent.try_get(path)
133 }
134 }
135
136 fn get(&self, path: &[ScalarCow<'_>]) -> Result<ValueCow<'_>> {
137 let key = path.first().ok_or_else(|| {
138 Error::with_msg("Unknown variable").context("requested variable", "nil")
139 })?;
140 let key = key.to_kstr();
141 let data = self.data.borrow();
142 if data.contains_key(key.as_str()) {
143 crate::model::find(data.as_value(), path).map(|v| v.into_owned().into())
144 } else {
145 self.parent.get(path)
146 }
147 }
148
149 fn set_global(
150 &self,
151 name: crate::model::KString,
152 val: crate::model::Value,
153 ) -> Option<crate::model::Value> {
154 let mut data = self.data.borrow_mut();
155 data.insert(name, val)
156 }
157
158 fn set_index(&self, name: crate::model::KString, val: Value) -> Option<Value> {
159 self.parent.set_index(name, val)
160 }
161
162 fn get_index<'a>(&'a self, name: &str) -> Option<ValueCow<'a>> {
163 self.parent.get_index(name)
164 }
165
166 fn registers(&self) -> &super::Registers {
167 self.parent.registers()
168 }
169}
170
171pub(crate) struct IndexFrame<P> {
172 parent: P,
173 data: std::cell::RefCell<Object>,
174}
175
176impl<P: super::Runtime> IndexFrame<P> {
177 pub fn new(parent: P) -> Self {
178 Self {
179 parent,
180 data: Default::default(),
181 }
182 }
183}
184
185impl<P: super::Runtime> super::Runtime for IndexFrame<P> {
186 fn partials(&self) -> &dyn super::PartialStore {
187 self.parent.partials()
188 }
189
190 fn name(&self) -> Option<crate::model::KStringRef<'_>> {
191 self.parent.name()
192 }
193
194 fn roots(&self) -> std::collections::BTreeSet<crate::model::KStringCow<'_>> {
195 let mut roots = self.parent.roots();
196 roots.extend(self.data.borrow().keys().map(|k| k.clone().into()));
197 roots
198 }
199
200 fn try_get(&self, path: &[ScalarCow<'_>]) -> Option<ValueCow<'_>> {
201 let key = path.first()?;
202 let key = key.to_kstr();
203 let data = self.data.borrow();
204 if data.contains_key(key.as_str()) {
205 crate::model::try_find(data.as_value(), path).map(|v| v.into_owned().into())
206 } else {
207 self.parent.try_get(path)
208 }
209 }
210
211 fn get(&self, path: &[ScalarCow<'_>]) -> Result<ValueCow<'_>> {
212 let key = path.first().ok_or_else(|| {
213 Error::with_msg("Unknown variable").context("requested variable", "nil")
214 })?;
215 let key = key.to_kstr();
216 let data = self.data.borrow();
217 if data.contains_key(key.as_str()) {
218 crate::model::find(data.as_value(), path).map(|v| v.into_owned().into())
219 } else {
220 self.parent.get(path)
221 }
222 }
223
224 fn set_global(
225 &self,
226 name: crate::model::KString,
227 val: crate::model::Value,
228 ) -> Option<crate::model::Value> {
229 self.parent.set_global(name, val)
230 }
231
232 fn set_index(&self, name: crate::model::KString, val: Value) -> Option<Value> {
233 let mut data = self.data.borrow_mut();
234 data.insert(name, val)
235 }
236
237 fn get_index<'a>(&'a self, name: &str) -> Option<ValueCow<'a>> {
238 self.data.borrow().get(name).map(|v| v.to_value().into())
239 }
240
241 fn registers(&self) -> &super::Registers {
242 self.parent.registers()
243 }
244}
245
246pub struct SandboxedStackFrame<P, O> {
249 parent: P,
250 name: Option<crate::model::KString>,
251 data: O,
252 registers: Registers,
253}
254
255impl<P: super::Runtime, O: ObjectView> SandboxedStackFrame<P, O> {
256 pub fn new(parent: P, data: O) -> Self {
258 Self {
259 parent,
260 name: None,
261 data,
262 registers: Default::default(),
263 }
264 }
265
266 pub fn with_name<S: Into<crate::model::KString>>(mut self, name: S) -> Self {
268 self.name = Some(name.into());
269 self
270 }
271}
272
273impl<P: super::Runtime, O: ObjectView> super::Runtime for SandboxedStackFrame<P, O> {
274 fn partials(&self) -> &dyn super::PartialStore {
275 self.parent.partials()
276 }
277
278 fn name(&self) -> Option<crate::model::KStringRef<'_>> {
279 self.name
280 .as_ref()
281 .map(|n| n.as_ref())
282 .or_else(|| self.parent.name())
283 }
284
285 fn roots(&self) -> std::collections::BTreeSet<crate::model::KStringCow<'_>> {
286 let mut roots = std::collections::BTreeSet::new();
287 roots.extend(self.data.keys());
288 roots
289 }
290
291 fn try_get(&self, path: &[ScalarCow<'_>]) -> Option<ValueCow<'_>> {
292 let key = path.first()?;
293 let key = key.to_kstr();
294 let data = &self.data;
295 data.get(key.as_str())
296 .and_then(|_| crate::model::try_find(data.as_value(), path))
297 }
298
299 fn get(&self, path: &[ScalarCow<'_>]) -> Result<ValueCow<'_>> {
300 let key = path.first().ok_or_else(|| {
301 Error::with_msg("Unknown variable").context("requested variable", "nil")
302 })?;
303 let key = key.to_kstr();
304 let data = &self.data;
305 data.get(key.as_str())
306 .and_then(|_| crate::model::try_find(data.as_value(), path))
307 .map(|v| v.into_owned().into())
308 .ok_or_else(|| Error::with_msg("Unknown variable").context("requested variable", key))
309 }
310
311 fn set_global(
312 &self,
313 name: crate::model::KString,
314 val: crate::model::Value,
315 ) -> Option<crate::model::Value> {
316 self.parent.set_global(name, val)
317 }
318
319 fn set_index(&self, name: crate::model::KString, val: Value) -> Option<Value> {
320 self.parent.set_index(name, val)
321 }
322
323 fn get_index<'a>(&'a self, name: &str) -> Option<ValueCow<'a>> {
324 self.parent.get_index(name)
325 }
326
327 fn registers(&self) -> &super::Registers {
328 &self.registers
329 }
330}
331
332#[cfg(test)]
333mod tests {
334 use crate::{runtime::RuntimeBuilder, Runtime};
335
336 use super::*;
337
338 #[test]
339 fn test_opaque_stack_frame_try_get() {
340 let globals = {
341 let mut o = Object::new();
342 o.insert("a".into(), Value::Scalar(1i64.into()));
343 o
344 };
345 let runtime = RuntimeBuilder::new().set_globals(&globals).build();
346 let opaque_stack_frame = SandboxedStackFrame::new(&runtime, {
347 let mut o = Object::new();
348 o.insert("b".into(), Value::Scalar(2i64.into()));
349 o
350 });
351
352 assert!(opaque_stack_frame.try_get(&["a".into()]).is_none());
354 assert!(opaque_stack_frame.try_get(&["b".into()]).is_some());
355
356 let stack_frame = StackFrame::new(opaque_stack_frame, {
357 let mut o = Object::new();
358 o.insert("c".into(), Value::Scalar(1i64.into()));
359 o
360 });
361
362 assert!(stack_frame.try_get(&["a".into()]).is_none());
364 assert!(stack_frame.try_get(&["b".into()]).is_some());
365 assert!(stack_frame.try_get(&["c".into()]).is_some());
366 }
367
368 #[test]
369 fn test_opaque_stack_frame_get() {
370 let globals = {
371 let mut o = Object::new();
372 o.insert("a".into(), Value::Scalar(1i64.into()));
373 o
374 };
375 let runtime = RuntimeBuilder::new().set_globals(&globals).build();
376 let opaque_stack_frame = SandboxedStackFrame::new(&runtime, {
377 let mut o = Object::new();
378 o.insert("b".into(), Value::Scalar(2i64.into()));
379 o
380 });
381
382 assert!(opaque_stack_frame.get(&["a".into()]).is_err());
384 assert!(opaque_stack_frame.get(&["b".into()]).is_ok());
385
386 let stack_frame = StackFrame::new(opaque_stack_frame, {
387 let mut o = Object::new();
388 o.insert("c".into(), Value::Scalar(1i64.into()));
389 o
390 });
391
392 assert!(stack_frame.get(&["a".into()]).is_err());
394 assert!(stack_frame.get(&["b".into()]).is_ok());
395 assert!(stack_frame.get(&["c".into()]).is_ok());
396 }
397
398 #[test]
399 fn test_opaque_stack_frame_roots() {
400 let globals = {
401 let mut o = Object::new();
402 o.insert("a".into(), Value::Scalar(1i64.into()));
403 o
404 };
405 let runtime = RuntimeBuilder::new().set_globals(&globals).build();
406 let opaque_stack_frame = SandboxedStackFrame::new(&runtime, {
407 let mut o = Object::new();
408 o.insert("b".into(), Value::Scalar(2i64.into()));
409 o
410 });
411 let roots = opaque_stack_frame.roots();
412
413 assert!(!roots.contains("a"));
415 assert!(roots.contains("b"));
416 }
417}