1use crate::{ops::*, value::*};
2
3use std::{
4 borrow::Cow,
5 collections::BTreeMap,
6 ops::{Deref, DerefMut},
7};
8
9use anyhow::{anyhow, bail, ensure, Ok, Result};
10
11const MAX_DEPTH: usize = 250;
12const MAX_PROTOCOL: u8 = 5;
13
14#[derive(Debug, Clone, PartialEq, Default)]
15pub struct PickleStack<'a>(pub Vec<Value<'a>>);
17
18impl<'a> PickleStack<'a> {
19 pub fn pop(&mut self) -> Result<Value<'a>> {
20 self.0.pop().ok_or_else(|| anyhow!("Stack underrun"))
21 }
22
23 pub fn pop_mark(&mut self) -> Result<Vec<Value<'a>>> {
24 let markidx = self.find_mark()?;
25 let postmark = self.0[markidx + 1..].to_owned();
26 self.truncate(markidx);
27 Ok(postmark)
28 }
29
30 pub fn find_mark(&self) -> Result<usize> {
31 Ok(self
32 .0
33 .iter()
34 .enumerate()
35 .rfind(|(_idx, op)| matches!(op, Value::Raw(Cow::Borrowed(&PickleOp::MARK))))
36 .map(|(idx, _)| idx)
37 .ok_or_else(|| anyhow!("Missing MARK"))?)
38 }
39}
40
41impl<'a> Deref for PickleStack<'a> {
42 type Target = Vec<Value<'a>>;
43
44 fn deref(&self) -> &Self::Target {
45 &self.0
46 }
47}
48
49impl<'a> DerefMut for PickleStack<'a> {
50 fn deref_mut(&mut self) -> &mut Self::Target {
51 &mut self.0
52 }
53}
54
55#[derive(Debug, Clone, PartialEq, Default)]
56pub struct PickleMemo<'a>(pub BTreeMap<u32, Value<'a>>);
58
59impl<'a> PickleMemo<'a> {
60 pub fn resolve(&self, mut op: Value<'a>, recursive: bool) -> Result<Value<'a>> {
65 let mut count = 0;
66 while let Value::Ref(ref mid) = op {
67 let val = self.0.get(mid).ok_or_else(|| anyhow!("Bad memo id"))?;
68 if !recursive {
69 return Ok(val.to_owned());
70 }
71 op = val.to_owned();
72 count += 1;
73 if count >= MAX_DEPTH {
74 break;
76 }
77 }
78
79 Ok(op)
80 }
81
82 pub fn insert(&mut self, mid: u32, val: Value<'a>) {
83 self.0.insert(mid, val);
84 }
85
86 pub fn resolve_mut<'b, 'c>(
88 &'c mut self,
89 op: &'b mut Value<'a>,
90 recursive: bool,
91 ) -> Result<&'c mut Value<'a>>
92 where
93 'b: 'c,
94 'c: 'b,
95 {
96 let mut lastmid = if let Value::Ref(ref mid) = op {
97 *mid
98 } else {
99 return Ok(op);
100 };
101
102 let mut count = 0;
103 while let Value::Ref(mid) = self.0.get(&lastmid).ok_or_else(|| anyhow!("Bad memo id"))? {
104 lastmid = *mid;
105 if !recursive {
106 break;
107 }
108 count += 1;
109 if count >= MAX_DEPTH {
110 break;
112 }
113 }
114 Ok(self
117 .0
118 .get_mut(&lastmid)
119 .expect("Impossible: Missing memo id"))
120 }
121
122 pub fn resolve_all_refs_iter(
126 &self,
127 depth: usize,
128 vals: impl IntoIterator<Item = Value<'a>>,
129 fix_values: bool,
130 ) -> Result<Vec<Value<'a>>> {
131 if depth >= MAX_DEPTH {
132 return Ok(vals.into_iter().collect::<Vec<_>>());
134 }
135 vals.into_iter()
136 .map(|val| self.resolve_all_refs(depth + 1, val, fix_values))
137 .collect::<Result<Vec<_>>>()
138 }
139
140 pub fn resolve_all_refs(
144 &self,
145 depth: usize,
146 val: Value<'a>,
147 fix_values: bool,
148 ) -> Result<Value<'a>> {
149 if depth >= MAX_DEPTH {
150 return Ok(val);
152 }
153 let rar = |v| self.resolve_all_refs(depth + 1, v, fix_values);
154 let rir = |i| self.resolve_all_refs_iter(depth + 1, i, fix_values);
155
156 let output = match val {
157 val @ Value::Ref(_) => rar(self.resolve(val, true)?)?,
158 Value::App(apped, apps) => Value::App(Box::new(rar(*apped)?), rir(apps)?),
159 Value::Object(apped, apps) => Value::Object(Box::new(rar(*apped)?), rir(apps)?),
160 Value::Build(apped, apps) => {
161 Value::Build(Box::new(rar(*apped)?), Box::new(rar(*apps)?))
162 }
163 Value::Global(target, args) => Value::Global(Box::new(rar(*target)?), rir(args)?),
164 Value::Seq(st, args) => Value::Seq(st, rir(args)?),
165 Value::PersId(pid) => Value::PersId(Box::new(rar(*pid)?)),
166 val => val,
167 };
168 if fix_values {
169 fix_value(output)
170 } else {
171 Ok(output)
172 }
173 }
174}
175
176pub fn evaluate<'a>(
182 x: &'a [PickleOp],
183 resolve_refs: bool,
184) -> Result<(Vec<Value<'a>>, PickleMemo<'a>)> {
185 let mut stack = PickleStack::default();
186 let mut memo = PickleMemo::default();
187
188 fn make_kvlist(items: Vec<Value<'_>>) -> Result<Vec<Value<'_>>> {
189 ensure!(items.len() & 1 == 0, "Bad value for setitems");
190 let mut kvitems = Vec::with_capacity(items.len());
191 let mut it = items.into_iter();
192 while let Some(k) = it.next() {
193 let v = it.next().expect("Impossible: Missing value item");
194 kvitems.push(Value::Seq(SequenceType::Tuple, vec![k, v]));
195 }
196 Ok(kvitems)
197 }
198
199 for op in x.iter() {
200 let stack = &mut stack;
201
202 match op {
203 PickleOp::MARK => stack.push(Value::Raw(Cow::Borrowed(op))),
204 PickleOp::STOP => break,
205 PickleOp::POP => {
206 let _ = stack.pop()?;
207 }
208 PickleOp::POP_MARK => {
209 let _ = stack.pop_mark()?;
210 }
211 PickleOp::DUP => {
212 let item = stack
213 .last()
214 .ok_or_else(|| anyhow!("Cannot DUP with empty stack"))?
215 .to_owned();
216 stack.push(item);
217 }
218 PickleOp::PERSID(pid) => stack.push(Value::PersId(Box::new(Value::String(pid)))),
219 PickleOp::BINPERSID => {
220 let pid = stack.pop()?;
221 stack.push(Value::PersId(Box::new(pid)));
222 }
223 PickleOp::REDUCE => {
224 let args = memo.resolve(stack.pop()?, true)?;
225 let target = memo.resolve(stack.pop()?, true)?;
226 stack.push(Value::Global(Box::new(target), vec![args]));
227 }
228 PickleOp::BUILD => {
229 let args = Box::new(memo.resolve(stack.pop()?, true)?);
230 let target = Box::new(memo.resolve(stack.pop()?, true)?);
231 stack.push(Value::Build(target, args));
232 }
233 PickleOp::EMPTY_DICT => stack.push(Value::Seq(SequenceType::Dict, Default::default())),
234 PickleOp::GET(mids) => stack.push(Value::Ref(mids.parse()?)),
235 PickleOp::BINGET(mid) => stack.push(Value::Ref(*mid as u32)),
236 PickleOp::LONG_BINGET(mid) => stack.push(Value::Ref(*mid)),
237 PickleOp::EMPTY_LIST => stack.push(Value::Seq(SequenceType::List, Default::default())),
238 PickleOp::BINPUT(mid) => {
239 let mid = *mid as u32;
240 memo.insert(mid, stack.pop()?);
241 stack.push(Value::Ref(mid));
242 }
243 PickleOp::LONG_BINPUT(mid) => {
244 memo.insert(*mid, stack.pop()?);
245 stack.push(Value::Ref(*mid));
246 }
247 PickleOp::TUPLE => {
248 let postmark = stack.pop_mark()?;
249 stack.push(Value::Seq(SequenceType::Tuple, postmark));
250 }
251 PickleOp::EMPTY_TUPLE => {
252 stack.push(Value::Seq(SequenceType::Tuple, Default::default()))
253 }
254 PickleOp::SETITEM => {
255 let v = stack.pop()?;
256 let k = stack.pop()?;
257 let top = stack
258 .last_mut()
259 .ok_or_else(|| anyhow!("Unexpected empty stack"))?;
260 let rtop = memo.resolve_mut(top, true)?;
261 match rtop {
262 Value::Global(_, args) | Value::Seq(_, args) => {
263 args.push(Value::Seq(SequenceType::Tuple, vec![k, v]));
264 }
265 _wut => bail!("Bad stack top for SETITEM!"),
266 }
267 }
268 PickleOp::SETITEMS => {
269 let kvitems = make_kvlist(stack.pop_mark()?)?;
270 let top = stack
271 .last_mut()
272 .ok_or_else(|| anyhow!("Unexpected empty stack"))?;
273 let rtop = memo.resolve_mut(top, true)?;
274 match rtop {
275 Value::Global(_, args) | Value::Seq(_, args) => {
276 args.push(Value::Seq(SequenceType::Tuple, kvitems));
277 }
278 _wut => bail!("Bad stack top for SETITEMS"),
279 }
280 }
281 PickleOp::PROTO(proto) => {
282 ensure!(*proto <= MAX_PROTOCOL, "Unsupported protocol {proto}")
283 }
284 PickleOp::TUPLE1 => {
285 let t1 = stack.pop()?;
286 stack.push(Value::Seq(SequenceType::Tuple, vec![t1]));
287 }
288 PickleOp::TUPLE2 => {
289 let (t2, t1) = (stack.pop()?, stack.pop()?);
290 stack.push(Value::Seq(SequenceType::Tuple, vec![t1, t2]));
291 }
292 PickleOp::TUPLE3 => {
293 let (t3, t2, t1) = (stack.pop()?, stack.pop()?, stack.pop()?);
294 stack.push(Value::Seq(SequenceType::Tuple, vec![t1, t2, t3]));
295 }
296 PickleOp::APPEND => {
297 let v = stack.pop()?;
298 let top = stack
299 .last_mut()
300 .ok_or_else(|| anyhow!("Unexpected empty stack"))?;
301 let rtop = memo.resolve_mut(top, true)?;
302 match rtop {
303 Value::Global(_, args) | Value::Seq(_, args) => {
304 args.push(v);
305 }
306 _wut => bail!("Bad stack top for APPEND!"),
307 }
308 }
309 PickleOp::APPENDS => {
310 let postmark = stack.pop_mark()?;
311 let top = stack
312 .last_mut()
313 .ok_or_else(|| anyhow!("Unexpected empty stack"))?;
314 let rtop = memo.resolve_mut(top, true)?;
315
316 match rtop {
317 Value::Global(_, args) | Value::Seq(_, args) => {
318 args.extend(postmark);
319 }
320 _wut => bail!("Bad stack top for APPENDS"),
321 }
322 }
323 PickleOp::DICT => {
324 let kvitems = make_kvlist(stack.pop_mark()?)?;
325 stack.push(Value::Seq(SequenceType::Dict, kvitems));
326 }
327 PickleOp::LIST => {
328 let items = stack.pop_mark()?;
329 stack.push(Value::Seq(SequenceType::List, items));
330 }
331 PickleOp::INST(mn, cn) => {
332 let args = stack.pop_mark()?;
333 stack.push(Value::Object(
334 Box::new(Value::Seq(
335 SequenceType::Tuple,
336 vec![Value::String(mn), Value::String(cn)],
337 )),
338 args,
339 ))
340 }
341 PickleOp::OBJ => {
342 let markidx = stack.find_mark()?;
343 let args = stack.0[markidx + 2..].to_owned();
344 let cls = stack.0[markidx + 1].clone();
345 stack.0.truncate(markidx);
346 stack.push(Value::Object(Box::new(cls), args));
347 }
348 PickleOp::PUT(midstr) => {
349 let mid = midstr.parse()?;
352 memo.insert(mid, stack.pop()?);
353 stack.push(Value::Ref(mid));
354 }
355 PickleOp::NEWOBJ => {
356 let (args, cls) = (stack.pop()?, stack.pop()?);
357 stack.push(Value::Object(Box::new(cls), vec![args]))
358 }
359 PickleOp::EMPTY_SET => stack.push(Value::Seq(SequenceType::Set, vec![])),
360 PickleOp::ADDITEMS => {
361 let postmark = stack.pop_mark()?;
362 let top = stack
363 .last_mut()
364 .ok_or_else(|| anyhow!("Unexpected empty stack"))?;
365 let rtop = memo.resolve_mut(top, true)?;
366
367 match rtop {
368 Value::Global(_, args) | Value::Seq(_, args) => {
369 args.extend(postmark);
370 }
371 _wut => bail!("Bad stack top for ADDITEMS"),
372 }
373 }
374 PickleOp::FROZENSET => {
375 let items = stack.pop_mark()?;
376 stack.push(Value::Seq(SequenceType::FrozenSet, items));
377 }
378 PickleOp::NEWOBJ_EX => {
379 let (kwargs, args, cls) = (stack.pop()?, stack.pop()?, stack.pop()?);
380 stack.push(Value::Object(
381 Box::new(cls),
382 vec![Value::Seq(SequenceType::Tuple, vec![args, kwargs])],
383 ))
384 }
385 PickleOp::STACK_GLOBAL => {
386 let (gn, mn) = (
387 memo.resolve(stack.pop()?, true)?,
388 memo.resolve(stack.pop()?, true)?,
389 );
390 stack.push(Value::Global(
391 Box::new(Value::Seq(SequenceType::Tuple, vec![gn, mn])),
392 vec![],
393 ));
394 }
395 PickleOp::MEMOIZE => {
396 let item = stack.last().ok_or_else(|| anyhow!("Stack underrun"))?;
397 memo.insert(memo.0.len() as u32, item.to_owned());
398 }
399
400 op => stack.push(Value::Raw(Cow::Borrowed(op))),
402 }
403 }
404 if !resolve_refs {
405 return Ok((stack.0, memo));
406 }
407 let stack = memo.resolve_all_refs_iter(0, stack.0, true)?;
408
409 Ok((stack, memo))
410}