pilota_build/
dedup.rs

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}