}
}
+impl Clean<TypeKind> for hir::def::DefKind {
+ fn clean(&self, _: &DocContext<'_>) -> TypeKind {
+ match *self {
+ hir::def::DefKind::Mod => TypeKind::Module,
+ hir::def::DefKind::Struct => TypeKind::Struct,
+ hir::def::DefKind::Union => TypeKind::Union,
+ hir::def::DefKind::Enum => TypeKind::Enum,
+ hir::def::DefKind::Trait => TypeKind::Trait,
+ hir::def::DefKind::TyAlias => TypeKind::Typedef,
+ hir::def::DefKind::ForeignTy => TypeKind::Foreign,
+ hir::def::DefKind::TraitAlias => TypeKind::TraitAlias,
+ hir::def::DefKind::Fn => TypeKind::Function,
+ hir::def::DefKind::Const => TypeKind::Const,
+ hir::def::DefKind::Static => TypeKind::Static,
+ hir::def::DefKind::Macro(_) => TypeKind::Macro,
+ _ => TypeKind::Foreign,
+ }
+ }
+}
+
impl Clean<Item> for hir::TraitItem<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Item {
let inner = match self.kind {
pub decl: FnDecl,
pub header: hir::FnHeader,
pub defaultness: Option<hir::Defaultness>,
- pub all_types: Vec<Type>,
- pub ret_types: Vec<Type>,
+ pub all_types: Vec<(Type, TypeKind)>,
+ pub ret_types: Vec<(Type, TypeKind)>,
}
#[derive(Clone, Debug)]
pub header: hir::FnHeader,
pub decl: FnDecl,
pub generics: Generics,
- pub all_types: Vec<Type>,
- pub ret_types: Vec<Type>,
+ pub all_types: Vec<(Type, TypeKind)>,
+ pub ret_types: Vec<(Type, TypeKind)>,
}
#[derive(Clone, Debug)]
pub decl: FnDecl,
pub generics: Generics,
pub header: hir::FnHeader,
- pub all_types: Vec<Type>,
- pub ret_types: Vec<Type>,
+ pub all_types: Vec<(Type, TypeKind)>,
+ pub ret_types: Vec<(Type, TypeKind)>,
}
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
Never,
}
-#[derive(Clone, Copy, Debug)]
+#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)]
pub enum TypeKind {
Enum,
Function,
arg: &Type,
cx: &DocContext<'_>,
recurse: i32,
-) -> FxHashSet<Type> {
+) -> FxHashSet<(Type, TypeKind)> {
let arg_s = arg.print().to_string();
let mut res = FxHashSet::default();
if recurse >= 10 {
if !adds.is_empty() {
res.extend(adds);
} else if !ty.is_full_generic() {
- res.insert(ty);
+ if let Some(did) = ty.def_id() {
+ if let Some(kind) = cx.tcx.def_kind(did).clean(cx) {
+ res.insert((ty, kind));
+ }
+ }
}
}
}
if !adds.is_empty() {
res.extend(adds);
} else if !ty.is_full_generic() {
- res.insert(ty.clone());
+ if let Some(did) = ty.def_id() {
+ if let Some(kind) = cx.tcx.def_kind(did).clean(cx) {
+ res.insert((ty.clone(), kind));
+ }
+ }
}
}
}
}
} else {
- res.insert(arg.clone());
+ if let Some(did) = arg.def_id() {
+ if let Some(kind) = cx.tcx.def_kind(did).clean(cx) {
+ res.insert((arg.clone(), kind));
+ }
+ }
if let Some(gens) = arg.generics() {
for gen in gens.iter() {
if gen.is_full_generic() {
if !adds.is_empty() {
res.extend(adds);
}
- } else {
- res.insert(gen.clone());
+ } else if let Some(did) = gen.def_id() {
+ if let Some(kind) = cx.tcx.def_kind(did).clean(cx) {
+ res.insert((gen.clone(), kind));
+ }
}
}
}
generics: &Generics,
decl: &FnDecl,
cx: &DocContext<'_>,
-) -> (Vec<Type>, Vec<Type>) {
+) -> (Vec<(Type, TypeKind)>, Vec<(Type, TypeKind)>) {
let mut all_types = FxHashSet::default();
for arg in decl.inputs.values.iter() {
if arg.type_.is_self_type() {
if !args.is_empty() {
all_types.extend(args);
} else {
- all_types.insert(arg.type_.clone());
+ if let Some(did) = arg.type_.def_id() {
+ if let Some(kind) = cx.tcx.def_kind(did).clean(cx) {
+ all_types.insert((arg.type_.clone(), kind));
+ }
+ }
}
}
FnRetTy::Return(ref return_type) => {
let mut ret = get_real_types(generics, &return_type, cx, 0);
if ret.is_empty() {
- ret.insert(return_type.clone());
+ if let Some(did) = return_type.def_id() {
+ if let Some(kind) = cx.tcx.def_kind(did).clean(cx) {
+ ret.insert((return_type.clone(), kind));
+ }
+ }
}
ret.into_iter().collect()
}
use serde::ser::SerializeSeq;
use serde::{Serialize, Serializer};
-use crate::clean::{self, AttributesExt, Deprecation, GetDefId, SelfTy};
+use crate::clean::{self, AttributesExt, Deprecation, GetDefId, SelfTy, TypeKind};
use crate::config::{OutputFormat, RenderOptions};
use crate::docfs::{DocFS, ErrorStorage, PathError};
use crate::doctree;
/// A type used for the search index.
#[derive(Debug)]
struct Type {
+ ty: Option<DefId>,
+ idx: Option<usize>,
name: Option<String>,
- generics: Option<Vec<String>>,
+ generics: Option<Vec<Generic>>,
}
impl Serialize for Type {
{
if let Some(name) = &self.name {
let mut seq = serializer.serialize_seq(None)?;
- seq.serialize_element(&name)?;
+ if let Some(id) = self.idx {
+ seq.serialize_element(&id)?;
+ } else {
+ seq.serialize_element(&name)?;
+ }
if let Some(generics) = &self.generics {
seq.serialize_element(&generics)?;
}
}
}
+/// A type used for the search index.
+#[derive(Debug)]
+struct Generic {
+ name: String,
+ defid: Option<DefId>,
+ idx: Option<usize>,
+}
+
+impl Serialize for Generic {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ if let Some(id) = self.idx {
+ serializer.serialize_some(&id)
+ } else {
+ serializer.serialize_some(&self.name)
+ }
+ }
+}
+
/// Full type of functions/methods in the search index.
#[derive(Debug)]
struct IndexItemFunctionType {
- inputs: Vec<Type>,
- output: Option<Vec<Type>>,
+ inputs: Vec<TypeWithKind>,
+ output: Option<Vec<TypeWithKind>>,
}
impl Serialize for IndexItemFunctionType {
// If we couldn't figure out a type, just write `null`.
let mut iter = self.inputs.iter();
if match self.output {
- Some(ref output) => iter.chain(output.iter()).any(|ref i| i.name.is_none()),
- None => iter.any(|ref i| i.name.is_none()),
+ Some(ref output) => iter.chain(output.iter()).any(|ref i| i.ty.name.is_none()),
+ None => iter.any(|ref i| i.ty.name.is_none()),
} {
serializer.serialize_none()
} else {
}
}
+#[derive(Debug)]
+pub struct TypeWithKind {
+ ty: Type,
+ kind: TypeKind,
+}
+
+impl From<(Type, TypeKind)> for TypeWithKind {
+ fn from(x: (Type, TypeKind)) -> TypeWithKind {
+ TypeWithKind {
+ ty: x.0,
+ kind: x.1,
+ }
+ }
+}
+
+impl Serialize for TypeWithKind {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ let mut seq = serializer.serialize_seq(None)?;
+ seq.serialize_element(&self.ty.name)?;
+ let x: ItemType = self.kind.into();
+ seq.serialize_element(&x)?;
+ seq.end()
+ }
+}
+
thread_local!(static CACHE_KEY: RefCell<Arc<Cache>> = Default::default());
thread_local!(pub static CURRENT_DEPTH: Cell<usize> = Cell::new(0));
use serde::Serialize;
use super::{plain_summary_line, shorten, Impl, IndexItem, IndexItemFunctionType, ItemType};
-use super::{RenderInfo, Type};
+use super::{Generic, RenderInfo, Type, TypeWithKind};
/// Indicates where an external crate can be found.
pub enum ExternalLocation {
let mut lastpathid = 0usize;
for item in search_index {
- item.parent_idx = item.parent.map(|defid| {
- if defid_to_pathid.contains_key(&defid) {
- *defid_to_pathid.get(&defid).expect("no pathid")
- } else {
- let pathid = lastpathid;
- defid_to_pathid.insert(defid, pathid);
- lastpathid += 1;
+ item.parent_idx = item.parent.and_then(|defid| {
+ if defid_to_pathid.contains_key(&defid) {
+ defid_to_pathid.get(&defid).map(|x| *x)
+ } else {
+ let pathid = lastpathid;
+ defid_to_pathid.insert(defid, pathid);
+ lastpathid += 1;
- let &(ref fqp, short) = paths.get(&defid).unwrap();
+ if let Some(&(ref fqp, short)) = paths.get(&defid) {
crate_paths.push((short, fqp.last().unwrap().clone()));
- pathid
+ Some(pathid)
+ } else {
+ None
}
- });
+ }
+ });
// Omit the parent path if it is same to that of the prior item.
if lastpath == item.path {
_ => return None,
};
- let inputs =
- all_types.iter().map(|arg| get_index_type(&arg)).filter(|a| a.name.is_some()).collect();
+ let inputs = all_types
+ .iter()
+ .map(|(ty, kind)| TypeWithKind::from((get_index_type(&ty), *kind)))
+ .filter(|a| a.ty.name.is_some())
+ .collect();
let output = ret_types
.iter()
- .map(|arg| get_index_type(&arg))
- .filter(|a| a.name.is_some())
+ .map(|(ty, kind)| TypeWithKind::from((get_index_type(&ty), *kind)))
+ .filter(|a| a.ty.name.is_some())
.collect::<Vec<_>>();
let output = if output.is_empty() { None } else { Some(output) };
fn get_index_type(clean_type: &clean::Type) -> Type {
let t = Type {
+ ty: clean_type.def_id(),
+ idx: None,
name: get_index_type_name(clean_type, true).map(|s| s.to_ascii_lowercase()),
generics: get_generics(clean_type),
};
}
}
-fn get_generics(clean_type: &clean::Type) -> Option<Vec<String>> {
+fn get_generics(clean_type: &clean::Type) -> Option<Vec<Generic>> {
clean_type.generics().and_then(|types| {
let r = types
.iter()
- .filter_map(|t| get_index_type_name(t, false))
- .map(|s| s.to_ascii_lowercase())
+ .filter_map(|t| if let Some(name) = get_index_type_name(t, false) {
+ Some(Generic { name: name.to_ascii_lowercase(), defid: t.def_id(), idx: None })
+ } else {
+ None
+ })
.collect::<Vec<_>>();
if r.is_empty() { None } else { Some(r) }
})
}
function initSearch(rawSearchIndex) {
- var currentResults, index, searchIndex;
var MAX_LEV_DISTANCE = 3;
var MAX_RESULTS = 200;
var GENERICS_DATA = 1;
var NAME = 0;
var INPUTS_DATA = 0;
var OUTPUT_DATA = 1;
+ var NO_TYPE_FILTER = -1;
+ var currentResults, index, searchIndex;
var params = getQueryStringParams();
// Populate search bar with query string search term when provided,
return i;
}
}
- return -1;
+ return NO_TYPE_FILTER;
}
var valLower = query.query.toLowerCase(),
};
}
+ function getObjectFromId(id) {
+ if (typeof id === "number") {
+ return searchIndex[id];
+ }
+ return {'name': id};
+ }
+
function checkGenerics(obj, val) {
// The names match, but we need to be sure that all generics kinda
// match as well.
for (var y = 0; y < vlength; ++y) {
var lev = { pos: -1, lev: MAX_LEV_DISTANCE + 1};
var elength = elems.length;
+ var firstGeneric = getObjectFromId(val.generics[y]).name;
for (var x = 0; x < elength; ++x) {
- var tmp_lev = levenshtein(elems[x], val.generics[y]);
+ var tmp_lev = levenshtein(getObjectFromId(elems[x]).name,
+ firstGeneric);
if (tmp_lev < lev.lev) {
lev.lev = tmp_lev;
lev.pos = x;
for (var y = 0; allFound === true && y < val.generics.length; ++y) {
allFound = false;
+ var firstGeneric = getObjectFromId(val.generics[y]).name;
for (x = 0; allFound === false && x < elems.length; ++x) {
- allFound = elems[x] === val.generics[y];
+ allFound = getObjectFromId(elems[x]).name === firstGeneric;
}
if (allFound === true) {
elems.splice(x - 1, 1);
return lev_distance + 1;
}
- function findArg(obj, val, literalSearch) {
+ function findArg(obj, val, literalSearch, typeFilter) {
var lev_distance = MAX_LEV_DISTANCE + 1;
- if (obj && obj.type && obj.type[INPUTS_DATA] &&
- obj.type[INPUTS_DATA].length > 0) {
+ if (obj && obj.type && obj.type[INPUTS_DATA] && obj.type[INPUTS_DATA].length > 0) {
var length = obj.type[INPUTS_DATA].length;
for (var i = 0; i < length; i++) {
- var tmp = checkType(obj.type[INPUTS_DATA][i], val, literalSearch);
- if (literalSearch === true && tmp === true) {
- return true;
+ var tmp = obj.type[INPUTS_DATA][i];
+ if (typePassesFilter(typeFilter, tmp[1]) === false) {
+ continue;
+ }
+ tmp[0] = tmp[NAME];
+ var tmp = checkType(tmp, val, literalSearch);
+ if (literalSearch === true) {
+ if (tmp === true) {
+ return true;
+ }
+ continue;
}
lev_distance = Math.min(tmp, lev_distance);
if (lev_distance === 0) {
return literalSearch === true ? false : lev_distance;
}
- function checkReturned(obj, val, literalSearch) {
+ function checkReturned(obj, val, literalSearch, typeFilter) {
var lev_distance = MAX_LEV_DISTANCE + 1;
if (obj && obj.type && obj.type.length > OUTPUT_DATA) {
var ret = obj.type[OUTPUT_DATA];
- if (!obj.type[OUTPUT_DATA].length) {
+ if (typeof ret[0] === "string") {
ret = [ret];
}
for (var x = 0; x < ret.length; ++x) {
var r = ret[x];
- if (typeof r === "string") {
- r = [r];
+ if (typePassesFilter(typeFilter, r[1]) === false) {
+ continue;
}
+ r[0] = r[NAME];
var tmp = checkType(r, val, literalSearch);
if (literalSearch === true) {
if (tmp === true) {
function typePassesFilter(filter, type) {
// No filter
- if (filter < 0) return true;
+ if (filter <= NO_TYPE_FILTER) return true;
// Exact match
if (filter === type) return true;
var name = itemTypes[type];
switch (itemTypes[filter]) {
case "constant":
- return (name == "associatedconstant");
+ return name === "associatedconstant";
case "fn":
- return (name == "method" || name == "tymethod");
+ return name === "method" || name === "tymethod";
case "type":
- return (name == "primitive" || name == "keyword");
+ return name === "primitive" || name === "associatedtype";
+ case "trait":
+ return name === "traitalias";
}
// No match
if (filterCrates !== undefined && searchIndex[i].crate !== filterCrates) {
continue;
}
- in_args = findArg(searchIndex[i], val, true);
- returned = checkReturned(searchIndex[i], val, true);
+ in_args = findArg(searchIndex[i], val, true, typeFilter);
+ returned = checkReturned(searchIndex[i], val, true, typeFilter);
ty = searchIndex[i];
fullId = generateId(ty);
- if (searchWords[i] === val.name) {
- // filter type: ... queries
- if (typePassesFilter(typeFilter, searchIndex[i].ty) &&
- results[fullId] === undefined)
- {
- results[fullId] = {id: i, index: -1};
- }
- } else if ((in_args === true || returned === true) &&
- typePassesFilter(typeFilter, searchIndex[i].ty)) {
- if (in_args === true || returned === true) {
- if (in_args === true) {
- results_in_args[fullId] = {
- id: i,
- index: -1,
- dontValidate: true,
- };
- }
- if (returned === true) {
- results_returned[fullId] = {
- id: i,
- index: -1,
- dontValidate: true,
- };
- }
- } else {
- results[fullId] = {
- id: i,
- index: -1,
- dontValidate: true,
- };
- }
+ if (searchWords[i] === val.name
+ && typePassesFilter(typeFilter, searchIndex[i].ty)
+ && results[fullId] === undefined) {
+ results[fullId] = {
+ id: i,
+ index: -1,
+ dontValidate: true,
+ };
+ }
+ if (in_args === true && results_in_args[fullId] === undefined) {
+ results_in_args[fullId] = {
+ id: i,
+ index: -1,
+ dontValidate: true,
+ };
+ }
+ if (returned === true && results_returned[fullId] === undefined) {
+ results_returned[fullId] = {
+ id: i,
+ index: -1,
+ dontValidate: true,
+ };
}
}
query.inputs = [val];
// allow searching for void (no output) functions as well
var typeOutput = type.length > OUTPUT_DATA ? type[OUTPUT_DATA].name : "";
- returned = checkReturned(ty, output, true);
+ returned = checkReturned(ty, output, true, NO_TYPE_FILTER);
if (output.name === "*" || returned === true) {
in_args = false;
var is_module = false;
lev += 1;
}
}
- if ((in_args = findArg(ty, valGenerics)) <= MAX_LEV_DISTANCE) {
- if (typePassesFilter(typeFilter, ty.ty) === false) {
- in_args = MAX_LEV_DISTANCE + 1;
- }
- }
- if ((returned = checkReturned(ty, valGenerics)) <= MAX_LEV_DISTANCE) {
- if (typePassesFilter(typeFilter, ty.ty) === false) {
- returned = MAX_LEV_DISTANCE + 1;
- }
- }
+ in_args = findArg(ty, valGenerics, false, typeFilter);
+ returned = checkReturned(ty, valGenerics, false, typeFilter);
lev += lev_add;
if (lev > 0 && val.length > 3 && searchWords[j].indexOf(val) > -1) {
--- /dev/null
+const QUERY = 'struct:chunksmut';
+
+const EXPECTED = {
+ 'returned': [
+ { 'path': 'std::slice::chunks_mut', 'name': 'chunks_mut' },
+ ],
+};