Materialise an iterable into Vec for `*args` positional spread. */
(&mut self, v: Val)
| 60 | |
| 61 | /* Materialise an iterable into Vec<Val> for `*args` positional spread. */ |
| 62 | pub(crate) fn iter_to_vec_for_spread(&mut self, v: Val) -> Result<Vec<Val>, VmErr> { |
| 63 | if !v.is_heap() { return Err(VmErr::Type("argument after * must be an iterable")); } |
| 64 | Ok(match self.heap.get(v) { |
| 65 | HeapObj::List(rc) => rc.borrow().clone(), |
| 66 | HeapObj::Tuple(t) => t.clone(), |
| 67 | HeapObj::Set(rc) => rc.borrow().iter().cloned().collect(), |
| 68 | HeapObj::Range(s, e, st) => { |
| 69 | let (s, e, st) = (*s, *e, *st); |
| 70 | if st == 0 { return Err(VmErr::Value("range() arg 3 must not be zero")); } |
| 71 | // Spreading a huge range would build a giant arg vec; cap against the heap budget. |
| 72 | let count = (e as i128 - s as i128).unsigned_abs() / (st as i128).unsigned_abs(); |
| 73 | if count > self.heap.limit() as u128 { return Err(VmErr::Heap); } |
| 74 | let mut out = Vec::new(); |
| 75 | let mut i = s; |
| 76 | // range_int promotes past the 47-bit inline range; checked_add ends at the i64 edge. |
| 77 | if st > 0 { while i < e { out.push(range_int(&mut self.heap, i)?); match i.checked_add(st) { Some(n) => i = n, None => break } } } |
| 78 | else { while i > e { out.push(range_int(&mut self.heap, i)?); match i.checked_add(st) { Some(n) => i = n, None => break } } } |
| 79 | out |
| 80 | } |
| 81 | _ => return Err(VmErr::Type("argument after * must be an iterable")), |
| 82 | }) |
| 83 | } |
| 84 | |
| 85 | /* Materialise a mapping into (key_str, value) pairs for `**kwargs` spread. */ |
| 86 | pub(crate) fn mapping_to_kw_pairs(&self, v: Val) -> Result<Vec<(Val, Val)>, VmErr> { |
no test coverage detected