Item presence in list/tuple/dict/set, or substring in string. Non-iterable container raises TypeError. */
(&self, container: Val, item: Val)
| 396 | |
| 397 | /* Item presence in list/tuple/dict/set, or substring in string. Non-iterable container raises TypeError. */ |
| 398 | pub fn contains(&self, container: Val, item: Val) -> Result<bool, VmErr> { |
| 399 | if container.is_heap() { |
| 400 | match self.heap.get(container) { |
| 401 | HeapObj::List(v) => return Ok(v.borrow().iter().any(|x| eq_vals_with_heap(*x, item, &self.heap))), |
| 402 | HeapObj::Tuple(v) => return Ok(v.iter().any(|x| eq_vals_with_heap(*x, item, &self.heap))), |
| 403 | HeapObj::Dict(p) => return Ok(p.borrow().contains_key(&item, &self.heap)), |
| 404 | HeapObj::Set(s) => return Ok(s.borrow().iter().any(|x| eq_vals_with_heap(*x, item, &self.heap))), |
| 405 | HeapObj::FrozenSet(s) => return Ok(s.iter().any(|x| eq_vals_with_heap(*x, item, &self.heap))), |
| 406 | HeapObj::Str(s) => { |
| 407 | if item.is_heap() && let HeapObj::Str(sub) = self.heap.get(item) { return Ok(s.contains(sub.as_str())); } |
| 408 | return Ok(false); |
| 409 | } |
| 410 | HeapObj::Range(s, e, st) => { |
| 411 | let (s, e, st) = (*s as i128, *e as i128, *st as i128); |
| 412 | // O(1) range membership: bounds + step; integral floats match too. |
| 413 | let x = match as_i128(item, &self.heap) { |
| 414 | Some(i) => Some(i), |
| 415 | None if item.is_float() => { |
| 416 | let v = item.as_float(); |
| 417 | if v.is_finite() && v == libm::trunc(v) { Some(v as i128) } else { None } |
| 418 | } |
| 419 | None => None, |
| 420 | }; |
| 421 | return Ok(match x { |
| 422 | Some(x) => { |
| 423 | let in_bounds = if st > 0 { x >= s && x < e } else { x <= s && x > e }; |
| 424 | in_bounds && st != 0 && (x - s) % st == 0 |
| 425 | } |
| 426 | None => false, |
| 427 | }); |
| 428 | } |
| 429 | // Iterable kinds keep prior non-raising behavior. |
| 430 | HeapObj::Bytes(..) | HeapObj::Coroutine(..) => return Ok(false), |
| 431 | _ => {} |
| 432 | } |
| 433 | } |
| 434 | Err(VmErr::TypeMsg(s!("argument of type '", str self.type_name(container), "' is not iterable"))) |
| 435 | } |
| 436 | pub fn add_vals(&mut self, a: Val, b: Val) -> Result<Val, VmErr> { |
| 437 | // Inline-int fast path; overflow falls through to the i128 slow path. |
| 438 | if a.is_int() && b.is_int() |