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 {
106 match (left, right) {
107 (Expr::Number(left), Expr::Number(right)) if left.domain.name.as_ref() == "f64" => {
108 left.canonical == right.canonical
109 }
110 _ => left.canonical_eq(right),
111 }
112}
113
114fn object_encoding_eq(left: &ObjectEncoding, right: &ObjectEncoding) -> bool {
115 match (left, right) {
116 (
117 ObjectEncoding::Constructor {
118 class: left_class,
119 args: left_args,
120 },
121 ObjectEncoding::Constructor {
122 class: right_class,
123 args: right_args,
124 },
125 ) => {
126 left_class == right_class
127 && left_args.len() == right_args.len()
128 && left_args
129 .iter()
130 .zip(right_args.iter())
131 .all(|(left, right)| expr_citizen_eq(left, right))
132 }
133 (
134 ObjectEncoding::TaggedData {
135 tag: left_tag,
136 fields: left_fields,
137 },
138 ObjectEncoding::TaggedData {
139 tag: right_tag,
140 fields: right_fields,
141 },
142 ) => {
143 left_tag == right_tag
144 && left_fields.len() == right_fields.len()
145 && left_fields.iter().zip(right_fields.iter()).all(
146 |((left_name, left), (right_name, right))| {
147 left_name == right_name && expr_citizen_eq(left, right)
148 },
149 )
150 }
151 (
152 ObjectEncoding::Opaque {
153 class: left_class,
154 stable_id: left_id,
155 },
156 ObjectEncoding::Opaque {
157 class: right_class,
158 stable_id: right_id,
159 },
160 ) => left_class == right_class && left_id == right_id,
161 _ => false,
162 }
163}