Skip to main content

kohebi_core/
object.rs

1//! What a value is while a program is running.
2//!
3//! This is not the object model in `docs/spec/03-object-model.md`. That one is
4//! a tagged 64-bit word pointing at heap objects with shapes and a packed
5//! refcount, and it is what the memory target depends on. This is an enum with
6//! `Rc` in it, because M1 is correctness and a shape graph is not a thing to
7//! debug at the same time as the semantics it stores.
8//!
9//! What survives the replacement is the surface. Nothing outside this crate
10//! reaches into a variant: callers ask [`Object::truthy`], [`Object::repr`] and
11//! the rest, so when the representation changes the callers do not.
12//!
13//! ## What a variant is, and what it is not
14//!
15//! `None`, `True` and `False` are values here rather than pointers to
16//! singletons, so `x is None` is a comparison of two enum discriminants. That
17//! happens to be what the tagged representation does too.
18//!
19//! A `str` is a sequence of code points and so is [`Str`], which is the same
20//! type the parser hands out for a literal. A `bytes` is a sequence of bytes,
21//! and the two are never equal to each other however similar they look.
22//!
23//! A tuple is immutable and holds its elements inline behind one `Rc`. A list
24//! is mutable and so is behind an `Rc<RefCell<_>>`, which is where the
25//! placeholder shows most: the real one has a lock bit in the object header and
26//! no cell at all.
27
28use std::borrow::Cow;
29use std::cell::RefCell;
30use std::rc::Rc;
31
32use crate::dict::{Dict, Set};
33use crate::exception::Exception;
34use crate::float::{DotZero, float_repr};
35use crate::hash::int_eq_float;
36use crate::int::Int;
37use crate::native::Native;
38use crate::slice::Slice;
39use crate::text::{Str, bytes_repr};
40
41/// A Python value.
42#[derive(Debug, Clone)]
43pub enum Object {
44    /// `None`.
45    None,
46    /// The answer an operator gives when it does not know how, which is what
47    /// lets Python try the reflected one before giving up.
48    NotImplemented,
49    /// `...`, which is a value as well as a piece of syntax.
50    Ellipsis,
51    /// `True` or `False`, which is an `int` in Python and is kept apart here
52    /// because `repr` and `type` both need to know which one it is.
53    Bool(bool),
54    /// An `int`, of any size.
55    Int(Int),
56    /// A `float`, which is an IEEE double and nothing more.
57    Float(f64),
58    /// A `str`, which is a sequence of code points.
59    Str(Rc<Str>),
60    /// A `bytes`, which is a sequence of bytes and never equal to a `str`.
61    Bytes(Rc<[u8]>),
62    /// A `tuple`, which cannot change and so holds its elements inline.
63    Tuple(Rc<[Object]>),
64    /// A `list`, which can.
65    List(Rc<RefCell<Vec<Object>>>),
66    /// A `dict`, which remembers the order things were put into it.
67    Dict(Rc<RefCell<Dict>>),
68    /// A `set`, which does not.
69    Set(Rc<RefCell<Set>>),
70    /// A `slice`, which is what `a:b:c` inside a subscript builds. It holds
71    /// three objects rather than three integers, because the numbers only have
72    /// to be numbers at the point a sequence uses them.
73    Slice(Rc<Slice>),
74    /// A value whose type is defined above this crate, which is how the runtime
75    /// gets functions, iterators and exceptions without this crate having to
76    /// know what any of those are. See [`Native`].
77    Native(Rc<dyn Native>),
78}
79
80impl Object {
81    /// An integer from a machine word.
82    #[must_use]
83    pub const fn int(value: i64) -> Self {
84        Object::Int(Int::Small(value))
85    }
86
87    /// A string from Rust text.
88    #[must_use]
89    pub fn str(value: impl Into<Str>) -> Self {
90        Object::Str(Rc::new(value.into()))
91    }
92
93    /// A list from its elements.
94    #[must_use]
95    pub fn list(items: Vec<Object>) -> Self {
96        Object::List(Rc::new(RefCell::new(items)))
97    }
98
99    /// A tuple from its elements.
100    #[must_use]
101    pub fn tuple(items: Vec<Object>) -> Self {
102        Object::Tuple(items.into())
103    }
104
105    /// A dict.
106    #[must_use]
107    pub fn dict(entries: Dict) -> Self {
108        Object::Dict(Rc::new(RefCell::new(entries)))
109    }
110
111    /// A set.
112    #[must_use]
113    pub fn set(members: Set) -> Self {
114        Object::Set(Rc::new(RefCell::new(members)))
115    }
116
117    /// A value of a type defined above this crate.
118    #[must_use]
119    pub fn native(value: impl Native + 'static) -> Self {
120        Object::Native(Rc::new(value))
121    }
122
123    /// The native value inside this object, if that is what it is and if it is
124    /// the type asked for.
125    ///
126    /// This is the downcast the runtime uses to find out whether the thing in a
127    /// register is the kind of object it can call or step.
128    #[must_use]
129    pub fn downcast<T: Native + 'static>(&self) -> Option<&T> {
130        match self {
131            Object::Native(value) => value.as_any().downcast_ref::<T>(),
132            _ => None,
133        }
134    }
135
136    /// This value as the exception it is, or `None` if it is not one.
137    ///
138    /// The one downcast common enough to be worth a name, since `raise`,
139    /// `except` and the traceback printer all ask the same question.
140    #[must_use]
141    pub fn exception(&self) -> Option<&Exception> {
142        self.downcast::<Exception>()
143    }
144
145    /// What `type(x).__name__` says, which is what every error message needs.
146    ///
147    /// Borrowed rather than `&'static str`, because a class defined in Python
148    /// names itself and that name is owned by the class object. Everything
149    /// built in still hands back a literal.
150    #[must_use]
151    pub fn type_name(&self) -> &str {
152        match self {
153            Object::None => "NoneType",
154            Object::NotImplemented => "NotImplementedType",
155            Object::Ellipsis => "ellipsis",
156            Object::Bool(_) => "bool",
157            Object::Int(_) => "int",
158            Object::Float(_) => "float",
159            Object::Str(_) => "str",
160            Object::Bytes(_) => "bytes",
161            Object::Tuple(_) => "tuple",
162            Object::List(_) => "list",
163            Object::Dict(_) => "dict",
164            Object::Set(_) => "set",
165            Object::Slice(_) => "slice",
166            Object::Native(value) => value.type_name(),
167        }
168    }
169
170    /// Python's truth protocol for the types that have no `__bool__` to run.
171    ///
172    /// Zero of any numeric type is false, an empty container is false, `None`
173    /// is false, and everything else is true. When user-defined types arrive
174    /// this becomes the thing that calls `__bool__` and then `__len__`, and the
175    /// answers below become what the builtin types answer with.
176    #[must_use]
177    pub fn truthy(&self) -> bool {
178        match self {
179            Object::None => false,
180            Object::Bool(value) => *value,
181            Object::Int(value) => !value.is_zero(),
182            Object::Float(value) => *value != 0.0,
183            Object::Str(value) => !value.is_empty(),
184            Object::Bytes(value) => !value.is_empty(),
185            Object::Tuple(items) => !items.is_empty(),
186            Object::List(items) => !items.borrow().is_empty(),
187            Object::Dict(entries) => !entries.borrow().is_empty(),
188            Object::Set(members) => !members.borrow().is_empty(),
189            Object::Native(value) => value.truthy(),
190            // `Ellipsis`, `NotImplemented` and a slice are objects with no
191            // `__bool__` and no `__len__`, which makes them true.
192            Object::NotImplemented | Object::Ellipsis | Object::Slice(_) => true,
193        }
194    }
195
196    /// Whether these are the same object, which is what `is` asks.
197    ///
198    /// For a heap value it is the pointer. For an immediate it is the value,
199    /// which is the one place this differs from CPython in a way a program
200    /// could see: `x = 1000; y = 1000; x is y` is `False` in CPython because
201    /// there are two objects, and is `True` here because there are none. The
202    /// tagged representation makes that true for real, and the language does
203    /// not promise either answer.
204    ///
205    /// The loudest case of it is the NaN, since identity is what decides
206    /// `nan in [nan]` and whether a NaN can be found in a dict again. Two
207    /// separately made ones are two objects in CPython and one value here.
208    #[must_use]
209    pub fn is(&self, other: &Self) -> bool {
210        match (self, other) {
211            (Object::None, Object::None)
212            | (Object::NotImplemented, Object::NotImplemented)
213            | (Object::Ellipsis, Object::Ellipsis) => true,
214            (Object::Bool(a), Object::Bool(b)) => a == b,
215            (Object::Int(a), Object::Int(b)) => a == b,
216            // Two NaNs are the same object when they are the same object, and
217            // `float('nan') is float('nan')` is false. Bit equality is the
218            // closest an immediate can get, and it gets `x is x` right.
219            (Object::Float(a), Object::Float(b)) => a.to_bits() == b.to_bits(),
220            (Object::Str(a), Object::Str(b)) => Rc::ptr_eq(a, b),
221            (Object::Bytes(a), Object::Bytes(b)) => Rc::ptr_eq(a, b),
222            (Object::Tuple(a), Object::Tuple(b)) => Rc::ptr_eq(a, b),
223            (Object::List(a), Object::List(b)) => Rc::ptr_eq(a, b),
224            (Object::Dict(a), Object::Dict(b)) => Rc::ptr_eq(a, b),
225            (Object::Set(a), Object::Set(b)) => Rc::ptr_eq(a, b),
226            (Object::Slice(a), Object::Slice(b)) => Rc::ptr_eq(a, b),
227            // The address alone, because two `Rc<dyn Native>` to one object can
228            // carry two vtable pointers and `Rc::ptr_eq` would compare those too.
229            (Object::Native(a), Object::Native(b)) => {
230                std::ptr::addr_eq(Rc::as_ptr(a), Rc::as_ptr(b))
231            }
232            _ => false,
233        }
234    }
235
236    /// What `==` answers.
237    ///
238    /// Numbers compare across their types, so `1 == 1.0 == True`, and an
239    /// integer too large for a float still gets an exact answer. Everything
240    /// else compares only within its own type: a `str` is never equal to the
241    /// `bytes` that spell it and a tuple is never equal to a list, however
242    /// alike either pair looks.
243    ///
244    /// A container holding itself sends this into a recursion CPython turns
245    /// into a `RecursionError`. There is no recursion limit here yet, because
246    /// there are no frames to count, and it arrives with them.
247    #[must_use]
248    pub fn equals(&self, other: &Self) -> bool {
249        match (self, other) {
250            (Object::None, Object::None)
251            | (Object::Ellipsis, Object::Ellipsis)
252            | (Object::NotImplemented, Object::NotImplemented) => true,
253            (Object::Str(a), Object::Str(b)) => a == b,
254            (Object::Bytes(a), Object::Bytes(b)) => a == b,
255            (Object::Tuple(a), Object::Tuple(b)) => elementwise(a, b),
256            (Object::List(a), Object::List(b)) => {
257                // The same list on both sides, which is `x == x` and which
258                // borrowing twice would panic on rather than answer.
259                Rc::ptr_eq(a, b) || elementwise(&a.borrow(), &b.borrow())
260            }
261            (Object::Dict(a), Object::Dict(b)) => {
262                Rc::ptr_eq(a, b) || a.borrow().equals(&b.borrow())
263            }
264            (Object::Set(a), Object::Set(b)) => Rc::ptr_eq(a, b) || a.borrow().equals(&b.borrow()),
265            // Two slices are equal when their three parts are, which is what
266            // makes `x[1:2] == x[1:2]` true of the subscripts as well as of the
267            // results. A slice is never equal to the tuple that spells it.
268            (Object::Slice(a), Object::Slice(b)) => {
269                Rc::ptr_eq(a, b)
270                    || a.parts()
271                        .iter()
272                        .zip(b.parts())
273                        .all(|(a, b)| a.same_value(b))
274            }
275            // A native value has no `__eq__` to run, so it is equal to itself,
276            // and then to whatever it says it is equal to. Almost all of them
277            // say nothing else.
278            (Object::Native(a), Object::Native(b)) => self.is(other) || a.equals(&**b),
279            _ => match (self.as_number(), other.as_number()) {
280                (Some(a), Some(b)) => a.equals(&b),
281                _ => false,
282            },
283        }
284    }
285
286    /// What a container asks about its elements, and what a dict asks about a
287    /// key, which is `x is y or x == y` rather than plain `==`.
288    ///
289    /// The identity half is not an optimization. `x == x` is false for a NaN,
290    /// so `[nan] == [nan]` would be false without it where CPython says true
291    /// for the same NaN in both, and a NaN stored in a dict could never be
292    /// found again.
293    #[must_use]
294    pub fn same_value(&self, other: &Self) -> bool {
295        self.is(other) || self.equals(other)
296    }
297
298    /// This value seen as a number, if it is one, with `bool` widened to the
299    /// `int` it is so the three numeric types become two cases.
300    fn as_number(&self) -> Option<Number<'_>> {
301        match self {
302            Object::Bool(value) => Some(Number::Int(Cow::Owned(Int::Small(i64::from(*value))))),
303            Object::Int(value) => Some(Number::Int(Cow::Borrowed(value))),
304            Object::Float(value) => Some(Number::Float(*value)),
305            _ => None,
306        }
307    }
308
309    /// What `repr` prints.
310    #[must_use]
311    pub fn repr(&self) -> String {
312        let mut seen = Vec::new();
313        self.write_repr(&mut seen)
314    }
315
316    /// What `str` prints, which differs from `repr` only for a string itself.
317    ///
318    /// `print('a')` writes `a` and `print(['a'])` writes `['a']`, because a
319    /// container prints its elements with `repr` however it was printed itself.
320    #[must_use]
321    pub fn display(&self) -> String {
322        match self {
323            Object::Str(value) => value.to_string(),
324            // A native type gets to answer this one for itself, because an
325            // exception says its message here and its constructor call in
326            // `repr`. Everything else defaults to the `repr`.
327            Object::Native(value) => value.display(),
328            other => other.repr(),
329        }
330    }
331
332    /// `repr`, carrying the containers currently being printed.
333    ///
334    /// `a = []` then `a.append(a)` gives a list that holds itself, and CPython
335    /// prints `[[...]]` for it. Without the trail this recurses until the stack
336    /// runs out, which is a crash rather than an answer.
337    fn write_repr(&self, seen: &mut Vec<*const ()>) -> String {
338        match self {
339            Object::None => "None".to_owned(),
340            Object::NotImplemented => "NotImplemented".to_owned(),
341            Object::Ellipsis => "Ellipsis".to_owned(),
342            Object::Bool(true) => "True".to_owned(),
343            Object::Bool(false) => "False".to_owned(),
344            Object::Int(value) => value.to_string(),
345            Object::Float(value) => float_repr(*value, DotZero::Add),
346            Object::Str(value) => value.repr(),
347            Object::Bytes(value) => bytes_repr(value),
348            Object::Slice(value) => value.repr(),
349            Object::Tuple(items) => {
350                let address = Rc::as_ptr(items).cast::<()>();
351                let inner = with_trail(seen, address, |seen| parts(items, seen));
352                match inner {
353                    // A tuple of one keeps its comma, because `(1)` is `1` and
354                    // the point of the repr is that it reads back.
355                    Some(parts) if parts.len() == 1 => format!("({},)", parts[0]),
356                    Some(parts) => format!("({})", parts.join(", ")),
357                    None => "(...)".to_owned(),
358                }
359            }
360            Object::List(items) => {
361                let address = Rc::as_ptr(items).cast::<()>();
362                let inner = with_trail(seen, address, |seen| parts(&items.borrow(), seen));
363                match inner {
364                    Some(parts) => format!("[{}]", parts.join(", ")),
365                    None => "[...]".to_owned(),
366                }
367            }
368            Object::Dict(entries) => {
369                let address = Rc::as_ptr(entries).cast::<()>();
370                let inner = with_trail(seen, address, |seen| {
371                    entries
372                        .borrow()
373                        .iter()
374                        .map(|(key, value)| {
375                            // The key cannot be a container that holds this
376                            // dict, since a container that can hold anything
377                            // has no hash, so only the value needs the trail.
378                            format!("{}: {}", key.object().repr(), value.write_repr(seen))
379                        })
380                        .collect::<Vec<_>>()
381                });
382                match inner {
383                    Some(parts) => format!("{{{}}}", parts.join(", ")),
384                    None => "{...}".to_owned(),
385                }
386            }
387            Object::Set(members) => {
388                let members = members.borrow();
389                if members.is_empty() {
390                    // `{}` is an empty dict, so an empty set has to spell
391                    // itself out. It is the one repr that does not read back
392                    // as the literal it came from, because there is no literal.
393                    return "set()".to_owned();
394                }
395                // No trail: a set can only hold hashable values and none of
396                // those can hold a set, so there is no cycle to guard against.
397                let parts: Vec<_> = members.iter().map(|value| value.object().repr()).collect();
398                format!("{{{}}}", parts.join(", "))
399            }
400            // No trail: a native value cannot hold an `Object`, since this crate
401            // is the one that would have to lend it the type to hold.
402            Object::Native(value) => value.repr(),
403        }
404    }
405}
406
407/// A numeric value with `bool` folded into `int`, which is what lets the three
408/// numeric types be compared as two.
409enum Number<'a> {
410    Int(Cow<'a, Int>),
411    Float(f64),
412}
413
414impl Number<'_> {
415    #[expect(
416        clippy::float_cmp,
417        reason = "this is Python's `==` on two floats, so it is IEEE equality \
418                  and an epsilon would be a wrong answer rather than a safer one"
419    )]
420    fn equals(&self, other: &Self) -> bool {
421        match (self, other) {
422            (Number::Int(a), Number::Int(b)) => a == b,
423            (Number::Float(a), Number::Float(b)) => a == b,
424            (Number::Int(a), Number::Float(b)) | (Number::Float(b), Number::Int(a)) => {
425                int_eq_float(a, *b)
426            }
427        }
428    }
429}
430
431/// Two sequences compared position by position, which stops at the first
432/// difference and so never looks past a length mismatch.
433fn elementwise(left: &[Object], right: &[Object]) -> bool {
434    left.len() == right.len() && left.iter().zip(right).all(|(a, b)| a.same_value(b))
435}
436
437/// The reprs of a sequence's elements.
438fn parts(items: &[Object], seen: &mut Vec<*const ()>) -> Vec<String> {
439    items.iter().map(|item| item.write_repr(seen)).collect()
440}
441
442/// Run `body` with `address` on the trail, or answer `None` if it is already
443/// there because that means we have come back round to it.
444fn with_trail<T>(
445    seen: &mut Vec<*const ()>,
446    address: *const (),
447    body: impl FnOnce(&mut Vec<*const ()>) -> T,
448) -> Option<T> {
449    if seen.contains(&address) {
450        return None;
451    }
452    seen.push(address);
453    let value = body(seen);
454    seen.pop();
455    Some(value)
456}
457
458#[cfg(test)]
459mod tests {
460    use super::*;
461    use crate::hash::Key;
462
463    #[test]
464    fn the_singletons_print_as_their_names() {
465        assert_eq!(Object::None.repr(), "None");
466        assert_eq!(Object::Ellipsis.repr(), "Ellipsis");
467        assert_eq!(Object::NotImplemented.repr(), "NotImplemented");
468        assert_eq!(Object::Bool(true).repr(), "True");
469        assert_eq!(Object::Bool(false).repr(), "False");
470    }
471
472    #[test]
473    fn a_type_names_itself_the_way_an_error_message_would() {
474        assert_eq!(Object::None.type_name(), "NoneType");
475        assert_eq!(Object::Bool(true).type_name(), "bool");
476        assert_eq!(Object::int(1).type_name(), "int");
477        assert_eq!(Object::Float(1.0).type_name(), "float");
478        assert_eq!(Object::str("a").type_name(), "str");
479        assert_eq!(Object::Ellipsis.type_name(), "ellipsis");
480    }
481
482    #[test]
483    fn emptiness_is_falseness_for_every_container() {
484        assert!(!Object::list(vec![]).truthy());
485        assert!(Object::list(vec![Object::None]).truthy());
486        assert!(!Object::tuple(vec![]).truthy());
487        assert!(Object::tuple(vec![Object::None]).truthy());
488        assert!(!Object::str("").truthy());
489        assert!(Object::str("a").truthy());
490        assert!(!Object::Bytes(Rc::from(&b""[..])).truthy());
491        assert!(Object::Bytes(Rc::from(&b"a"[..])).truthy());
492    }
493
494    /// A container holding only falsey things is still true, because what is
495    /// asked is its length rather than anything about what is in it.
496    #[test]
497    fn a_container_of_falsey_things_is_true() {
498        assert!(Object::list(vec![Object::int(0)]).truthy());
499        assert!(Object::tuple(vec![Object::None]).truthy());
500    }
501
502    #[test]
503    fn zero_is_false_in_every_numeric_type() {
504        assert!(!Object::int(0).truthy());
505        assert!(Object::int(1).truthy());
506        assert!(Object::int(-1).truthy());
507        assert!(!Object::Float(0.0).truthy());
508        // `-0.0 == 0.0`, so it is false too, and `nan` is true.
509        assert!(!Object::Float(-0.0).truthy());
510        assert!(Object::Float(f64::NAN).truthy());
511        assert!(!Object::Bool(false).truthy());
512    }
513
514    #[test]
515    fn a_tuple_of_one_keeps_the_comma_that_makes_it_a_tuple() {
516        assert_eq!(Object::tuple(vec![]).repr(), "()");
517        assert_eq!(Object::tuple(vec![Object::int(1)]).repr(), "(1,)");
518        assert_eq!(
519            Object::tuple(vec![Object::int(1), Object::int(2)]).repr(),
520            "(1, 2)"
521        );
522    }
523
524    #[test]
525    fn a_container_prints_its_elements_with_repr() {
526        let value = Object::list(vec![Object::str("a"), Object::None, Object::Float(1.5)]);
527        assert_eq!(value.repr(), "['a', None, 1.5]");
528        // And that does not change when the container itself is printed with
529        // `str`, which is why `print(['a'])` shows the quotes.
530        assert_eq!(value.display(), "['a', None, 1.5]");
531    }
532
533    #[test]
534    fn str_of_a_string_is_the_string_and_repr_of_one_is_quoted() {
535        assert_eq!(Object::str("a").display(), "a");
536        assert_eq!(Object::str("a").repr(), "'a'");
537        assert_eq!(Object::str("it's").repr(), "\"it's\"");
538        // Everything else prints the same either way.
539        assert_eq!(Object::int(1).display(), "1");
540        assert_eq!(Object::None.display(), "None");
541    }
542
543    /// A list that holds itself has no finite repr, and CPython prints the
544    /// ellipsis rather than recursing until the stack runs out.
545    #[test]
546    fn a_container_that_holds_itself_prints_an_ellipsis() {
547        let items = Rc::new(RefCell::new(Vec::new()));
548        let value = Object::List(Rc::clone(&items));
549        items.borrow_mut().push(value.clone());
550        assert_eq!(value.repr(), "[[...]]");
551
552        // Two hops round is the same thing one level further out.
553        let outer = Rc::new(RefCell::new(Vec::new()));
554        items.borrow_mut().clear();
555        items.borrow_mut().push(Object::List(Rc::clone(&outer)));
556        outer.borrow_mut().push(value.clone());
557        assert_eq!(value.repr(), "[[[...]]]");
558    }
559
560    /// The same container twice in one repr is not a cycle, and printing it as
561    /// one would be wrong. The trail has to come off again on the way out.
562    #[test]
563    fn the_same_container_twice_side_by_side_is_not_a_cycle() {
564        let shared = Object::list(vec![Object::int(1)]);
565        let value = Object::list(vec![shared.clone(), shared]);
566        assert_eq!(value.repr(), "[[1], [1]]");
567    }
568
569    #[test]
570    fn identity_is_the_pointer_for_a_heap_value() {
571        let list = Object::list(vec![]);
572        assert!(list.is(&list.clone()));
573        assert!(!list.is(&Object::list(vec![])));
574
575        let text = Object::str("a");
576        assert!(text.is(&text.clone()));
577        assert!(!text.is(&Object::str("a")));
578    }
579
580    /// `None is None` is the question `x is None` asks a few million times a
581    /// second, and the answer has to be yes without a heap object to compare.
582    #[test]
583    fn identity_is_the_value_for_a_singleton_or_a_number() {
584        assert!(Object::None.is(&Object::None));
585        assert!(Object::Ellipsis.is(&Object::Ellipsis));
586        assert!(!Object::None.is(&Object::Ellipsis));
587        assert!(Object::int(1000).is(&Object::int(1000)));
588        assert!(!Object::int(1).is(&Object::Bool(true)));
589    }
590
591    /// `x is x` has to hold for a NaN even though `x == x` does not, which is
592    /// the whole reason identity is asked separately from equality.
593    #[test]
594    fn a_nan_is_itself() {
595        let nan = Object::Float(f64::NAN);
596        assert!(nan.is(&nan.clone()));
597        assert!(!nan.is(&Object::Float(1.0)));
598        assert!(!nan.equals(&nan.clone()));
599        assert!(nan.same_value(&nan.clone()));
600    }
601
602    /// `{}` is an empty dict, so an empty set has nothing to be spelled as and
603    /// has to name its own constructor.
604    #[test]
605    fn an_empty_set_is_the_one_repr_that_is_not_a_literal() {
606        assert_eq!(Object::dict(Dict::new()).repr(), "{}");
607        assert_eq!(Object::set(Set::new()).repr(), "set()");
608    }
609
610    #[test]
611    fn a_dict_prints_its_pairs_in_the_order_they_went_in() {
612        let key = |object| Key::new(object).expect("expected this to be hashable");
613        let dict: Dict = [
614            (key(Object::str("b")), Object::int(1)),
615            (key(Object::str("a")), Object::int(2)),
616        ]
617        .into_iter()
618        .collect();
619        assert_eq!(Object::dict(dict).repr(), "{'b': 1, 'a': 2}");
620
621        let set: Set = [key(Object::int(1)), key(Object::int(2))]
622            .into_iter()
623            .collect();
624        assert_eq!(Object::set(set).repr(), "{1, 2}");
625    }
626
627    /// A dict can hold itself as a value, and CPython prints the ellipsis for
628    /// it the same way it does for a list. It cannot hold itself as a key,
629    /// because it has no hash.
630    #[test]
631    fn a_dict_that_holds_itself_prints_an_ellipsis() {
632        let entries = Rc::new(RefCell::new(Dict::new()));
633        let value = Object::Dict(Rc::clone(&entries));
634        let key = Key::new(Object::str("x")).expect("expected this to be hashable");
635        entries.borrow_mut().insert(key, value.clone());
636        assert_eq!(value.repr(), "{'x': {...}}");
637    }
638
639    #[test]
640    fn dicts_and_sets_compare_by_what_is_in_them() {
641        let dict = |pairs: Vec<(i64, i64)>| {
642            let entries: Dict = pairs
643                .into_iter()
644                .map(|(k, v)| (Key::new(Object::int(k)).expect("hashable"), Object::int(v)))
645                .collect();
646            Object::dict(entries)
647        };
648        assert!(dict(vec![(1, 2), (3, 4)]).equals(&dict(vec![(3, 4), (1, 2)])));
649        assert!(!dict(vec![(1, 2)]).equals(&dict(vec![(1, 3)])));
650        assert!(!dict(vec![(1, 2)]).equals(&dict(vec![(1, 2), (3, 4)])));
651        // A dict is not a set and a set is not a dict, however they print.
652        assert!(!dict(vec![]).equals(&Object::set(Set::new())));
653    }
654
655    #[test]
656    fn a_dict_and_a_set_are_not_hashable() {
657        for value in [Object::dict(Dict::new()), Object::set(Set::new())] {
658            let name = value.type_name().to_owned();
659            let refused = Key::new(value).expect_err("expected this to be refused");
660            assert_eq!(refused.message(), format!("unhashable type: '{name}'"));
661        }
662    }
663
664    #[test]
665    fn the_three_numeric_types_compare_against_each_other() {
666        assert!(Object::int(1).equals(&Object::Float(1.0)));
667        assert!(Object::int(1).equals(&Object::Bool(true)));
668        assert!(Object::int(0).equals(&Object::Bool(false)));
669        assert!(Object::Float(0.0).equals(&Object::Bool(false)));
670        assert!(Object::Float(-0.0).equals(&Object::Float(0.0)));
671        assert!(!Object::int(1).equals(&Object::Float(1.5)));
672        assert!(!Object::int(1).equals(&Object::Float(f64::INFINITY)));
673    }
674
675    /// Every other type compares only within itself, however alike two of them
676    /// happen to look.
677    #[test]
678    fn nothing_but_a_number_compares_across_types() {
679        assert!(!Object::str("abc").equals(&Object::Bytes(Rc::from(&b"abc"[..]))));
680        assert!(!Object::tuple(vec![Object::int(1)]).equals(&Object::list(vec![Object::int(1)])));
681        assert!(!Object::int(1).equals(&Object::str("1")));
682        assert!(!Object::None.equals(&Object::Bool(false)));
683        assert!(!Object::None.equals(&Object::int(0)));
684    }
685
686    #[test]
687    fn a_sequence_compares_position_by_position() {
688        let list = |items: Vec<Object>| Object::list(items);
689        assert!(list(vec![]).equals(&list(vec![])));
690        assert!(list(vec![Object::int(1)]).equals(&list(vec![Object::Float(1.0)])));
691        assert!(!list(vec![Object::int(1)]).equals(&list(vec![Object::int(1), Object::int(2)])));
692        assert!(!list(vec![Object::int(1)]).equals(&list(vec![Object::int(2)])));
693        // Nesting compares the same way the whole way down.
694        let nested = |n| Object::tuple(vec![Object::tuple(vec![Object::int(n)])]);
695        assert!(nested(1).equals(&nested(1)));
696        assert!(!nested(1).equals(&nested(2)));
697    }
698
699    /// The identity shortcut inside a container is what makes this true, and
700    /// CPython says the same for the same reason.
701    #[test]
702    fn a_list_holding_a_nan_is_equal_to_itself() {
703        let nan = Object::Float(f64::NAN);
704        let value = Object::list(vec![nan]);
705        assert!(value.equals(&value.clone()));
706    }
707
708    /// `x == x` on a list is asked all the time, and reaching for the contents
709    /// of the same list twice would be a panic rather than an answer.
710    #[test]
711    fn a_list_compared_against_itself_does_not_borrow_it_twice() {
712        let value = Object::list(vec![Object::int(1)]);
713        assert!(value.equals(&value.clone()));
714    }
715
716    /// A stand-in for whatever the runtime defines, which is enough to check
717    /// that this crate asks it the questions and does not answer them itself.
718    #[derive(Debug)]
719    struct Thing(&'static str);
720
721    impl crate::native::Native for Thing {
722        fn type_name(&self) -> &str {
723            "thing"
724        }
725
726        fn repr(&self) -> String {
727            format!("<thing {}>", self.0)
728        }
729
730        fn as_any(&self) -> &dyn std::any::Any {
731            self
732        }
733    }
734
735    #[test]
736    fn a_native_value_answers_for_itself() {
737        let value = Object::native(Thing("a"));
738        assert_eq!(value.type_name(), "thing");
739        assert_eq!(value.repr(), "<thing a>");
740        assert_eq!(value.display(), "<thing a>");
741        // The default truth, which is what an object with no `__bool__` and no
742        // `__len__` has.
743        assert!(value.truthy());
744        assert_eq!(value.downcast::<Thing>().map(|thing| thing.0), Some("a"));
745    }
746
747    /// Identity and equality are both the address, so two natives spelled the
748    /// same are two objects and neither `is` nor `==` says otherwise.
749    #[test]
750    fn a_native_value_is_equal_to_itself_and_to_nothing_else() {
751        let value = Object::native(Thing("a"));
752        assert!(value.is(&value.clone()));
753        assert!(value.equals(&value.clone()));
754        assert!(!value.is(&Object::native(Thing("a"))));
755        assert!(!value.equals(&Object::native(Thing("a"))));
756        assert!(!value.equals(&Object::int(1)));
757        // A container holding it compares by the same rule the whole way down.
758        let held = Object::list(vec![value.clone()]);
759        assert!(held.equals(&Object::list(vec![value])));
760    }
761
762    /// A native value is hashable, which is what puts a function in a dict, and
763    /// its hash comes from the address rather than from anything about it.
764    #[test]
765    fn a_native_value_can_be_a_key() {
766        let value = Object::native(Thing("a"));
767        let key = Key::new(value.clone()).expect("expected this to be hashable");
768        let same = Key::new(value).expect("expected this to be hashable");
769        assert_eq!(
770            crate::hash::hash(key.object()),
771            crate::hash::hash(same.object())
772        );
773
774        let mut dict = Dict::new();
775        dict.insert(key, Object::int(1));
776        assert_eq!(dict.get(&same).map(Object::repr), Some("1".to_owned()));
777        // A different object of the same type is a different key.
778        let other = Key::new(Object::native(Thing("a"))).expect("expected this to be hashable");
779        assert!(!dict.contains(&other));
780    }
781}