compose_library/foundations/ops/
equality.rs

1use crate::diag::StrResult;
2use crate::{Array, ArrayValue, MapValue, Value};
3use compose_library::Heap;
4use compose_library::diag::bail;
5
6pub trait Comparison {
7    fn equals(&self, other: &Self, heap: &crate::Heap) -> compose_library::diag::StrResult<bool>;
8
9    fn not_equals(&self, other: &Self, heap: &Heap) -> StrResult<bool> {
10        self.equals(other, heap).map(|b| !b)
11    }
12}
13
14impl Comparison for Value {
15    fn equals(&self, other: &Value, heap: &Heap) -> StrResult<bool> {
16        match (self, other) {
17            (Value::Int(left), Value::Int(right)) => Ok(left == right),
18            (Value::Bool(left), Value::Bool(right)) => Ok(left == right),
19            (Value::Str(left), Value::Str(right)) => Ok(left == right),
20            (Value::Func(left), Value::Func(right)) => Ok(left == right),
21            (Value::Type(left), Value::Type(right)) => Ok(left == right),
22            (Value::Iterator(_left), Value::Iterator(_right)) => {
23                bail!("cannot compare iterators for equality")
24            }
25            (Value::Unit(_), Value::Unit(_)) => Ok(true),
26            // Box performs a HeapRef comparison, so we can compare them directly
27            (Value::Box(left), Value::Box(right)) => Ok(left == right),
28            (Value::Range(left), Value::Range(right)) => Ok(left == right),
29            (Value::Array(left), Value::Array(right)) => left.equals(right, heap),
30            (Value::Map(left), Value::Map(right)) => left.equals(right, heap),
31            (Value::Module(left), Value::Module(right)) => Ok(left == right),
32
33            // Mismatched Value variants are never equal.
34            // We spell out every variant explicitly (instead of using `_`) so that
35            // adding a new Value variant causes a non-exhaustive match error.
36            (Value::Range(_), _)
37            | (Value::Func(_), _)
38            | (Value::Type(_), _)
39            | (Value::Unit(_), _)
40            | (Value::Str(_), _)
41            | (Value::Bool(_), _)
42            | (Value::Iterator(_), _)
43            | (Value::Box(_), _)
44            | (Value::Array(_), _)
45            | (Value::Map(_), _)
46            | (Value::Module(_), _)
47            | (Value::Int(_), _) => Ok(false),
48        }
49    }
50}
51
52impl Comparison for ArrayValue {
53    fn equals(&self, other: &Self, heap: &Heap) -> StrResult<bool> {
54        let left = self.heap_ref().get_unwrap(heap);
55        let right = other.heap_ref().get_unwrap(heap);
56
57        left.equals(right, heap)
58    }
59}
60
61impl Comparison for Array {
62    fn equals(&self, other: &Self, heap: &Heap) -> StrResult<bool> {
63        if self.values.len() != other.values.len() {
64            return Ok(false);
65        }
66
67        for (a, b) in self.values.iter().zip(&other.values) {
68            if !a.equals(b, heap)? {
69                return Ok(false);
70            }
71        }
72
73        Ok(true)
74    }
75}
76
77impl Comparison for MapValue {
78    fn equals(&self, other: &Self, heap: &Heap) -> StrResult<bool> {
79        let left = self.heap_ref().get_unwrap(heap);
80        let right = other.heap_ref().get_unwrap(heap);
81
82        left.equals(right, heap)
83    }
84}