1use std::{
2 cmp::{max, min},
3 collections::HashMap,
4};
5
6use levenshtein::levenshtein;
7use rustdoc_types as types;
8use tracing::{instrument, trace};
9
10use crate::query::*;
11
12#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
13pub enum Similarity {
14 Discrete(DiscreteSimilarity),
16
17 Continuous(f32),
19}
20
21impl Similarity {
22 pub fn score(&self) -> f32 {
23 match self {
24 Discrete(Equivalent) => 0.0,
25 Discrete(Subequal) => 0.25,
26 Discrete(Different) => 1.0,
27 Continuous(s) => *s,
28 }
29 }
30}
31
32use Similarity::*;
33
34#[derive(Debug, Clone, PartialEq)]
35pub struct Similarities(pub Vec<Similarity>);
36
37impl Similarities {
38 pub fn score(&self) -> f32 {
40 let sum: f32 = self.0.iter().map(|sim| sim.score()).sum();
41 sum / self.0.len() as f32
42 }
43}
44
45impl PartialOrd for Similarities {
46 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
47 (self.score()).partial_cmp(&other.score())
48 }
49}
50
51#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
52pub enum DiscreteSimilarity {
53 Equivalent,
59
60 Subequal,
66
67 Different,
72}
73
74use DiscreteSimilarity::*;
75
76pub trait Compare<Rhs> {
77 fn compare(
78 &self,
79 rhs: &Rhs,
80 krate: &types::Crate,
81 generics: &mut types::Generics,
82 substs: &mut HashMap<String, Type>,
83 ) -> Vec<Similarity>;
84}
85
86impl Compare<types::Item> for Query {
87 #[instrument(skip(krate))]
88 fn compare(
89 &self,
90 item: &types::Item,
91 krate: &types::Crate,
92 generics: &mut types::Generics,
93 substs: &mut HashMap<String, Type>,
94 ) -> Vec<Similarity> {
95 let mut sims = vec![];
96
97 match (&self.name, &item.name) {
98 (Some(q), Some(i)) => sims.append(&mut q.compare(i, krate, generics, substs)),
99 (Some(_), None) => sims.push(Discrete(Different)),
100 _ => {}
101 }
102 trace!(?sims);
103
104 if let Some(ref kind) = self.kind {
105 sims.append(&mut kind.compare(&item.inner, krate, generics, substs))
106 }
107 trace!(?sims);
108
109 sims
110 }
111}
112
113impl Compare<String> for Symbol {
114 #[instrument]
115 fn compare(
116 &self,
117 symbol: &String,
118 _: &types::Crate,
119 _: &mut types::Generics,
120 _: &mut HashMap<String, Type>,
121 ) -> Vec<Similarity> {
122 use std::cmp::max;
123
124 let symbol = symbol.split("::").last().unwrap(); vec![Continuous(
126 levenshtein(self, symbol) as f32 / max(self.len(), symbol.len()) as f32,
127 )]
128 }
129}
130
131impl Compare<types::ItemEnum> for QueryKind {
132 #[instrument(skip(krate))]
133 fn compare(
134 &self,
135 kind: &types::ItemEnum,
136 krate: &types::Crate,
137 generics: &mut types::Generics,
138 substs: &mut HashMap<String, Type>,
139 ) -> Vec<Similarity> {
140 use types::ItemEnum::*;
141 use QueryKind::*;
142
143 match (self, kind) {
144 (FunctionQuery(q), Function(i)) => q.compare(i, krate, generics, substs),
145 (FunctionQuery(q), Method(i)) => q.compare(i, krate, generics, substs),
146 (FunctionQuery(_), _) => vec![Discrete(Different)],
147 }
148 }
149}
150
151impl Compare<types::Function> for Function {
152 #[instrument(skip(krate))]
153 fn compare(
154 &self,
155 function: &types::Function,
156 krate: &types::Crate,
157 generics: &mut types::Generics,
158 substs: &mut HashMap<String, Type>,
159 ) -> Vec<Similarity> {
160 generics
161 .params
162 .append(&mut function.generics.params.clone());
163 generics
164 .where_predicates
165 .append(&mut function.generics.where_predicates.clone());
166 self.decl.compare(&function.decl, krate, generics, substs)
167 }
168}
169
170impl Compare<types::Method> for Function {
171 #[instrument(skip(krate))]
172 fn compare(
173 &self,
174 method: &types::Method,
175 krate: &types::Crate,
176 generics: &mut types::Generics,
177 substs: &mut HashMap<String, Type>,
178 ) -> Vec<Similarity> {
179 generics.params.append(&mut method.generics.params.clone());
180 generics
181 .where_predicates
182 .append(&mut method.generics.where_predicates.clone());
183 self.decl.compare(&method.decl, krate, generics, substs)
184 }
185}
186
187impl Compare<types::FnDecl> for FnDecl {
188 #[instrument(skip(krate))]
189 fn compare(
190 &self,
191 decl: &types::FnDecl,
192 krate: &types::Crate,
193 generics: &mut types::Generics,
194 substs: &mut HashMap<String, Type>,
195 ) -> Vec<Similarity> {
196 let mut sims = vec![];
197
198 if let Some(ref inputs) = self.inputs {
199 inputs.iter().enumerate().for_each(|(idx, q)| {
200 if let Some(i) = decl.inputs.get(idx) {
201 sims.append(&mut q.compare(i, krate, generics, substs))
202 }
203 });
204
205 if inputs.len() != decl.inputs.len() {
206 let abs_diff =
208 max(inputs.len(), decl.inputs.len()) - min(inputs.len(), decl.inputs.len());
209 sims.append(&mut vec![Discrete(Different); abs_diff])
210 } else if inputs.is_empty() && decl.inputs.is_empty() {
211 sims.push(Discrete(Equivalent));
212 }
213 }
214 trace!(?sims);
215
216 if let Some(ref output) = self.output {
217 sims.append(&mut output.compare(&decl.output, krate, generics, substs));
218 }
219 trace!(?sims);
220
221 sims
222 }
223}
224
225impl Compare<(String, types::Type)> for Argument {
226 #[instrument(skip(krate))]
227 fn compare(
228 &self,
229 arg: &(String, types::Type),
230 krate: &types::Crate,
231 generics: &mut types::Generics,
232 substs: &mut HashMap<String, Type>,
233 ) -> Vec<Similarity> {
234 let mut sims = vec![];
235
236 if let Some(ref name) = self.name {
237 sims.append(&mut name.compare(&arg.0, krate, generics, substs));
238 }
239 trace!(?sims);
240
241 if let Some(ref type_) = self.ty {
242 sims.append(&mut type_.compare(&arg.1, krate, generics, substs));
243 }
244 trace!(?sims);
245
246 sims
247 }
248}
249
250impl Compare<Option<types::Type>> for FnRetTy {
251 #[instrument(skip(krate))]
252 fn compare(
253 &self,
254 ret_ty: &Option<types::Type>,
255 krate: &types::Crate,
256 generics: &mut types::Generics,
257 substs: &mut HashMap<String, Type>,
258 ) -> Vec<Similarity> {
259 match (self, ret_ty) {
260 (FnRetTy::Return(q), Some(i)) => q.compare(i, krate, generics, substs),
261 (FnRetTy::DefaultReturn, None) => vec![Discrete(Equivalent)],
262 _ => vec![Discrete(Different)],
263 }
264 }
265}
266
267fn compare_type(
268 lhs: &Type,
269 rhs: &types::Type,
270 krate: &types::Crate,
271 generics: &mut types::Generics,
272 substs: &mut HashMap<String, Type>,
273 allow_recursion: bool,
274) -> Vec<Similarity> {
275 use {crate::query::Type::*, types::Type};
276
277 match (lhs, rhs) {
278 (q, Type::Generic(i)) if i == "Self" => {
279 let mut i = None;
280 for where_predicate in &generics.where_predicates {
281 if let types::WherePredicate::EqPredicate {
282 lhs: Type::Generic(lhs),
283 rhs,
284 } = where_predicate
285 {
286 if lhs == "Self" {
287 i = Some(rhs).cloned();
288 break;
289 }
290 }
291 }
292 let i = &i.unwrap(); q.compare(i, krate, generics, substs)
294 }
295 (q, Type::Generic(i)) => match substs.get(i) {
296 Some(i) => {
297 if q == i {
298 vec![Discrete(Equivalent)]
299 } else {
300 vec![Discrete(Different)]
301 }
302 }
303 None => {
304 substs.insert(i.clone(), q.clone());
305 vec![Discrete(Subequal)]
306 }
307 },
308 (q, Type::ResolvedPath { id, .. })
309 if krate
310 .index
311 .get(id)
312 .map(|i| matches!(i.inner, types::ItemEnum::Typedef(_)))
313 .unwrap_or(false)
314 && allow_recursion =>
315 {
316 let sims_typedef = compare_type(lhs, rhs, krate, generics, substs, false);
317 if let Some(types::Item {
318 inner: types::ItemEnum::Typedef(types::Typedef { type_: ref i, .. }),
319 ..
320 }) = krate.index.get(id)
321 {
322 let sims_adt = q.compare(i, krate, generics, substs);
324 let sum =
325 |sims: &Vec<Similarity>| -> f32 { sims.iter().map(Similarity::score).sum() };
326 if sum(&sims_adt) < sum(&sims_typedef) {
327 return sims_adt;
328 }
329 }
330 sims_typedef
331 }
332 (Tuple(q), Type::Tuple(i)) => {
333 let mut sims = q
334 .iter()
335 .zip(i.iter())
336 .filter_map(|(q, i)| q.as_ref().map(|q| q.compare(i, krate, generics, substs)))
337 .flatten()
338 .collect::<Vec<_>>();
339
340 sims.push(Discrete(Equivalent));
342
343 let abs_diff = max(q.len(), i.len()) - min(q.len(), i.len());
345 sims.append(&mut vec![Discrete(Different); abs_diff]);
346
347 sims
348 }
349 (Slice(q), Type::Slice(i)) => {
350 let mut sims = vec![Discrete(Equivalent)];
352
353 if let Some(q) = q {
354 sims.append(&mut q.compare(i, krate, generics, substs));
355 }
356
357 sims
358 }
359 (
360 RawPointer {
361 mutable: q_mut,
362 type_: q,
363 },
364 Type::RawPointer {
365 mutable: i_mut,
366 type_: i,
367 },
368 )
369 | (
370 BorrowedRef {
371 mutable: q_mut,
372 type_: q,
373 },
374 Type::BorrowedRef {
375 mutable: i_mut,
376 type_: i,
377 ..
378 },
379 ) => {
380 if q_mut == i_mut {
381 q.compare(i, krate, generics, substs)
382 } else {
383 let mut sims = q.compare(i, krate, generics, substs);
384 sims.push(Discrete(Subequal));
385 sims
386 }
387 }
388 (q, Type::RawPointer { type_: i, .. } | Type::BorrowedRef { type_: i, .. }) => {
389 let mut sims = q.compare(i, krate, generics, substs);
390 sims.push(Discrete(Subequal));
391 sims
392 }
393 (RawPointer { type_: q, .. } | BorrowedRef { type_: q, .. }, i) => {
394 let mut sims = q.compare(i, krate, generics, substs);
395 sims.push(Discrete(Subequal));
396 sims
397 }
398 (
399 UnresolvedPath {
400 name: q,
401 args: q_args,
402 },
403 Type::ResolvedPath {
404 name: i,
405 args: i_args,
406 ..
407 },
408 ) => {
409 let mut sims = q.compare(i, krate, generics, substs);
410
411 match (q_args, i_args) {
412 (Some(q), Some(i)) => match (&**q, &**i) {
413 (
414 GenericArgs::AngleBracketed { args: ref q },
415 types::GenericArgs::AngleBracketed { args: ref i, .. },
416 ) => {
417 let q = q.iter().map(|q| {
418 q.as_ref().map(|q| match q {
419 GenericArg::Type(q) => q,
420 })
421 });
422 let i = i.iter().map(|i| match i {
423 types::GenericArg::Type(t) => Some(t),
424 _ => None,
425 });
426 q.zip(i).for_each(|(q, i)| match (q, i) {
427 (Some(q), Some(i)) => {
428 sims.append(&mut q.compare(i, krate, generics, substs))
429 }
430 (Some(_), None) => sims.push(Discrete(Different)),
431 (None, _) => {}
432 });
433 }
434 (_, _) => {}
436 },
437 (Some(q), None) => {
438 let GenericArgs::AngleBracketed { args: ref q } = **q;
439 sims.append(&mut vec![Discrete(Different); q.len()])
440 }
441 (None, _) => {}
442 }
443
444 sims
445 }
446 (Primitive(q), Type::Primitive(i)) => q.compare(i, krate, generics, substs),
447 _ => vec![Discrete(Different)],
448 }
449}
450
451impl Compare<types::Type> for Type {
452 #[instrument(skip(krate))]
453 fn compare(
454 &self,
455 type_: &types::Type,
456 krate: &types::Crate,
457 generics: &mut types::Generics,
458 substs: &mut HashMap<String, Type>,
459 ) -> Vec<Similarity> {
460 compare_type(self, type_, krate, generics, substs, true)
461 }
462}
463
464impl Compare<String> for PrimitiveType {
465 #[instrument]
466 fn compare(
467 &self,
468 prim_ty: &String,
469 _: &types::Crate,
470 _: &mut types::Generics,
471 _: &mut HashMap<String, Type>,
472 ) -> Vec<Similarity> {
473 if self.as_str() == prim_ty {
474 vec![Discrete(Equivalent)]
475 } else {
476 vec![Discrete(Different)]
477 }
478 }
479}