1use std::sync::Arc;
2
3use rustc_hash::FxHashMap;
4
5use crate::{
6 DefId,
7 rir::{Arg, EnumVariant, Field, Item, Method, Node},
8 ty::{Ty, TyKind},
9};
10
11type Nodes = Arc<FxHashMap<DefId, Node>>;
12
13pub fn def_id_equal(nodes: &Nodes, def_id1: DefId, def_id2: DefId) -> bool {
14 let node1 = nodes.get(&def_id1).unwrap();
15 let node2 = nodes.get(&def_id2).unwrap();
16 node_equal(nodes, node1, node2)
17}
18
19fn node_equal(nodes: &Nodes, n1: &Node, n2: &Node) -> bool {
20 match (&n1.kind, &n2.kind) {
21 (crate::rir::NodeKind::Item(item1), crate::rir::NodeKind::Item(item2)) => {
22 item_equal(nodes, item1, item2)
23 }
24 (crate::rir::NodeKind::Variant(v1), crate::rir::NodeKind::Variant(v2)) => {
25 variant_equal(nodes, v1, v2)
26 }
27 (crate::rir::NodeKind::Field(f1), crate::rir::NodeKind::Field(f2)) => {
28 field_equal(nodes, f1, f2)
29 }
30 (crate::rir::NodeKind::Method(m1), crate::rir::NodeKind::Method(m2)) => {
31 method_equal(nodes, m1, m2)
32 }
33 (crate::rir::NodeKind::Arg(a1), crate::rir::NodeKind::Arg(a2)) => arg_equal(nodes, a1, a2),
34 _ => false,
35 }
36}
37
38fn item_equal(nodes: &Nodes, item1: &Item, item2: &Item) -> bool {
39 match (item1, item2) {
40 (Item::Message(m1), Item::Message(m2)) => {
41 m1.name == m2.name
42 && vec_equal_by_key(
43 nodes,
44 &m1.fields,
45 &m2.fields,
46 |m| m.id,
47 |cx, f1, f2| field_equal(cx, f1, f2),
48 )
49 }
50 (Item::Enum(e1), Item::Enum(e2)) => {
51 e1.name == e2.name
52 && vec_equal_by_key(
53 nodes,
54 &e1.variants,
55 &e2.variants,
56 |v| v.id,
57 |cx, v1, v2| variant_equal(cx, v1, v2),
58 )
59 }
60 (Item::Service(s1), Item::Service(s2)) => {
61 s1.name == s2.name
62 && vec_equal_by_key(
63 nodes,
64 &s1.extend,
65 &s2.extend,
66 |e| e.did,
67 |cx, d1, d2| def_id_equal(cx, d1.did, d2.did),
68 )
69 && vec_equal_by_key(
70 nodes,
71 &s1.methods,
72 &s2.methods,
73 |m| m.name.0.clone(),
74 |cx, m1, m2| method_equal(cx, m1, m2),
75 )
76 }
77 (Item::NewType(n1), Item::NewType(n2)) => {
78 n1.name == n2.name && ty_equal(nodes, &n1.ty, &n2.ty)
79 }
80 (Item::Const(c1), Item::Const(c2)) => c1.name == c2.name && ty_equal(nodes, &c1.ty, &c2.ty),
81 _ => false,
82 }
83}
84
85fn vec_equal_by_key<T: Clone, F, O: Ord>(
86 nodes: &Nodes,
87 v1: &[T],
88 v2: &[T],
89 get_key: impl Fn(&T) -> O,
90 f: F,
91) -> bool
92where
93 F: Fn(&Nodes, &T, &T) -> bool,
94{
95 if v1.len() != v2.len() {
96 return false;
97 }
98
99 v1.to_owned().sort_by_key(|i| get_key(i));
100 v2.to_owned().sort_by_key(|i| get_key(i));
101
102 v1.iter().zip(v2.iter()).all(|(i1, i2)| f(nodes, i1, i2))
103}
104
105fn variant_equal(nodes: &Nodes, v1: &EnumVariant, v2: &EnumVariant) -> bool {
106 v1.name == v2.name
107 && v1.id == v2.id
108 && v1.discr == v2.discr
109 && v1.fields.len() == v2.fields.len()
110 && v1
111 .fields
112 .iter()
113 .zip(&v2.fields)
114 .all(|(t1, t2)| ty_equal(nodes, t1, t2))
115}
116
117fn field_equal(nodes: &Nodes, f1: &Field, f2: &Field) -> bool {
118 f1.id == f2.id && f1.kind == f2.kind && ty_equal(nodes, &f1.ty, &f2.ty)
119}
120
121fn method_equal(nodes: &Nodes, m1: &Method, m2: &Method) -> bool {
122 m1.name == m2.name
123 && m1.args.len() == m2.args.len()
124 && m1
125 .args
126 .iter()
127 .zip(m2.args.iter())
128 .all(|(a1, a2)| ty_equal(nodes, &a1.ty, &a2.ty))
129}
130
131fn arg_equal(nodes: &Nodes, a1: &Arg, a2: &Arg) -> bool {
132 ty_equal(nodes, &a1.ty, &a2.ty)
133}
134
135fn ty_equal(nodes: &Nodes, ty1: &Ty, ty2: &Ty) -> bool {
136 match (&ty1.kind, &ty2.kind) {
137 (TyKind::String, TyKind::String) => true,
138 (TyKind::FastStr, TyKind::FastStr) => true,
139 (TyKind::Void, TyKind::Void) => true,
140 (TyKind::U8, TyKind::U8) => true,
141 (TyKind::Bool, TyKind::Bool) => true,
142 (TyKind::BytesVec, TyKind::BytesVec) => true,
143 (TyKind::Bytes, TyKind::Bytes) => true,
144 (TyKind::I8, TyKind::I8) => true,
145 (TyKind::I16, TyKind::I16) => true,
146 (TyKind::I32, TyKind::I32) => true,
147 (TyKind::I64, TyKind::I64) => true,
148 (TyKind::UInt32, TyKind::UInt32) => true,
149 (TyKind::UInt64, TyKind::UInt32) => true,
150 (TyKind::F32, TyKind::F32) => true,
151 (TyKind::F64, TyKind::F64) => true,
152 (TyKind::Map(k1, v1), TyKind::Map(k2, v2)) => {
153 ty_equal(nodes, k1, k2) && ty_equal(nodes, v1, v2)
154 }
155 (TyKind::Vec(t1), TyKind::Vec(t2))
156 | (TyKind::Set(t1), TyKind::Set(t2))
157 | (TyKind::Arc(t1), TyKind::Arc(t2)) => ty_equal(nodes, t1, t2),
158 (TyKind::Path(p1), TyKind::Path(p2)) => def_id_equal(nodes, p1.did, p2.did),
159 _ => false,
160 }
161}