1use sim_kernel::{Cx, Expr, ObjectEncoding, Result, Value};
4
5pub trait CitizenEq<Rhs = Self> {
12 fn citizen_eq(&self, rhs: &Rhs) -> bool;
14}
15
16macro_rules! citizen_eq_partial {
17 ($($ty:ty),* $(,)?) => {
18 $(impl CitizenEq for $ty {
19 fn citizen_eq(&self, rhs: &Self) -> bool {
20 self == rhs
21 }
22 })*
23 };
24}
25
26citizen_eq_partial!(
27 bool, String, i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, usize
28);
29
30impl CitizenEq for f64 {
31 fn citizen_eq(&self, rhs: &Self) -> bool {
32 self.to_string() == rhs.to_string()
33 }
34}
35
36impl<T> CitizenEq for Vec<T>
37where
38 T: CitizenEq,
39{
40 fn citizen_eq(&self, rhs: &Self) -> bool {
41 self.len() == rhs.len()
42 && self
43 .iter()
44 .zip(rhs.iter())
45 .all(|(left, right)| left.citizen_eq(right))
46 }
47}
48
49impl<T> CitizenEq for Option<T>
50where
51 T: CitizenEq,
52{
53 fn citizen_eq(&self, rhs: &Self) -> bool {
54 match (self, rhs) {
55 (Some(left), Some(right)) => left.citizen_eq(right),
56 (None, None) => true,
57 _ => false,
58 }
59 }
60}
61
62pub fn values_citizen_eq(cx: &mut Cx, left: &Value, right: &Value) -> Result<bool> {
69 let left_encoding = left
70 .object()
71 .as_object_encoder()
72 .map(|encoder| encoder.object_encoding(cx))
73 .transpose()?;
74 let right_encoding = right
75 .object()
76 .as_object_encoder()
77 .map(|encoder| encoder.object_encoding(cx))
78 .transpose()?;
79
80 match (left_encoding, right_encoding) {
81 (Some(left), Some(right)) => Ok(object_encoding_eq(&left, &right)),
82 _ => Ok(expr_citizen_eq(
83 &left.object().as_expr(cx)?,
84 &right.object().as_expr(cx)?,
85 )),
86 }
87}
88
89pub fn expr_citizen_eq(left: &Expr, right: &Expr) -> bool {
108 match (left, right) {
109 (Expr::Number(left), Expr::Number(right))
110 if is_f64_domain(&left.domain) || is_f64_domain(&right.domain) =>
111 {
112 left.domain == right.domain && left.canonical == right.canonical
113 }
114 _ => left.canonical_eq(right),
115 }
116}
117
118fn is_f64_domain(symbol: &sim_kernel::Symbol) -> bool {
119 *symbol == sim_kernel::Symbol::qualified("numbers", "f64")
120}
121
122fn object_encoding_eq(left: &ObjectEncoding, right: &ObjectEncoding) -> bool {
123 match (left, right) {
124 (
125 ObjectEncoding::Constructor {
126 class: left_class,
127 args: left_args,
128 },
129 ObjectEncoding::Constructor {
130 class: right_class,
131 args: right_args,
132 },
133 ) => {
134 left_class == right_class
135 && left_args.len() == right_args.len()
136 && left_args
137 .iter()
138 .zip(right_args.iter())
139 .all(|(left, right)| expr_citizen_eq(left, right))
140 }
141 (
142 ObjectEncoding::TaggedData {
143 tag: left_tag,
144 fields: left_fields,
145 },
146 ObjectEncoding::TaggedData {
147 tag: right_tag,
148 fields: right_fields,
149 },
150 ) => {
151 left_tag == right_tag
152 && left_fields.len() == right_fields.len()
153 && left_fields.iter().zip(right_fields.iter()).all(
154 |((left_name, left), (right_name, right))| {
155 left_name == right_name && expr_citizen_eq(left, right)
156 },
157 )
158 }
159 (
160 ObjectEncoding::Opaque {
161 class: left_class,
162 stable_id: left_id,
163 },
164 ObjectEncoding::Opaque {
165 class: right_class,
166 stable_id: right_id,
167 },
168 ) => left_class == right_class && left_id == right_id,
169 _ => false,
170 }
171}