1use std::cmp::Ordering;
23use std::rc::Rc;
24
25use num_bigint::BigInt;
26use num_traits::FromPrimitive;
27
28use crate::dict::Set;
29use crate::error::{Error, Kind, Result};
30use crate::hash::Key;
31use crate::int::{DivideByZero, Int};
32use crate::object::Object;
33use crate::slice::Indices;
34use crate::text::{Str, StrBuf};
35
36const REPEAT_LIMIT: u64 = 1 << 40;
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq)]
48pub enum Compare {
49 Eq,
51 Ne,
53 Lt,
55 Le,
57 Gt,
59 Ge,
61}
62
63impl Compare {
64 #[must_use]
66 pub const fn symbol(self) -> &'static str {
67 match self {
68 Compare::Eq => "==",
69 Compare::Ne => "!=",
70 Compare::Lt => "<",
71 Compare::Le => "<=",
72 Compare::Gt => ">",
73 Compare::Ge => ">=",
74 }
75 }
76
77 #[must_use]
79 const fn decide(self, ordering: Ordering) -> bool {
80 match self {
81 Compare::Eq => ordering.is_eq(),
82 Compare::Ne => ordering.is_ne(),
83 Compare::Lt => ordering.is_lt(),
84 Compare::Le => ordering.is_le(),
85 Compare::Gt => ordering.is_gt(),
86 Compare::Ge => ordering.is_ge(),
87 }
88 }
89
90 #[must_use]
92 const fn is_equality(self) -> bool {
93 matches!(self, Compare::Eq | Compare::Ne)
94 }
95}
96
97pub fn add(left: &Object, right: &Object) -> Result<Object> {
103 if let Some(pair) = promote(left, right)? {
104 return Ok(match pair {
105 Pair::Ints(a, b) => Object::Int(a.add(b)),
106 Pair::Floats(a, b) => Object::Float(a + b),
107 });
108 }
109 match (left, right) {
110 (Object::Str(a), Object::Str(b)) => {
111 let mut buf = StrBuf::new();
112 buf.push_string(a);
113 buf.push_string(b);
114 Ok(Object::Str(Rc::new(buf.finish())))
115 }
116 (Object::Bytes(a), Object::Bytes(b)) => {
117 let mut joined = a.to_vec();
118 joined.extend_from_slice(b);
119 Ok(Object::Bytes(joined.into()))
120 }
121 (Object::Tuple(a), Object::Tuple(b)) => {
122 let mut joined = a.to_vec();
123 joined.extend_from_slice(b);
124 Ok(Object::tuple(joined))
125 }
126 (Object::List(a), Object::List(b)) => {
127 let mut joined = a.borrow().clone();
130 joined.extend(b.borrow().iter().cloned());
131 Ok(Object::list(joined))
132 }
133 _ => Err(concat_error(left, right)),
134 }
135}
136
137pub fn sub(left: &Object, right: &Object) -> Result<Object> {
139 if let Some(pair) = promote(left, right)? {
140 return Ok(match pair {
141 Pair::Ints(a, b) => Object::Int(a.sub(b)),
142 Pair::Floats(a, b) => Object::Float(a - b),
143 });
144 }
145 if let (Object::Set(a), Object::Set(b)) = (left, right) {
146 let (a, b) = (a.borrow(), b.borrow());
147 return Ok(Object::set(
148 a.iter().filter(|key| !b.contains(key)).cloned().collect(),
149 ));
150 }
151 Err(unsupported("-", left, right))
152}
153
154pub fn mul(left: &Object, right: &Object) -> Result<Object> {
160 if let Some(pair) = promote(left, right)? {
161 return Ok(match pair {
162 Pair::Ints(a, b) => Object::Int(a.mul(b)),
163 Pair::Floats(a, b) => Object::Float(a * b),
164 });
165 }
166 let (sequence, count) = match (index(left), index(right)) {
169 (_, Some(count)) => (left, count?),
170 (Some(count), None) => (right, count?),
171 (None, None) => return Err(repeat_error(left, right)),
172 };
173 repeat(sequence, count)?.ok_or_else(|| repeat_error(left, right))
174}
175
176pub fn true_div(left: &Object, right: &Object) -> Result<Object> {
178 let Some(pair) = promote(left, right)? else {
179 return Err(unsupported("/", left, right));
180 };
181 match pair {
182 Pair::Ints(a, b) => match a.true_div(b) {
183 Ok(Some(value)) => Ok(Object::Float(value)),
184 Ok(None) => Err(Error::overflow(
185 "integer division result too large for a float",
186 )),
187 Err(DivideByZero) => Err(divide_by_zero()),
188 },
189 Pair::Floats(a, b) => {
190 if b == 0.0 {
191 return Err(divide_by_zero());
192 }
193 Ok(Object::Float(a / b))
194 }
195 }
196}
197
198pub fn floor_div(left: &Object, right: &Object) -> Result<Object> {
201 let Some(pair) = promote(left, right)? else {
202 return Err(unsupported("//", left, right));
203 };
204 match pair {
205 Pair::Ints(a, b) => a
206 .floor_div(b)
207 .map(Object::Int)
208 .map_err(|DivideByZero| divide_by_zero()),
209 Pair::Floats(a, b) => Ok(Object::Float(float_div_mod(a, b)?.0)),
210 }
211}
212
213pub fn modulo(left: &Object, right: &Object) -> Result<Object> {
222 let Some(pair) = promote(left, right)? else {
223 return Err(unsupported("%", left, right));
224 };
225 match pair {
226 Pair::Ints(a, b) => a
227 .modulo(b)
228 .map(Object::Int)
229 .map_err(|DivideByZero| divide_by_zero()),
230 Pair::Floats(a, b) => Ok(Object::Float(float_div_mod(a, b)?.1)),
231 }
232}
233
234pub fn div_mod(left: &Object, right: &Object) -> Result<Object> {
237 let Some(pair) = promote(left, right)? else {
238 return Err(unsupported("divmod()", left, right));
239 };
240 let (quotient, remainder) = match pair {
241 Pair::Ints(a, b) => {
242 let (q, r) = a.div_mod(b).map_err(|DivideByZero| divide_by_zero())?;
243 (Object::Int(q), Object::Int(r))
244 }
245 Pair::Floats(a, b) => {
246 let (q, r) = float_div_mod(a, b)?;
247 (Object::Float(q), Object::Float(r))
248 }
249 };
250 Ok(Object::tuple(vec![quotient, remainder]))
251}
252
253pub fn pow(base: &Object, exponent: &Object) -> Result<Object> {
260 let Some(pair) = promote(base, exponent)? else {
261 return Err(unsupported("** or pow()", base, exponent));
262 };
263 match pair {
264 Pair::Ints(a, b) if !b.is_negative() => match a.pow(b) {
265 Some(value) => Ok(Object::Int(value)),
266 None => Err(Error::new(Kind::MemoryError, "")),
270 },
271 Pair::Ints(a, b) => float_pow(to_float(a)?, to_float(b)?),
274 Pair::Floats(a, b) => float_pow(a, b),
275 }
276}
277
278pub fn lshift(left: &Object, right: &Object) -> Result<Object> {
280 shift(left, right, "<<", Int::shl)
281}
282
283pub fn rshift(left: &Object, right: &Object) -> Result<Object> {
286 shift(left, right, ">>", Int::shr)
287}
288
289pub fn bit_and(left: &Object, right: &Object) -> Result<Object> {
291 bitwise(left, right, "&", Int::bitand, |a, b| {
292 a.iter().filter(|key| b.contains(key)).cloned().collect()
293 })
294}
295
296pub fn bit_or(left: &Object, right: &Object) -> Result<Object> {
298 bitwise(left, right, "|", Int::bitor, |a, b| {
299 a.iter().chain(b.iter()).cloned().collect()
300 })
301}
302
303pub fn bit_xor(left: &Object, right: &Object) -> Result<Object> {
306 bitwise(left, right, "^", Int::bitxor, |a, b| {
307 a.iter()
308 .filter(|key| !b.contains(key))
309 .chain(b.iter().filter(|key| !a.contains(key)))
310 .cloned()
311 .collect()
312 })
313}
314
315pub fn neg(value: &Object) -> Result<Object> {
317 match number(value) {
318 Some(Num::Int(value)) => Ok(Object::Int(value.neg())),
319 Some(Num::Float(value)) => Ok(Object::Float(-value)),
320 None => Err(bad_unary("-", value)),
321 }
322}
323
324pub fn pos(value: &Object) -> Result<Object> {
326 match number(value) {
327 Some(Num::Int(value)) => Ok(Object::Int(value.clone())),
328 Some(Num::Float(value)) => Ok(Object::Float(value)),
329 None => Err(bad_unary("+", value)),
330 }
331}
332
333pub fn invert(value: &Object) -> Result<Object> {
335 match number(value) {
336 Some(Num::Int(value)) => Ok(Object::Int(value.invert())),
337 _ => Err(bad_unary("~", value)),
338 }
339}
340
341pub fn abs(value: &Object) -> Result<Object> {
349 match number(value) {
350 Some(Num::Int(value)) => Ok(Object::Int(value.abs())),
351 Some(Num::Float(value)) => Ok(Object::Float(value.abs())),
352 None => Err(Error::type_error(format!(
353 "bad operand type for abs(): '{}'",
354 value.type_name()
355 ))),
356 }
357}
358
359#[must_use]
361pub fn not(value: &Object) -> Object {
362 Object::Bool(!value.truthy())
363}
364
365pub fn compare(op: Compare, left: &Object, right: &Object) -> Result<Object> {
373 if op.is_equality() {
374 let equal = left.equals(right);
375 return Ok(Object::Bool(equal == (op == Compare::Eq)));
376 }
377 order(op, left, right).map(Object::Bool)
378}
379
380pub fn contains(container: &Object, value: &Object) -> Result<Object> {
382 let found = match container {
383 Object::Str(text) => {
384 let Object::Str(needle) = value else {
385 return Err(Error::type_error(format!(
386 "'in <string>' requires string as left operand, not {}",
387 value.type_name()
388 )));
389 };
390 substring(text, needle)
391 }
392 Object::Bytes(haystack) => match value {
393 Object::Bytes(needle) => subslice(haystack, needle),
394 Object::Int(_) | Object::Bool(_) => {
395 let Some(Num::Int(byte)) = number(value) else {
396 unreachable!("an int and a bool are both numbers")
397 };
398 let byte = byte
399 .to_i64()
400 .and_then(|value| u8::try_from(value).ok())
401 .ok_or_else(|| Error::value_error("byte must be in range(0, 256)"))?;
402 haystack.contains(&byte)
403 }
404 other => {
405 return Err(Error::type_error(format!(
406 "a bytes-like object is required, not '{}'",
407 other.type_name()
408 )));
409 }
410 },
411 Object::Tuple(items) => items.iter().any(|item| item.same_value(value)),
412 Object::List(items) => items.borrow().iter().any(|item| item.same_value(value)),
413 Object::Dict(entries) => entries.borrow().contains(&key(value, "dict key")?),
414 Object::Set(members) => members.borrow().contains(&key(value, "set element")?),
415 other => {
416 return Err(Error::type_error(format!(
417 "argument of type '{}' is not a container or iterable",
418 other.type_name()
419 )));
420 }
421 };
422 Ok(Object::Bool(found))
423}
424
425enum Num<'a> {
432 Int(&'a Int),
433 Float(f64),
434}
435
436enum Pair<'a> {
438 Ints(&'a Int, &'a Int),
439 Floats(f64, f64),
440}
441
442static FALSE: Int = Int::Small(0);
445static TRUE: Int = Int::Small(1);
446
447fn number(value: &Object) -> Option<Num<'_>> {
449 match value {
450 Object::Bool(true) => Some(Num::Int(&TRUE)),
451 Object::Bool(false) => Some(Num::Int(&FALSE)),
452 Object::Int(value) => Some(Num::Int(value)),
453 Object::Float(value) => Some(Num::Float(*value)),
454 _ => None,
455 }
456}
457
458fn promote<'a>(left: &'a Object, right: &'a Object) -> Result<Option<Pair<'a>>> {
464 let (Some(left), Some(right)) = (number(left), number(right)) else {
465 return Ok(None);
466 };
467 Ok(Some(match (left, right) {
468 (Num::Int(a), Num::Int(b)) => Pair::Ints(a, b),
469 (Num::Float(a), Num::Float(b)) => Pair::Floats(a, b),
470 (Num::Int(a), Num::Float(b)) => Pair::Floats(to_float(a)?, b),
471 (Num::Float(a), Num::Int(b)) => Pair::Floats(a, to_float(b)?),
472 }))
473}
474
475fn to_float(value: &Int) -> Result<f64> {
477 value
478 .to_f64()
479 .ok_or_else(|| Error::overflow("int too large to convert to float"))
480}
481
482fn float_pow(base: f64, exponent: f64) -> Result<Object> {
484 if base == 0.0 && exponent < 0.0 {
485 return Err(Error::zero_division("zero to a negative power"));
486 }
487 if base < 0.0 && exponent.is_finite() && exponent.fract() != 0.0 {
488 return Err(Error::new(
489 Kind::NotImplementedError,
490 "a negative number raised to a fractional power is a complex number, \
491 and complex numbers are not implemented yet",
492 ));
493 }
494 let value = base.powf(exponent);
495 if value.is_infinite() && base.is_finite() && exponent.is_finite() {
496 return Err(Error::overflow("(34, 'Result too large')"));
499 }
500 Ok(Object::Float(value))
501}
502
503fn float_div_mod(left: f64, right: f64) -> Result<(f64, f64)> {
510 if right == 0.0 {
511 return Err(divide_by_zero());
512 }
513 let mut remainder = left % right;
514 let mut quotient = (left - remainder) / right;
515 if remainder == 0.0 {
516 remainder = 0.0_f64.copysign(right);
518 } else if (right < 0.0) != (remainder < 0.0) {
519 remainder += right;
520 quotient -= 1.0;
521 }
522 let quotient = if quotient == 0.0 {
523 0.0_f64.copysign(left / right)
524 } else {
525 let floor = quotient.floor();
526 if quotient - floor > 0.5 {
530 floor + 1.0
531 } else {
532 floor
533 }
534 };
535 Ok((quotient, remainder))
536}
537
538fn shift(
540 left: &Object,
541 right: &Object,
542 symbol: &str,
543 apply: impl Fn(&Int, &Int) -> Option<Int>,
544) -> Result<Object> {
545 let (Some(Num::Int(a)), Some(Num::Int(b))) = (number(left), number(right)) else {
546 return Err(unsupported(symbol, left, right));
547 };
548 if b.is_negative() {
549 return Err(Error::value_error("negative shift count"));
550 }
551 match apply(a, b) {
552 Some(value) => Ok(Object::Int(value)),
553 None => Err(Error::new(Kind::MemoryError, "")),
554 }
555}
556
557fn bitwise(
559 left: &Object,
560 right: &Object,
561 symbol: &str,
562 on_ints: impl Fn(&Int, &Int) -> Int,
563 on_sets: impl Fn(&Set, &Set) -> Set,
564) -> Result<Object> {
565 if let (Some(Num::Int(a)), Some(Num::Int(b))) = (number(left), number(right)) {
566 let value = on_ints(a, b);
567 if matches!((left, right), (Object::Bool(_), Object::Bool(_))) {
570 return Ok(Object::Bool(!value.is_zero()));
571 }
572 return Ok(Object::Int(value));
573 }
574 if let (Object::Set(a), Object::Set(b)) = (left, right) {
575 let (a, b) = (a.borrow(), b.borrow());
576 return Ok(Object::set(on_sets(&a, &b)));
577 }
578 Err(unsupported(symbol, left, right))
579}
580
581fn index(value: &Object) -> Option<Result<usize>> {
588 let count = match number(value)? {
589 Num::Int(count) => count,
590 Num::Float(_) => return None,
591 };
592 if count.is_negative() {
595 return Some(Ok(0));
596 }
597 Some(
600 count
601 .to_usize()
602 .filter(|count| isize::try_from(*count).is_ok())
603 .ok_or_else(|| Error::overflow("cannot fit 'int' into an index-sized integer")),
604 )
605}
606
607fn repeat(value: &Object, count: usize) -> Result<Option<Object>> {
609 let repeated = match value {
610 Object::Str(text) => {
611 let points: Vec<u32> = text.code_points().collect();
612 room(points.len(), count, size_of::<char>())?;
613 let mut buf = StrBuf::new();
614 for _ in 0..count {
615 for point in &points {
616 buf.push_code_point(*point);
617 }
618 }
619 Object::Str(Rc::new(buf.finish()))
620 }
621 Object::Bytes(bytes) => {
622 room(bytes.len(), count, 1)?;
623 Object::Bytes(bytes.repeat(count).into())
624 }
625 Object::Tuple(items) => {
626 room(items.len(), count, size_of::<Object>())?;
627 Object::tuple(repeated_elements(items, count))
628 }
629 Object::List(items) => {
630 let items = items.borrow();
631 room(items.len(), count, size_of::<Object>())?;
632 Object::list(repeated_elements(&items, count))
633 }
634 _ => return Ok(None),
635 };
636 Ok(Some(repeated))
637}
638
639fn repeated_elements(items: &[Object], count: usize) -> Vec<Object> {
641 let mut repeated = Vec::with_capacity(items.len().saturating_mul(count));
642 for _ in 0..count {
643 repeated.extend(items.iter().cloned());
644 }
645 repeated
646}
647
648fn room(len: usize, count: usize, element: usize) -> Result<()> {
650 let bytes = u64::try_from(len)
651 .ok()
652 .and_then(|len| len.checked_mul(u64::try_from(count).ok()?))
653 .and_then(|total| total.checked_mul(u64::try_from(element).ok()?));
654 match bytes {
655 Some(bytes) if bytes <= REPEAT_LIMIT => Ok(()),
656 _ => Err(Error::new(Kind::MemoryError, "")),
657 }
658}
659
660fn order(op: Compare, left: &Object, right: &Object) -> Result<bool> {
662 if let (Some(a), Some(b)) = (number(left), number(right)) {
663 return Ok(numeric_order(a, b).is_some_and(|ordering| op.decide(ordering)));
665 }
666 match (left, right) {
667 (Object::Str(a), Object::Str(b)) => Ok(op.decide(a.code_points().cmp(b.code_points()))),
668 (Object::Bytes(a), Object::Bytes(b)) => Ok(op.decide(a.cmp(b))),
669 (Object::Tuple(a), Object::Tuple(b)) => sequence_order(op, a, b),
670 (Object::List(a), Object::List(b)) => sequence_order(op, &a.borrow(), &b.borrow()),
671 (Object::Set(a), Object::Set(b)) => {
672 let (a, b) = (a.borrow(), b.borrow());
675 let subset = a.len() <= b.len() && a.iter().all(|key| b.contains(key));
676 let superset = b.len() <= a.len() && b.iter().all(|key| a.contains(key));
677 Ok(match op {
678 Compare::Lt => subset && !superset,
679 Compare::Le => subset,
680 Compare::Gt => superset && !subset,
681 Compare::Ge => superset,
682 Compare::Eq | Compare::Ne => unreachable!("equality never reaches here"),
683 })
684 }
685 _ => Err(Error::type_error(format!(
686 "'{}' not supported between instances of '{}' and '{}'",
687 op.symbol(),
688 left.type_name(),
689 right.type_name()
690 ))),
691 }
692}
693
694fn sequence_order(op: Compare, left: &[Object], right: &[Object]) -> Result<bool> {
702 for (a, b) in left.iter().zip(right) {
703 if !a.same_value(b) {
704 return order(op, a, b);
705 }
706 }
707 Ok(op.decide(left.len().cmp(&right.len())))
708}
709
710fn numeric_order(left: Num<'_>, right: Num<'_>) -> Option<Ordering> {
716 match (left, right) {
717 (Num::Int(a), Num::Int(b)) => Some(a.cmp(b)),
718 (Num::Float(a), Num::Float(b)) => a.partial_cmp(&b),
719 (Num::Int(a), Num::Float(b)) => int_cmp_float(a, b),
720 (Num::Float(a), Num::Int(b)) => int_cmp_float(b, a).map(Ordering::reverse),
721 }
722}
723
724#[expect(
727 clippy::cast_possible_truncation,
728 reason = "the cast is guarded by the range check above it, and the float is \
729 known to be integral there, so it is exact"
730)]
731fn int_cmp_float(int: &Int, float: f64) -> Option<Ordering> {
732 if float.is_nan() {
733 return None;
734 }
735 if float.is_infinite() {
736 return Some(if float > 0.0 {
737 Ordering::Less
738 } else {
739 Ordering::Greater
740 });
741 }
742 let whole = float.trunc();
743 let fraction = zero_cmp(float - whole);
744 if let Int::Small(value) = int
745 && (-9_223_372_036_854_775_808.0..9_223_372_036_854_775_808.0).contains(&whole)
746 {
747 return Some(value.cmp(&(whole as i64)).then(fraction));
748 }
749 let whole = BigInt::from_f64(whole).expect("a finite truncated float is an integer");
750 Some(int.to_big().cmp(&whole).then(fraction))
751}
752
753fn zero_cmp(fraction: f64) -> Ordering {
756 if fraction > 0.0 {
757 Ordering::Less
758 } else if fraction < 0.0 {
759 Ordering::Greater
760 } else {
761 Ordering::Equal
762 }
763}
764
765fn substring(haystack: &Str, needle: &Str) -> bool {
767 if let (Str::Utf8(haystack), Str::Utf8(needle)) = (haystack, needle) {
768 return haystack.contains(needle.as_ref());
769 }
770 let haystack: Vec<u32> = haystack.code_points().collect();
773 let needle: Vec<u32> = needle.code_points().collect();
774 subslice(&haystack, &needle)
775}
776
777fn subslice<T: PartialEq>(haystack: &[T], needle: &[T]) -> bool {
779 needle.is_empty()
782 || (needle.len() <= haystack.len()
783 && haystack.windows(needle.len()).any(|run| run == needle))
784}
785
786pub fn key(value: &Object, role: &str) -> Result<Key> {
801 Key::new(value.clone()).map_err(|unhashable| {
802 Error::type_error(format!(
803 "cannot use '{}' as a {role} ({})",
804 value.type_name(),
805 unhashable.message()
806 ))
807 })
808}
809
810fn divide_by_zero() -> Error {
812 Error::zero_division("division by zero")
813}
814
815fn unsupported(symbol: &str, left: &Object, right: &Object) -> Error {
818 Error::type_error(format!(
819 "unsupported operand type(s) for {symbol}: '{}' and '{}'",
820 left.type_name(),
821 right.type_name()
822 ))
823}
824
825fn concat_error(left: &Object, right: &Object) -> Error {
829 let named = |kind| {
830 Error::type_error(format!(
831 "can only concatenate {kind} (not \"{}\") to {kind}",
832 right.type_name()
833 ))
834 };
835 match left {
836 Object::Str(_) => named("str"),
837 Object::List(_) => named("list"),
838 Object::Tuple(_) => named("tuple"),
839 Object::Bytes(_) => {
840 Error::type_error(format!("can't concat {} to bytes", right.type_name()))
841 }
842 _ => unsupported("+", left, right),
843 }
844}
845
846fn repeat_error(left: &Object, right: &Object) -> Error {
849 let sequence = |value: &Object| {
850 matches!(
851 value,
852 Object::Str(_) | Object::Bytes(_) | Object::Tuple(_) | Object::List(_)
853 )
854 };
855 let culprit = if sequence(right) {
858 Some(left)
859 } else if sequence(left) {
860 Some(right)
861 } else {
862 None
863 };
864 match culprit {
865 Some(culprit) => Error::type_error(format!(
866 "can't multiply sequence by non-int of type '{}'",
867 culprit.type_name()
868 )),
869 None => unsupported("*", left, right),
870 }
871}
872
873fn bad_unary(symbol: &str, value: &Object) -> Error {
875 Error::type_error(format!(
876 "bad operand type for unary {symbol}: '{}'",
877 value.type_name()
878 ))
879}
880
881#[cfg(test)]
882mod tests {
883 use super::*;
884
885 fn i(value: i64) -> Object {
886 Object::int(value)
887 }
888
889 fn two_to(power: i64) -> Object {
890 Object::Int(
891 Int::Small(2)
892 .pow(&Int::Small(power))
893 .expect("a power this size fits"),
894 )
895 }
896
897 fn f(value: f64) -> Object {
898 Object::Float(value)
899 }
900
901 fn s(value: &str) -> Object {
902 Object::str(value)
903 }
904
905 fn y(value: &[u8]) -> Object {
906 Object::Bytes(value.into())
907 }
908
909 fn t(items: Vec<Object>) -> Object {
910 Object::tuple(items)
911 }
912
913 fn l(items: Vec<Object>) -> Object {
914 Object::list(items)
915 }
916
917 fn set(items: Vec<Object>) -> Object {
918 Object::set(
919 items
920 .into_iter()
921 .map(|item| Key::new(item).expect("a hashable member"))
922 .collect(),
923 )
924 }
925
926 fn dict(pairs: Vec<(Object, Object)>) -> Object {
927 Object::dict(
928 pairs
929 .into_iter()
930 .map(|(key, value)| (Key::new(key).expect("a hashable key"), value))
931 .collect(),
932 )
933 }
934
935 fn wide(points: &[u32]) -> Object {
938 let mut buf = StrBuf::new();
939 for point in points {
940 buf.push_code_point(*point);
941 }
942 Object::Str(Rc::new(buf.finish()))
943 }
944
945 fn ok(result: Result<Object>) -> String {
947 result.expect("an answer").repr()
948 }
949
950 fn bad(result: Result<Object>) -> String {
952 result.expect_err("an exception").to_string()
953 }
954
955 #[test]
956 fn numbers_add_across_their_types() {
957 assert_eq!(ok(add(&i(1), &i(2))), "3");
958 assert_eq!(ok(add(&Object::Bool(true), &Object::Bool(true))), "2");
959 assert_eq!(ok(add(&i(1), &f(0.5))), "1.5");
960 assert_eq!(ok(add(&f(0.5), &Object::Bool(true))), "1.5");
961 }
962
963 #[test]
964 fn sequences_join_only_with_their_own_kind() {
965 assert_eq!(ok(add(&s("ab"), &s("cd"))), "'abcd'");
966 assert_eq!(ok(add(&y(b"ab"), &y(b"cd"))), "b'abcd'");
967 assert_eq!(ok(add(&t(vec![i(1)]), &t(vec![i(2)]))), "(1, 2)");
968 assert_eq!(ok(add(&l(vec![i(1)]), &l(vec![i(2)]))), "[1, 2]");
969 }
970
971 #[test]
974 fn a_list_added_to_itself_is_it_twice_over() {
975 let items = l(vec![i(1)]);
976 assert_eq!(ok(add(&items, &items)), "[1, 1]");
977 }
978
979 #[test]
980 fn a_bad_addition_says_which_operand_it_is_about() {
981 assert_eq!(
982 bad(add(&i(1), &s("a"))),
983 "TypeError: unsupported operand type(s) for +: 'int' and 'str'"
984 );
985 assert_eq!(
986 bad(add(&s("a"), &i(1))),
987 "TypeError: can only concatenate str (not \"int\") to str"
988 );
989 assert_eq!(
990 bad(add(&s("a"), &y(b"b"))),
991 "TypeError: can only concatenate str (not \"bytes\") to str"
992 );
993 assert_eq!(
994 bad(add(&l(vec![i(1)]), &t(vec![i(2)]))),
995 "TypeError: can only concatenate list (not \"tuple\") to list"
996 );
997 assert_eq!(
998 bad(add(&t(vec![i(1)]), &l(vec![i(2)]))),
999 "TypeError: can only concatenate tuple (not \"list\") to tuple"
1000 );
1001 assert_eq!(
1002 bad(add(&y(b"a"), &s("a"))),
1003 "TypeError: can't concat str to bytes"
1004 );
1005 assert_eq!(
1006 bad(add(&y(b"a"), &i(1))),
1007 "TypeError: can't concat int to bytes"
1008 );
1009 assert_eq!(
1010 bad(add(&i(1), &l(vec![]))),
1011 "TypeError: unsupported operand type(s) for +: 'int' and 'list'"
1012 );
1013 assert_eq!(
1014 bad(add(&set(vec![i(1)]), &set(vec![i(2)]))),
1015 "TypeError: unsupported operand type(s) for +: 'set' and 'set'"
1016 );
1017 }
1018
1019 #[test]
1020 fn an_integer_too_large_for_a_float_says_so_rather_than_rounding() {
1021 let huge = two_to(2000);
1022 for result in [
1023 add(&huge, &f(1.0)),
1024 mul(&huge, &f(1.0)),
1025 floor_div(&huge, &f(1.0)),
1026 div_mod(&huge, &f(1.0)),
1027 pow(&huge, &f(0.5)),
1028 ] {
1029 assert_eq!(
1030 bad(result),
1031 "OverflowError: int too large to convert to float"
1032 );
1033 }
1034 }
1035
1036 #[test]
1039 fn a_comparison_against_a_float_stays_exact_however_large_the_integer() {
1040 let huge = two_to(2000);
1041 assert_eq!(ok(compare(Compare::Lt, &huge, &f(1.0))), "False");
1042 assert_eq!(ok(compare(Compare::Eq, &huge, &f(1.0))), "False");
1043 assert_eq!(ok(compare(Compare::Gt, &huge, &f(1e308))), "True");
1044 assert_eq!(ok(compare(Compare::Lt, &i(1), &f(1.5))), "True");
1045 assert_eq!(ok(compare(Compare::Gt, &i(2), &f(1.5))), "True");
1046 assert_eq!(ok(compare(Compare::Lt, &i(-2), &f(-1.5))), "True");
1047 assert_eq!(ok(compare(Compare::Lt, &i(1), &f(f64::INFINITY))), "True");
1048 assert_eq!(
1049 ok(compare(Compare::Gt, &huge, &f(f64::NEG_INFINITY))),
1050 "True"
1051 );
1052 }
1053
1054 #[test]
1055 fn a_sequence_repeats_by_an_integer_from_either_side() {
1056 assert_eq!(ok(mul(&s("ab"), &i(3))), "'ababab'");
1057 assert_eq!(ok(mul(&i(3), &s("ab"))), "'ababab'");
1058 assert_eq!(ok(mul(&Object::Bool(true), &s("ab"))), "'ab'");
1059 assert_eq!(ok(mul(&y(b"ab"), &i(2))), "b'abab'");
1060 assert_eq!(ok(mul(&t(vec![i(1)]), &i(3))), "(1, 1, 1)");
1061 assert_eq!(ok(mul(&i(3), &l(vec![i(0)]))), "[0, 0, 0]");
1062 assert_eq!(ok(mul(&wide(&[0xD800]), &i(2))), r"'\ud800\ud800'");
1063 }
1064
1065 #[test]
1068 fn a_count_below_one_gives_an_empty_sequence_rather_than_an_error() {
1069 assert_eq!(ok(mul(&s("a"), &i(-1))), "''");
1070 assert_eq!(ok(mul(&s("a"), &i(0))), "''");
1071 assert_eq!(ok(mul(&l(vec![i(1)]), &i(-1))), "[]");
1072 }
1073
1074 #[test]
1075 fn a_count_that_is_not_an_integer_names_itself() {
1076 assert_eq!(
1077 bad(mul(&s("a"), &f(1.5))),
1078 "TypeError: can't multiply sequence by non-int of type 'float'"
1079 );
1080 assert_eq!(
1081 bad(mul(&f(1.5), &s("a"))),
1082 "TypeError: can't multiply sequence by non-int of type 'float'"
1083 );
1084 assert_eq!(
1085 bad(mul(&Object::None, &s("a"))),
1086 "TypeError: can't multiply sequence by non-int of type 'NoneType'"
1087 );
1088 assert_eq!(
1089 bad(mul(&s("a"), &Object::None)),
1090 "TypeError: can't multiply sequence by non-int of type 'NoneType'"
1091 );
1092 assert_eq!(
1093 bad(mul(&set(vec![i(1)]), &i(2))),
1094 "TypeError: unsupported operand type(s) for *: 'set' and 'int'"
1095 );
1096 assert_eq!(
1097 bad(mul(&Object::None, &Object::None)),
1098 "TypeError: unsupported operand type(s) for *: 'NoneType' and 'NoneType'"
1099 );
1100 }
1101
1102 #[test]
1103 fn a_repetition_no_machine_could_hold_is_refused_before_it_is_attempted() {
1104 assert_eq!(
1105 bad(mul(&s("a"), &two_to(63))),
1106 "OverflowError: cannot fit 'int' into an index-sized integer"
1107 );
1108 assert_eq!(
1109 bad(mul(&s("a"), &i(1_000_000_000_000_000_000))),
1110 "MemoryError"
1111 );
1112 assert_eq!(
1113 bad(mul(&l(vec![i(1)]), &i(1_000_000_000_000_000_000))),
1114 "MemoryError"
1115 );
1116 }
1117
1118 #[test]
1119 fn dividing_gives_a_float_however_the_operands_are_spelled() {
1120 assert_eq!(ok(true_div(&i(1), &i(2))), "0.5");
1121 assert_eq!(ok(true_div(&i(4), &i(2))), "2.0");
1122 assert_eq!(ok(true_div(&f(1.0), &i(2))), "0.5");
1123 }
1124
1125 #[test]
1126 fn every_divisor_of_zero_raises_the_same_thing() {
1127 for result in [
1128 true_div(&i(1), &i(0)),
1129 floor_div(&i(1), &i(0)),
1130 modulo(&i(1), &i(0)),
1131 div_mod(&i(1), &i(0)),
1132 true_div(&f(1.0), &i(0)),
1133 floor_div(&f(1.0), &i(0)),
1134 modulo(&f(1.0), &i(0)),
1135 div_mod(&f(7.0), &i(0)),
1136 true_div(&f(1.0), &f(-0.0)),
1137 ] {
1138 assert_eq!(bad(result), "ZeroDivisionError: division by zero");
1139 }
1140 }
1141
1142 #[test]
1143 fn a_quotient_with_no_float_to_land_on_says_so() {
1144 assert_eq!(
1145 bad(true_div(&two_to(2000), &i(1))),
1146 "OverflowError: integer division result too large for a float"
1147 );
1148 assert_eq!(ok(true_div(&i(1), &two_to(2000))), "0.0");
1149 }
1150
1151 #[test]
1152 fn flooring_goes_down_and_the_remainder_takes_the_divisors_sign() {
1153 assert_eq!(ok(floor_div(&i(7), &i(-3))), "-3");
1154 assert_eq!(ok(modulo(&i(7), &i(-3))), "-2");
1155 assert_eq!(ok(modulo(&i(-7), &i(3))), "2");
1156 assert_eq!(ok(div_mod(&i(7), &i(-3))), "(-3, -2)");
1157 assert_eq!(ok(floor_div(&f(7.0), &f(-2.0))), "-4.0");
1158 assert_eq!(ok(modulo(&f(-5.5), &f(2.0))), "0.5");
1159 assert_eq!(ok(modulo(&f(5.5), &f(-2.0))), "-0.5");
1160 assert_eq!(ok(div_mod(&f(-7.0), &f(-2.0))), "(3.0, -1.0)");
1161 }
1162
1163 #[test]
1166 fn a_float_quotient_keeps_the_bits_the_division_would_have_lost() {
1167 assert_eq!(ok(floor_div(&f(7.0), &f(0.5))), "14.0");
1168 assert_eq!(ok(floor_div(&f(1e308), &f(1e-10))), "inf");
1169 }
1170
1171 #[test]
1172 fn a_zero_quotient_and_a_zero_remainder_each_keep_a_sign() {
1173 assert_eq!(ok(floor_div(&f(-0.0), &f(1.0))), "-0.0");
1174 assert_eq!(ok(floor_div(&f(0.0), &f(-1.0))), "-0.0");
1175 assert_eq!(ok(modulo(&f(4.0), &f(-2.0))), "-0.0");
1176 }
1177
1178 #[test]
1179 fn raising_to_a_power_leaves_the_integers_when_the_exponent_is_negative() {
1180 assert_eq!(ok(pow(&i(2), &i(10))), "1024");
1181 assert_eq!(ok(pow(&i(0), &i(0))), "1");
1182 assert_eq!(ok(pow(&i(2), &i(-2))), "0.25");
1183 assert_eq!(ok(pow(&i(-2), &i(-1))), "-0.5");
1184 assert_eq!(ok(pow(&Object::Bool(true), &i(-1))), "1.0");
1185 assert_eq!(ok(pow(&i(2), &f(0.5))), "1.4142135623730951");
1186 assert_eq!(ok(pow(&f(0.0), &i(0))), "1.0");
1187 assert_eq!(ok(pow(&i(1), &f(f64::INFINITY))), "1.0");
1188 }
1189
1190 #[test]
1191 fn zero_to_a_negative_power_is_its_own_exception() {
1192 for result in [
1193 pow(&i(0), &i(-1)),
1194 pow(&f(0.0), &f(-1.0)),
1195 pow(&f(-0.0), &i(-1)),
1196 ] {
1197 assert_eq!(bad(result), "ZeroDivisionError: zero to a negative power");
1198 }
1199 }
1200
1201 #[test]
1202 fn a_power_that_runs_off_the_top_of_a_double_reports_what_the_c_library_said() {
1203 assert_eq!(
1204 bad(pow(&f(2.0), &i(10000))),
1205 "OverflowError: (34, 'Result too large')"
1206 );
1207 assert_eq!(
1208 bad(pow(&f(1e300), &i(2))),
1209 "OverflowError: (34, 'Result too large')"
1210 );
1211 assert_eq!(ok(pow(&f(f64::INFINITY), &i(2))), "inf");
1212 }
1213
1214 #[test]
1215 fn a_negative_base_to_a_fractional_power_needs_complex_numbers() {
1216 assert_eq!(
1217 bad(pow(&i(-2), &f(0.5))),
1218 "NotImplementedError: a negative number raised to a fractional power is a \
1219 complex number, and complex numbers are not implemented yet"
1220 );
1221 assert_eq!(ok(pow(&f(-1.0), &f(2.0))), "1.0");
1222 }
1223
1224 #[test]
1225 fn a_bad_power_names_both_of_its_spellings() {
1226 assert_eq!(
1227 bad(pow(&i(1), &s("a"))),
1228 "TypeError: unsupported operand type(s) for ** or pow(): 'int' and 'str'"
1229 );
1230 }
1231
1232 #[test]
1233 fn shifting_needs_a_count_that_is_not_negative() {
1234 assert_eq!(
1235 ok(lshift(&i(1), &i(100))),
1236 "1267650600228229401496703205376"
1237 );
1238 assert_eq!(ok(rshift(&i(-1), &i(100))), "-1");
1239 assert_eq!(ok(rshift(&i(1), &i(1_000_000))), "0");
1240 assert_eq!(ok(lshift(&Object::Bool(true), &i(1))), "2");
1241 assert_eq!(
1242 bad(lshift(&i(1), &i(-1))),
1243 "ValueError: negative shift count"
1244 );
1245 assert_eq!(
1246 bad(rshift(&i(1), &i(-1))),
1247 "ValueError: negative shift count"
1248 );
1249 assert_eq!(
1250 bad(lshift(&i(1), &i(1_000_000_000_000_000_000))),
1251 "MemoryError"
1252 );
1253 assert_eq!(
1254 bad(lshift(&i(1), &f(1.0))),
1255 "TypeError: unsupported operand type(s) for <<: 'int' and 'float'"
1256 );
1257 }
1258
1259 #[test]
1262 fn two_bools_give_a_bool_and_anything_else_gives_an_int() {
1263 assert_eq!(
1264 ok(bit_and(&Object::Bool(true), &Object::Bool(true))),
1265 "True"
1266 );
1267 assert_eq!(
1268 ok(bit_or(&Object::Bool(true), &Object::Bool(false))),
1269 "True"
1270 );
1271 assert_eq!(
1272 ok(bit_xor(&Object::Bool(true), &Object::Bool(true))),
1273 "False"
1274 );
1275 assert_eq!(ok(bit_and(&Object::Bool(true), &i(1))), "1");
1276 assert_eq!(ok(bit_and(&i(6), &i(3))), "2");
1277 assert_eq!(ok(rshift(&Object::Bool(true), &Object::Bool(true))), "0");
1278 }
1279
1280 #[test]
1281 fn the_bitwise_operators_are_the_set_operators_too() {
1282 let a = set(vec![i(1), i(2)]);
1283 assert_eq!(ok(sub(&a, &set(vec![i(2)]))), "{1}");
1284 assert_eq!(ok(bit_or(&a, &set(vec![i(3)]))), "{1, 2, 3}");
1285 assert_eq!(ok(bit_and(&a, &set(vec![i(2)]))), "{2}");
1286 assert_eq!(ok(bit_xor(&a, &set(vec![i(2)]))), "{1}");
1287 assert_eq!(ok(sub(&set(vec![i(1)]), &set(vec![f(1.0)]))), "set()");
1290 assert_eq!(ok(bit_or(&set(vec![i(1)]), &set(vec![f(1.0)]))), "{1}");
1291 assert_eq!(
1292 bad(bit_or(&a, &l(vec![i(1)]))),
1293 "TypeError: unsupported operand type(s) for |: 'set' and 'list'"
1294 );
1295 assert_eq!(
1296 bad(sub(&a, &l(vec![i(1)]))),
1297 "TypeError: unsupported operand type(s) for -: 'set' and 'list'"
1298 );
1299 }
1300
1301 #[test]
1302 fn the_unary_operators_widen_a_bool_to_the_integer_it_is() {
1303 assert_eq!(ok(neg(&Object::Bool(true))), "-1");
1304 assert_eq!(ok(pos(&Object::Bool(true))), "1");
1305 assert_eq!(ok(invert(&Object::Bool(true))), "-2");
1306 assert_eq!(ok(neg(&f(1.5))), "-1.5");
1307 assert_eq!(ok(invert(&i(1))), "-2");
1308 assert_eq!(
1309 bad(invert(&f(1.5))),
1310 "TypeError: bad operand type for unary ~: 'float'"
1311 );
1312 assert_eq!(
1313 bad(pos(&s("a"))),
1314 "TypeError: bad operand type for unary +: 'str'"
1315 );
1316 assert_eq!(
1317 bad(neg(&Object::None)),
1318 "TypeError: bad operand type for unary -: 'NoneType'"
1319 );
1320 }
1321
1322 #[test]
1323 fn abs_drops_the_sign_and_the_bool_with_it() {
1324 assert_eq!(ok(abs(&i(-3))), "3");
1325 assert_eq!(ok(abs(&i(3))), "3");
1326 assert_eq!(ok(abs(&Object::Bool(true))), "1");
1327 assert_eq!(ok(abs(&f(-1.5))), "1.5");
1328 assert_eq!(ok(abs(&f(-0.0))), "0.0");
1331 assert_eq!(
1334 bad(abs(&s("a"))),
1335 "TypeError: bad operand type for abs(): 'str'"
1336 );
1337 }
1338
1339 #[test]
1340 fn not_answers_for_every_object() {
1341 assert_eq!(not(&s("a")).repr(), "False");
1342 assert_eq!(not(&l(vec![])).repr(), "True");
1343 assert_eq!(not(&Object::None).repr(), "True");
1344 assert_eq!(not(&Object::Ellipsis).repr(), "False");
1345 }
1346
1347 #[test]
1348 fn numbers_compare_across_their_types() {
1349 assert_eq!(ok(compare(Compare::Lt, &Object::Bool(true), &i(2))), "True");
1350 assert_eq!(ok(compare(Compare::Le, &i(1), &f(1.0))), "True");
1351 assert_eq!(ok(compare(Compare::Eq, &f(0.0), &f(-0.0))), "True");
1352 assert_eq!(ok(compare(Compare::Gt, &f(1.5), &i(1))), "True");
1353 assert_eq!(ok(compare(Compare::Ne, &i(1), &f(1.0))), "False");
1354 }
1355
1356 #[test]
1357 fn a_nan_is_on_neither_side_of_anything() {
1358 let nan = f(f64::NAN);
1359 for op in [
1360 Compare::Lt,
1361 Compare::Le,
1362 Compare::Gt,
1363 Compare::Ge,
1364 Compare::Eq,
1365 ] {
1366 assert_eq!(ok(compare(op, &nan, &i(1))), "False");
1367 assert_eq!(ok(compare(op, &nan, &nan)), "False");
1368 }
1369 assert_eq!(ok(compare(Compare::Ne, &nan, &nan)), "True");
1370 }
1371
1372 #[test]
1373 fn a_sequence_compares_at_the_first_place_it_differs() {
1374 assert_eq!(
1375 ok(compare(
1376 Compare::Lt,
1377 &l(vec![i(1), i(2)]),
1378 &l(vec![i(1), i(2), i(3)])
1379 )),
1380 "True"
1381 );
1382 assert_eq!(ok(compare(Compare::Lt, &t(vec![]), &t(vec![i(1)]))), "True");
1383 assert_eq!(ok(compare(Compare::Lt, &s("abc"), &s("abd"))), "True");
1384 assert_eq!(ok(compare(Compare::Lt, &s("Z"), &s("a"))), "True");
1385 assert_eq!(ok(compare(Compare::Lt, &y(&[0]), &y(&[1]))), "True");
1386 assert_eq!(
1387 ok(compare(
1388 Compare::Lt,
1389 &t(vec![i(1), s("a")]),
1390 &t(vec![i(2), s("a")])
1391 )),
1392 "True"
1393 );
1394 assert_eq!(
1397 bad(compare(
1398 Compare::Lt,
1399 &t(vec![i(1), s("a")]),
1400 &t(vec![i(1), i(2)])
1401 )),
1402 "TypeError: '<' not supported between instances of 'str' and 'int'"
1403 );
1404 }
1405
1406 #[test]
1410 fn a_sequence_checks_identity_first_and_a_nan_shows_it() {
1411 let nan = f(f64::NAN);
1412 assert_eq!(
1413 ok(compare(
1414 Compare::Eq,
1415 &t(vec![nan.clone()]),
1416 &t(vec![nan.clone()])
1417 )),
1418 "True"
1419 );
1420 assert_eq!(
1421 ok(compare(
1422 Compare::Lt,
1423 &t(vec![nan.clone()]),
1424 &t(vec![nan.clone()])
1425 )),
1426 "False"
1427 );
1428 assert_eq!(
1429 ok(compare(
1430 Compare::Le,
1431 &t(vec![nan.clone()]),
1432 &t(vec![nan.clone()])
1433 )),
1434 "True"
1435 );
1436 assert_eq!(
1437 ok(compare(
1438 Compare::Lt,
1439 &t(vec![i(1), nan]),
1440 &t(vec![i(1), i(2)])
1441 )),
1442 "False"
1443 );
1444 }
1445
1446 #[test]
1447 fn a_set_is_ordered_by_containment_rather_than_by_size() {
1448 assert_eq!(
1449 ok(compare(
1450 Compare::Lt,
1451 &set(vec![i(1)]),
1452 &set(vec![i(1), i(2)])
1453 )),
1454 "True"
1455 );
1456 assert_eq!(
1457 ok(compare(Compare::Lt, &set(vec![i(1)]), &set(vec![i(2)]))),
1458 "False"
1459 );
1460 assert_eq!(
1461 ok(compare(Compare::Gt, &set(vec![i(1)]), &set(vec![i(2)]))),
1462 "False"
1463 );
1464 assert_eq!(
1465 ok(compare(Compare::Le, &set(vec![i(1)]), &set(vec![i(1)]))),
1466 "True"
1467 );
1468 assert_eq!(
1469 ok(compare(
1470 Compare::Gt,
1471 &set(vec![i(1), i(2)]),
1472 &set(vec![i(1)])
1473 )),
1474 "True"
1475 );
1476 }
1477
1478 #[test]
1479 fn a_pair_with_no_order_says_so_and_still_answers_equality() {
1480 assert_eq!(
1481 bad(compare(Compare::Lt, &i(1), &s("a"))),
1482 "TypeError: '<' not supported between instances of 'int' and 'str'"
1483 );
1484 assert_eq!(
1485 bad(compare(Compare::Le, &i(1), &s("a"))),
1486 "TypeError: '<=' not supported between instances of 'int' and 'str'"
1487 );
1488 assert_eq!(
1489 bad(compare(Compare::Lt, &Object::None, &Object::None)),
1490 "TypeError: '<' not supported between instances of 'NoneType' and 'NoneType'"
1491 );
1492 assert_eq!(
1493 bad(compare(Compare::Lt, &l(vec![i(1)]), &t(vec![i(1)]))),
1494 "TypeError: '<' not supported between instances of 'list' and 'tuple'"
1495 );
1496 assert_eq!(
1497 bad(compare(Compare::Lt, &s("a"), &y(b"a"))),
1498 "TypeError: '<' not supported between instances of 'str' and 'bytes'"
1499 );
1500 assert_eq!(
1501 bad(compare(
1502 Compare::Lt,
1503 &dict(vec![(i(1), i(2))]),
1504 &dict(vec![(i(1), i(3))])
1505 )),
1506 "TypeError: '<' not supported between instances of 'dict' and 'dict'"
1507 );
1508 assert_eq!(
1509 ok(compare(Compare::Eq, &Object::None, &Object::None)),
1510 "True"
1511 );
1512 assert_eq!(ok(compare(Compare::Ne, &i(1), &s("a"))), "True");
1513 }
1514
1515 #[test]
1516 fn a_string_contains_strings_and_nothing_else() {
1517 assert_eq!(ok(contains(&s("xaby"), &s("ab"))), "True");
1518 assert_eq!(ok(contains(&s("abc"), &s(""))), "True");
1519 assert_eq!(ok(contains(&s("abc"), &s("d"))), "False");
1520 assert_eq!(
1521 bad(contains(&s("abc"), &i(1))),
1522 "TypeError: 'in <string>' requires string as left operand, not int"
1523 );
1524 }
1525
1526 #[test]
1529 fn a_substring_search_works_on_a_string_that_has_no_utf8() {
1530 let text = wide(&[u32::from('a'), 0xD800, u32::from('b')]);
1531 assert_eq!(ok(contains(&text, &wide(&[0xD800]))), "True");
1532 assert_eq!(ok(contains(&text, &s("ab"))), "False");
1533 assert_eq!(ok(contains(&text, &s("b"))), "True");
1534 }
1535
1536 #[test]
1537 fn a_bytes_contains_runs_of_bytes_and_single_byte_values() {
1538 assert_eq!(ok(contains(&y(b"abc"), &y(b"ab"))), "True");
1539 assert_eq!(ok(contains(&y(b"abc"), &y(b"x"))), "False");
1540 assert_eq!(ok(contains(&y(b"abc"), &i(i64::from(b'a')))), "True");
1541 assert_eq!(ok(contains(&y(b"abc"), &i(1))), "False");
1542 assert_eq!(
1543 bad(contains(&y(b"abc"), &i(256))),
1544 "ValueError: byte must be in range(0, 256)"
1545 );
1546 assert_eq!(
1547 bad(contains(&y(b"abc"), &i(-1))),
1548 "ValueError: byte must be in range(0, 256)"
1549 );
1550 assert_eq!(
1551 bad(contains(&y(b"abc"), &s("a"))),
1552 "TypeError: a bytes-like object is required, not 'str'"
1553 );
1554 }
1555
1556 #[test]
1557 fn a_lookup_by_an_unhashable_key_names_what_it_was_being_used_as() {
1558 assert_eq!(
1559 bad(contains(&set(vec![i(1)]), &l(vec![]))),
1560 "TypeError: cannot use 'list' as a set element (unhashable type: 'list')"
1561 );
1562 assert_eq!(
1563 bad(contains(&dict(vec![(i(1), i(2))]), &l(vec![]))),
1564 "TypeError: cannot use 'list' as a dict key (unhashable type: 'list')"
1565 );
1566 assert_eq!(
1569 bad(contains(
1570 &dict(vec![(i(1), i(2))]),
1571 &t(vec![l(vec![]), i(1)])
1572 )),
1573 "TypeError: cannot use 'tuple' as a dict key (unhashable type: 'list')"
1574 );
1575 assert_eq!(
1576 bad(contains(&set(vec![i(1)]), &t(vec![l(vec![]), i(1)]))),
1577 "TypeError: cannot use 'tuple' as a set element (unhashable type: 'list')"
1578 );
1579 }
1580
1581 #[test]
1582 fn a_container_is_searched_by_value_and_everything_else_is_not_a_container() {
1583 assert_eq!(ok(contains(&t(vec![i(1), i(2)]), &i(1))), "True");
1584 assert_eq!(
1585 ok(contains(&l(vec![l(vec![i(1)])]), &l(vec![i(1)]))),
1586 "True"
1587 );
1588 assert_eq!(ok(contains(&dict(vec![(i(1), i(2))]), &f(1.0))), "True");
1589 assert_eq!(ok(contains(&dict(vec![]), &s("a"))), "False");
1590 assert_eq!(ok(contains(&set(vec![s("a")]), &s("a"))), "True");
1591 assert_eq!(
1592 bad(contains(&Object::None, &i(1))),
1593 "TypeError: argument of type 'NoneType' is not a container or iterable"
1594 );
1595 assert_eq!(
1596 bad(contains(&i(2), &i(1))),
1597 "TypeError: argument of type 'int' is not a container or iterable"
1598 );
1599 }
1600}
1601
1602pub fn get_item(container: &Object, index: &Object) -> Result<Object> {
1609 match container {
1610 Object::List(items) => {
1611 match subscript(index, items.borrow().len(), Seq::List, Write::No)? {
1612 Subscript::At(at) => Ok(items.borrow()[at].clone()),
1613 Subscript::Range(range) => {
1614 let items = items.borrow();
1615 Ok(Object::list(
1616 range.offsets().map(|at| items[at].clone()).collect(),
1617 ))
1618 }
1619 }
1620 }
1621 Object::Tuple(items) => match subscript(index, items.len(), Seq::Tuple, Write::No)? {
1622 Subscript::At(at) => Ok(items[at].clone()),
1623 Subscript::Range(range) => Ok(Object::tuple(
1624 range.offsets().map(|at| items[at].clone()).collect(),
1625 )),
1626 },
1627 Object::Str(text) => match subscript(index, text.len(), Seq::Str, Write::No)? {
1628 Subscript::At(at) => {
1631 let mut out = StrBuf::new();
1632 out.push_code_point(text.code_point_at(at).expect("the index was checked"));
1633 Ok(Object::Str(Rc::new(out.finish())))
1634 }
1635 Subscript::Range(range) => {
1636 let points: Vec<u32> = text.code_points().collect();
1640 let mut out = StrBuf::new();
1641 for at in range.offsets() {
1642 out.push_code_point(points[at]);
1643 }
1644 Ok(Object::Str(Rc::new(out.finish())))
1645 }
1646 },
1647 Object::Bytes(bytes) => match subscript(index, bytes.len(), Seq::Bytes, Write::No)? {
1648 Subscript::At(at) => Ok(Object::int(i64::from(bytes[at]))),
1651 Subscript::Range(range) => {
1652 let taken: Vec<u8> = range.offsets().map(|at| bytes[at]).collect();
1653 Ok(Object::Bytes(taken.into()))
1654 }
1655 },
1656 Object::Dict(entries) => {
1657 let key = key(index, "dict key")?;
1658 entries
1659 .borrow()
1660 .get(&key)
1661 .cloned()
1662 .ok_or_else(|| missing_key(index))
1663 }
1664 other => Err(not_subscriptable(other)),
1665 }
1666}
1667
1668pub fn set_item(container: &Object, index: &Object, value: &Object) -> Result<()> {
1675 match container {
1676 Object::List(items) => {
1677 let len = items.borrow().len();
1678 match subscript(index, len, Seq::List, Write::Yes)? {
1679 Subscript::At(at) => {
1680 items.borrow_mut()[at] = value.clone();
1681 Ok(())
1682 }
1683 Subscript::Range(range) => {
1684 let replacement = elements(value).ok_or_else(|| {
1687 Error::type_error("must assign iterable to extended slice")
1688 })?;
1689 let mut items = items.borrow_mut();
1690 if range.is_contiguous() {
1691 let start = range.start.cast_unsigned();
1692 items.splice(start..start + range.len, replacement);
1693 return Ok(());
1694 }
1695 if replacement.len() != range.len {
1696 return Err(Error::value_error(format!(
1697 "attempt to assign sequence of size {} to extended slice of size {}",
1698 replacement.len(),
1699 range.len
1700 )));
1701 }
1702 for (at, value) in range.offsets().zip(replacement) {
1703 items[at] = value;
1704 }
1705 Ok(())
1706 }
1707 }
1708 }
1709 Object::Dict(entries) => {
1710 entries
1711 .borrow_mut()
1712 .insert(key(index, "dict key")?, value.clone());
1713 Ok(())
1714 }
1715 other => Err(Error::type_error(format!(
1719 "'{}' object does not support item assignment",
1720 other.type_name()
1721 ))),
1722 }
1723}
1724
1725pub fn del_item(container: &Object, index: &Object) -> Result<()> {
1732 match container {
1733 Object::List(items) => {
1734 let len = items.borrow().len();
1735 match subscript(index, len, Seq::List, Write::Yes)? {
1736 Subscript::At(at) => {
1737 items.borrow_mut().remove(at);
1738 Ok(())
1739 }
1740 Subscript::Range(range) => {
1741 let mut doomed: Vec<usize> = range.offsets().collect();
1744 doomed.sort_unstable();
1745 let mut items = items.borrow_mut();
1746 for at in doomed.into_iter().rev() {
1747 items.remove(at);
1748 }
1749 Ok(())
1750 }
1751 }
1752 }
1753 Object::Dict(entries) => entries
1754 .borrow_mut()
1755 .remove(&key(index, "dict key")?)
1756 .map(|_| ())
1757 .ok_or_else(|| missing_key(index)),
1758 Object::Tuple(_) | Object::Str(_) | Object::Bytes(_) | Object::Set(_) => {
1762 Err(Error::type_error(format!(
1763 "'{}' object doesn't support item deletion",
1764 container.type_name()
1765 )))
1766 }
1767 other => Err(Error::type_error(format!(
1768 "'{}' object does not support item deletion",
1769 other.type_name()
1770 ))),
1771 }
1772}
1773
1774#[must_use]
1781pub fn len(value: &Object) -> Option<usize> {
1782 Some(match value {
1783 Object::Str(text) => text.len(),
1784 Object::Bytes(bytes) => bytes.len(),
1785 Object::Tuple(items) => items.len(),
1786 Object::List(items) => items.borrow().len(),
1787 Object::Dict(entries) => entries.borrow().len(),
1788 Object::Set(members) => members.borrow().len(),
1789 _ => return None,
1790 })
1791}
1792
1793#[must_use]
1800pub fn elements(value: &Object) -> Option<Vec<Object>> {
1801 match value {
1802 Object::List(items) => Some(items.borrow().clone()),
1805 Object::Tuple(items) => Some(items.to_vec()),
1806 Object::Str(text) => Some(
1807 text.code_points()
1808 .map(|point| {
1809 let mut out = StrBuf::new();
1810 out.push_code_point(point);
1811 Object::Str(Rc::new(out.finish()))
1812 })
1813 .collect(),
1814 ),
1815 Object::Bytes(bytes) => Some(bytes.iter().map(|&b| Object::int(i64::from(b))).collect()),
1817 Object::Dict(entries) => Some(
1819 entries
1820 .borrow()
1821 .iter()
1822 .map(|(key, _)| key.object().clone())
1823 .collect(),
1824 ),
1825 Object::Set(members) => Some(
1826 members
1827 .borrow()
1828 .iter()
1829 .map(|key| key.object().clone())
1830 .collect(),
1831 ),
1832 _ => None,
1833 }
1834}
1835
1836enum Subscript {
1838 At(usize),
1840 Range(Indices),
1842}
1843
1844#[derive(Clone, Copy)]
1846enum Seq {
1847 List,
1848 Tuple,
1849 Str,
1850 Bytes,
1851}
1852
1853impl Seq {
1854 fn not_an_index(self, index: &Object) -> Error {
1860 let name = index.type_name();
1861 Error::type_error(match self {
1862 Seq::List => format!("list indices must be integers or slices, not {name}"),
1863 Seq::Tuple => format!("tuple indices must be integers or slices, not {name}"),
1864 Seq::Bytes => format!("byte indices must be integers or slices, not {name}"),
1865 Seq::Str => format!("string indices must be integers, not '{name}'"),
1866 })
1867 }
1868
1869 fn out_of_range(self, write: Write) -> Error {
1874 Error::new(
1875 Kind::IndexError,
1876 match (self, write) {
1877 (Seq::List, Write::No) => "list index out of range",
1878 (Seq::List, Write::Yes) => "list assignment index out of range",
1879 (Seq::Tuple, _) => "tuple index out of range",
1880 (Seq::Str, _) => "string index out of range",
1881 (Seq::Bytes, _) => "index out of range",
1882 },
1883 )
1884 }
1885}
1886
1887#[derive(Clone, Copy, PartialEq, Eq)]
1890enum Write {
1891 No,
1892 Yes,
1893}
1894
1895fn subscript(index: &Object, len: usize, seq: Seq, write: Write) -> Result<Subscript> {
1897 match index {
1898 Object::Slice(slice) => Ok(Subscript::Range(slice.indices(len)?)),
1899 Object::Bool(_) | Object::Int(_) => {
1900 let Some(Num::Int(at)) = number(index) else {
1901 unreachable!("an int and a bool are both numbers")
1902 };
1903 Ok(Subscript::At(offset(at, len, seq, write)?))
1904 }
1905 other => Err(seq.not_an_index(other)),
1906 }
1907}
1908
1909fn offset(index: &Int, len: usize, seq: Seq, write: Write) -> Result<usize> {
1918 let too_big = || {
1919 Error::new(
1920 Kind::IndexError,
1921 "cannot fit 'int' into an index-sized integer",
1922 )
1923 };
1924 let at = index.to_i64().ok_or_else(too_big)?;
1925 let at = isize::try_from(at).map_err(|_| too_big())?;
1926 let at = if at < 0 {
1927 at.checked_add(len.cast_signed()).ok_or_else(too_big)?
1928 } else {
1929 at
1930 };
1931 if at < 0 || at.cast_unsigned() >= len {
1932 return Err(seq.out_of_range(write));
1933 }
1934 Ok(at.cast_unsigned())
1935}
1936
1937fn missing_key(key: &Object) -> Error {
1944 Error::raised(Kind::KeyError, vec![key.clone()])
1945}
1946
1947fn not_subscriptable(value: &Object) -> Error {
1949 Error::type_error(format!(
1950 "'{}' object is not subscriptable",
1951 value.type_name()
1952 ))
1953}