1use std::{
2 cmp::{max, min},
3 collections::{HashMap, HashSet},
4};
5
6use levenshtein::levenshtein;
7
8use tracing::{instrument, trace};
9
10use crate::{
11 query::*,
12 types::{self, Generics, Item},
13 Crate,
14};
15
16#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
17pub enum Similarity {
18 Discrete(DiscreteSimilarity),
20
21 Continuous(f32),
23}
24
25impl Similarity {
26 pub fn score(&self) -> f32 {
27 match self {
28 Discrete(Equivalent) => 0.0,
29 Discrete(Subequal) => 0.25,
30 Discrete(Different) => 1.0,
31 Continuous(s) => *s,
32 }
33 }
34}
35
36use Similarity::*;
37
38#[derive(Debug, Clone, PartialEq, Default)]
39pub struct Similarities(pub Vec<Similarity>);
40
41impl Similarities {
42 pub fn score(&self) -> f32 {
44 let sum: f32 = self.0.iter().map(|sim| sim.score()).sum();
45 sum / self.0.len() as f32
46 }
47}
48
49impl PartialOrd for Similarities {
50 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
51 (self.score()).partial_cmp(&other.score())
52 }
53}
54
55#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
56pub enum DiscreteSimilarity {
57 Equivalent,
63
64 Subequal,
70
71 Different,
76}
77
78use DiscreteSimilarity::*;
79
80pub trait Compare<Rhs> {
81 fn compare(
82 &self,
83 rhs: &Rhs,
84 krate: &Crate,
85 generics: &mut Generics,
86 substs: &mut HashMap<String, Type>,
87 ) -> Vec<Similarity>;
88}
89
90impl Compare<Item> for Query {
91 #[instrument(skip(krate))]
92 fn compare(
93 &self,
94 item: &Item,
95 krate: &Crate,
96 generics: &mut Generics,
97 substs: &mut HashMap<String, Type>,
98 ) -> Vec<Similarity> {
99 let mut sims = vec![];
100
101 match (&self.name, &item.name) {
102 (Some(q), Some(i)) => sims.append(&mut q.compare(i, krate, generics, substs)),
103 (Some(_), None) => sims.push(Discrete(Different)),
104 _ => {}
105 }
106 trace!(?sims);
107
108 if let Some(ref kind) = self.kind {
109 sims.append(&mut kind.compare(&item.inner, krate, generics, substs))
110 }
111 trace!(?sims);
112
113 sims
114 }
115}
116
117impl Compare<String> for Symbol {
118 #[instrument]
119 fn compare(
120 &self,
121 symbol: &String,
122 _: &Crate,
123 _: &mut Generics,
124 _: &mut HashMap<String, Type>,
125 ) -> Vec<Similarity> {
126 use std::cmp::max;
127
128 let symbol = symbol.split("::").last().unwrap(); vec![Continuous(
130 levenshtein(self, symbol) as f32 / max(self.len(), symbol.len()) as f32,
131 )]
132 }
133}
134
135impl Compare<types::ItemEnum> for QueryKind {
136 #[instrument(skip(krate))]
137 fn compare(
138 &self,
139 kind: &types::ItemEnum,
140 krate: &Crate,
141 generics: &mut Generics,
142 substs: &mut HashMap<String, Type>,
143 ) -> Vec<Similarity> {
144 use types::ItemEnum::*;
145 use QueryKind::*;
146
147 match (self, kind) {
148 (FunctionQuery(q), Function(i)) => q.compare(i, krate, generics, substs),
149 (FunctionQuery(_), _) => vec![Discrete(Different)],
151 }
152 }
153}
154
155impl Compare<Qualifier> for Qualifier {
156 #[instrument]
157 fn compare(
158 &self,
159 qualifer: &Qualifier,
160 _: &Crate,
161 _: &mut Generics,
162 _: &mut HashMap<String, Type>,
163 ) -> Vec<Similarity> {
164 let mut sims = vec![];
165
166 if self == qualifer {
167 sims.push(Discrete(Equivalent));
168 } else {
169 sims.push(Discrete(Different));
170 }
171
172 sims
173 }
174}
175impl Compare<types::Function> for Function {
176 #[instrument(skip(krate))]
177 fn compare(
178 &self,
179 function: &types::Function,
180 krate: &Crate,
181 generics: &mut Generics,
182 substs: &mut HashMap<String, Type>,
183 ) -> Vec<Similarity> {
184 generics
185 .params
186 .append(&mut function.generics.params.clone());
187 generics
188 .where_predicates
189 .append(&mut function.generics.where_predicates.clone());
190
191 let mut sims = Vec::new();
192
193 let missing_qualifiers = self
194 .qualifiers
195 .difference(&function.header.qualifiers())
196 .cloned()
197 .collect::<HashSet<_>>();
198 let extra_qualifiers = function
199 .header
200 .qualifiers()
201 .difference(&self.qualifiers)
202 .cloned()
203 .collect::<HashSet<_>>();
204
205 for _ in missing_qualifiers {
206 sims.push(Discrete(Different));
207 }
208 for _ in extra_qualifiers {
209 sims.push(Discrete(Different));
210 }
211
212 sims.extend(self.decl.compare(&function.sig, krate, generics, substs));
213 sims
214 }
215}
216
217impl Compare<types::FunctionSignature> for FnDecl {
218 #[instrument(skip(krate))]
219 fn compare(
220 &self,
221 decl: &types::FunctionSignature,
222 krate: &Crate,
223 generics: &mut Generics,
224 substs: &mut HashMap<String, Type>,
225 ) -> Vec<Similarity> {
226 let mut sims = vec![];
227
228 if let Some(ref inputs) = self.inputs {
229 inputs.iter().enumerate().for_each(|(idx, q)| {
230 if let Some(i) = decl.inputs.get(idx) {
231 sims.append(&mut q.compare(i, krate, generics, substs))
232 }
233 });
234
235 if inputs.len() != decl.inputs.len() {
236 let abs_diff = usize::abs_diff(inputs.len(), decl.inputs.len());
237 sims.append(&mut vec![Discrete(Different); abs_diff])
238 } else if inputs.is_empty() && decl.inputs.is_empty() {
239 sims.push(Discrete(Equivalent));
240 }
241 }
242 trace!(?sims);
243
244 if let Some(ref output) = self.output {
245 sims.append(&mut output.compare(&decl.output, krate, generics, substs));
246 }
247 trace!(?sims);
248
249 sims
250 }
251}
252
253impl Compare<(String, types::Type)> for Argument {
254 #[instrument(skip(krate))]
255 fn compare(
256 &self,
257 arg: &(String, types::Type),
258 krate: &Crate,
259 generics: &mut Generics,
260 substs: &mut HashMap<String, Type>,
261 ) -> Vec<Similarity> {
262 let mut sims = vec![];
263
264 if let Some(ref name) = self.name {
265 sims.append(&mut name.compare(&arg.0, krate, generics, substs));
266 }
267 trace!(?sims);
268
269 if let Some(ref type_) = self.ty {
270 sims.append(&mut type_.compare(&arg.1, krate, generics, substs));
271 }
272 trace!(?sims);
273
274 sims
275 }
276}
277
278impl Compare<Option<types::Type>> for FnRetTy {
279 #[instrument(skip(krate))]
280 fn compare(
281 &self,
282 ret_ty: &Option<types::Type>,
283 krate: &Crate,
284 generics: &mut Generics,
285 substs: &mut HashMap<String, Type>,
286 ) -> Vec<Similarity> {
287 match (self, ret_ty) {
288 (FnRetTy::Return(q), Some(i)) => q.compare(i, krate, generics, substs),
289 (FnRetTy::DefaultReturn, None) => vec![Discrete(Equivalent)],
290 _ => vec![Discrete(Different)],
291 }
292 }
293}
294
295fn compare_type(
296 lhs: &Type,
297 rhs: &types::Type,
298 krate: &Crate,
299 generics: &mut Generics,
300 substs: &mut HashMap<String, Type>,
301 _allow_recursion: bool,
302) -> Vec<Similarity> {
303 use {crate::query::Type::*, types::Type};
304
305 match (lhs, rhs) {
306 (q, Type::Generic(i)) if i == "Self" => {
307 let mut i = None;
308 for where_predicate in &generics.where_predicates {
309 if let types::WherePredicate::EqPredicate {
310 lhs: Type::Generic(lhs),
311 rhs,
312 } = where_predicate
313 {
314 if lhs == "Self" {
315 i = Some(rhs).cloned();
316 break;
317 }
318 }
319 }
320
321 match i {
322 None => {
323 vec![Discrete(Subequal)]
325 }
326 Some(i) => q.compare(&i, krate, generics, substs),
327 }
328 }
329 (q, Type::Generic(i)) => match substs.get(i) {
330 Some(i) => {
331 if q == i {
332 vec![Discrete(Equivalent)]
333 } else {
334 vec![Discrete(Different)]
335 }
336 }
337 None => {
338 substs.insert(i.clone(), q.clone());
339 vec![Discrete(Subequal)]
340 }
341 },
342 (Tuple(q), Type::Tuple(i)) => {
368 let mut sims = q
369 .iter()
370 .zip(i.iter())
371 .filter_map(|(q, i)| q.as_ref().map(|q| q.compare(i, krate, generics, substs)))
372 .flatten()
373 .collect::<Vec<_>>();
374
375 sims.push(Discrete(Equivalent));
377
378 let abs_diff = max(q.len(), i.len()) - min(q.len(), i.len());
380 sims.append(&mut vec![Discrete(Different); abs_diff]);
381
382 sims
383 }
384 (Slice(q), Type::Slice(i)) => {
385 let mut sims = vec![Discrete(Equivalent)];
387
388 if let Some(q) = q {
389 sims.append(&mut q.compare(i.as_ref(), krate, generics, substs));
390 }
391
392 sims
393 }
394 (
395 RawPointer {
396 mutable: q_mut,
397 type_: q,
398 },
399 Type::RawPointer {
400 is_mutable: i_mut,
401 type_: i,
402 },
403 )
404 | (
405 BorrowedRef {
406 mutable: q_mut,
407 type_: q,
408 },
409 Type::BorrowedRef {
410 is_mutable: i_mut,
411 type_: i,
412 ..
413 },
414 ) => {
415 if q_mut == i_mut {
416 q.compare(i.as_ref(), krate, generics, substs)
417 } else {
418 let mut sims = q.compare(i.as_ref(), krate, generics, substs);
419 sims.push(Discrete(Subequal));
420 sims
421 }
422 }
423 (q, Type::RawPointer { type_: i, .. } | Type::BorrowedRef { type_: i, .. }) => {
424 let mut sims = q.compare(i.as_ref(), krate, generics, substs);
425 sims.push(Discrete(Subequal));
426 sims
427 }
428 (RawPointer { type_: q, .. } | BorrowedRef { type_: q, .. }, i) => {
429 let mut sims = q.compare(i, krate, generics, substs);
430 sims.push(Discrete(Subequal));
431 sims
432 }
433 (
434 UnresolvedPath {
435 name: q,
436 args: q_args,
437 },
438 Type::ResolvedPath(types::Path {
439 path: i,
440 args: i_args,
441 ..
442 }),
443 ) => {
444 let mut sims = q.compare(i, krate, generics, substs);
445
446 match (q_args, i_args) {
447 (Some(q), Some(i)) => match (&**q, &**i) {
448 (
449 GenericArgs::AngleBracketed { args: ref q },
450 types::GenericArgs::AngleBracketed { args: ref i, .. },
451 ) => {
452 let q = q.iter().map(|q| {
453 q.as_ref().map(|q| match q {
454 GenericArg::Type(q) => q,
455 })
456 });
457 let i = i.iter().map(|i| match i {
458 types::GenericArg::Type(t) => Some(t),
459 _ => None,
460 });
461 q.zip(i).for_each(|(q, i)| match (q, i) {
462 (Some(q), Some(i)) => {
463 sims.append(&mut q.compare(i, krate, generics, substs))
464 }
465 (Some(_), None) => sims.push(Discrete(Different)),
466 (None, _) => {}
467 });
468 }
469 (_, _) => {}
471 },
472 (Some(q), None) => {
473 let GenericArgs::AngleBracketed { args: ref q } = **q;
474 sims.append(&mut vec![Discrete(Different); q.len()])
475 }
476 (None, _) => {}
477 }
478
479 sims
480 }
481 (Primitive(q), Type::Primitive(i)) => q.compare(i, krate, generics, substs),
482 _ => vec![Discrete(Different)],
483 }
484}
485
486impl Compare<types::Type> for Type {
487 #[instrument(skip(krate))]
488 fn compare(
489 &self,
490 type_: &types::Type,
491 krate: &Crate,
492 generics: &mut Generics,
493 substs: &mut HashMap<String, Type>,
494 ) -> Vec<Similarity> {
495 compare_type(self, type_, krate, generics, substs, true)
496 }
497}
498
499impl Compare<types::Term> for Type {
500 #[instrument(skip(krate))]
501 fn compare(
502 &self,
503 type_: &types::Term,
504 krate: &Crate,
505 generics: &mut Generics,
506 substs: &mut HashMap<String, Type>,
507 ) -> Vec<Similarity> {
508 match type_ {
509 types::Term::Type(i) => compare_type(self, i, krate, generics, substs, true),
510 _ => todo!("comparing Type with non-Type Term is not supported yet"),
511 }
512 }
513}
514
515impl Compare<String> for PrimitiveType {
516 #[instrument]
517 fn compare(
518 &self,
519 prim_ty: &String,
520 _: &Crate,
521 _: &mut Generics,
522 _: &mut HashMap<String, Type>,
523 ) -> Vec<Similarity> {
524 if self.as_str() == prim_ty {
525 vec![Discrete(Equivalent)]
526 } else {
527 vec![Discrete(Different)]
528 }
529 }
530}