rustdoc: sort stable items first

This commit is contained in:
binarycat 2025-11-29 12:04:31 -06:00
parent a234ae6b65
commit dca86a9521
11 changed files with 58 additions and 4 deletions

View file

@ -431,6 +431,10 @@ impl Item {
self.deprecation(tcx).is_some_and(|deprecation| deprecation.is_in_effect()) self.deprecation(tcx).is_some_and(|deprecation| deprecation.is_in_effect())
} }
pub(crate) fn is_unstable(&self) -> bool {
self.stability.is_some_and(|x| x.is_unstable())
}
pub(crate) fn inner_docs(&self, tcx: TyCtxt<'_>) -> bool { pub(crate) fn inner_docs(&self, tcx: TyCtxt<'_>) -> bool {
self.item_id.as_def_id().map(|did| inner_docs(tcx.get_all_attrs(did))).unwrap_or(false) self.item_id.as_def_id().map(|did| inner_docs(tcx.get_all_attrs(did))).unwrap_or(false)
} }

View file

@ -594,6 +594,7 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It
); );
let aliases = item.attrs.get_doc_aliases(); let aliases = item.attrs.get_doc_aliases();
let is_deprecated = item.is_deprecated(tcx); let is_deprecated = item.is_deprecated(tcx);
let is_unstable = item.is_unstable();
let index_item = IndexItem { let index_item = IndexItem {
ty: item.type_(), ty: item.type_(),
defid: Some(defid), defid: Some(defid),
@ -609,6 +610,7 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It
search_type, search_type,
aliases, aliases,
is_deprecated, is_deprecated,
is_unstable,
}; };
cache.search_index.push(index_item); cache.search_index.push(index_item);

View file

@ -142,6 +142,7 @@ pub(crate) struct IndexItem {
pub(crate) search_type: Option<IndexItemFunctionType>, pub(crate) search_type: Option<IndexItemFunctionType>,
pub(crate) aliases: Box<[Symbol]>, pub(crate) aliases: Box<[Symbol]>,
pub(crate) is_deprecated: bool, pub(crate) is_deprecated: bool,
pub(crate) is_unstable: bool,
} }
/// A type used for the search index. /// A type used for the search index.

View file

@ -616,6 +616,7 @@ impl SerializedSearchIndex {
parent, parent,
trait_parent, trait_parent,
deprecated, deprecated,
unstable,
associated_item_disambiguator, associated_item_disambiguator,
}| EntryData { }| EntryData {
krate: *map.get(krate).unwrap(), krate: *map.get(krate).unwrap(),
@ -626,6 +627,7 @@ impl SerializedSearchIndex {
parent: parent.and_then(|path_id| map.get(&path_id).copied()), parent: parent.and_then(|path_id| map.get(&path_id).copied()),
trait_parent: trait_parent.and_then(|path_id| map.get(&path_id).copied()), trait_parent: trait_parent.and_then(|path_id| map.get(&path_id).copied()),
deprecated: *deprecated, deprecated: *deprecated,
unstable: *unstable,
associated_item_disambiguator: associated_item_disambiguator.clone(), associated_item_disambiguator: associated_item_disambiguator.clone(),
}, },
), ),
@ -896,6 +898,7 @@ struct EntryData {
parent: Option<usize>, parent: Option<usize>,
trait_parent: Option<usize>, trait_parent: Option<usize>,
deprecated: bool, deprecated: bool,
unstable: bool,
associated_item_disambiguator: Option<String>, associated_item_disambiguator: Option<String>,
} }
@ -912,6 +915,7 @@ impl Serialize for EntryData {
seq.serialize_element(&self.parent.map(|id| id + 1).unwrap_or(0))?; seq.serialize_element(&self.parent.map(|id| id + 1).unwrap_or(0))?;
seq.serialize_element(&self.trait_parent.map(|id| id + 1).unwrap_or(0))?; seq.serialize_element(&self.trait_parent.map(|id| id + 1).unwrap_or(0))?;
seq.serialize_element(&if self.deprecated { 1 } else { 0 })?; seq.serialize_element(&if self.deprecated { 1 } else { 0 })?;
seq.serialize_element(&if self.unstable { 1 } else { 0 })?;
if let Some(disambig) = &self.associated_item_disambiguator { if let Some(disambig) = &self.associated_item_disambiguator {
seq.serialize_element(&disambig)?; seq.serialize_element(&disambig)?;
} }
@ -946,6 +950,7 @@ impl<'de> Deserialize<'de> for EntryData {
v.next_element()?.ok_or_else(|| A::Error::missing_field("trait_parent"))?; v.next_element()?.ok_or_else(|| A::Error::missing_field("trait_parent"))?;
let deprecated: u32 = v.next_element()?.unwrap_or(0); let deprecated: u32 = v.next_element()?.unwrap_or(0);
let unstable: u32 = v.next_element()?.unwrap_or(0);
let associated_item_disambiguator: Option<String> = v.next_element()?; let associated_item_disambiguator: Option<String> = v.next_element()?;
Ok(EntryData { Ok(EntryData {
krate, krate,
@ -956,6 +961,7 @@ impl<'de> Deserialize<'de> for EntryData {
parent: Option::<i32>::from(parent).map(|path| path as usize), parent: Option::<i32>::from(parent).map(|path| path as usize),
trait_parent: Option::<i32>::from(trait_parent).map(|path| path as usize), trait_parent: Option::<i32>::from(trait_parent).map(|path| path as usize),
deprecated: deprecated != 0, deprecated: deprecated != 0,
unstable: unstable != 0,
associated_item_disambiguator, associated_item_disambiguator,
}) })
} }
@ -1283,6 +1289,7 @@ pub(crate) fn build_index(
), ),
aliases: item.attrs.get_doc_aliases(), aliases: item.attrs.get_doc_aliases(),
is_deprecated: item.is_deprecated(tcx), is_deprecated: item.is_deprecated(tcx),
is_unstable: item.is_unstable(),
}); });
} }
} }
@ -1382,6 +1389,7 @@ pub(crate) fn build_index(
parent: None, parent: None,
trait_parent: None, trait_parent: None,
deprecated: false, deprecated: false,
unstable: false,
associated_item_disambiguator: None, associated_item_disambiguator: None,
}), }),
crate_doc, crate_doc,
@ -1520,6 +1528,7 @@ pub(crate) fn build_index(
module_path, module_path,
exact_module_path, exact_module_path,
deprecated: item.is_deprecated, deprecated: item.is_deprecated,
unstable: item.is_unstable,
associated_item_disambiguator: if let Some(impl_id) = item.impl_id associated_item_disambiguator: if let Some(impl_id) = item.impl_id
&& let Some(parent_idx) = item.parent_idx && let Some(parent_idx) = item.parent_idx
&& associated_item_duplicates && associated_item_duplicates

View file

@ -243,6 +243,7 @@ declare namespace rustdoc {
parent: number?, parent: number?,
traitParent: number?, traitParent: number?,
deprecated: boolean, deprecated: boolean,
unstable: boolean,
associatedItemDisambiguator: string?, associatedItemDisambiguator: string?,
} }
@ -292,6 +293,7 @@ declare namespace rustdoc {
path: PathData?, path: PathData?,
functionData: FunctionData?, functionData: FunctionData?,
deprecated: boolean, deprecated: boolean,
unstable: boolean,
parent: RowParent, parent: RowParent,
traitParent: RowParent, traitParent: RowParent,
} }

View file

@ -1633,6 +1633,7 @@ class DocSearch {
* parent, * parent,
* trait_parent, * trait_parent,
* deprecated, * deprecated,
* unstable,
* associated_item_disambiguator * associated_item_disambiguator
* @type {rustdoc.ArrayWithOptionals<[ * @type {rustdoc.ArrayWithOptionals<[
* number, * number,
@ -1642,6 +1643,7 @@ class DocSearch {
* number, * number,
* number, * number,
* number, * number,
* number,
* ], [string]>} * ], [string]>}
*/ */
const raw = JSON.parse(encoded); const raw = JSON.parse(encoded);
@ -1653,7 +1655,8 @@ class DocSearch {
parent: raw[4] === 0 ? null : raw[4] - 1, parent: raw[4] === 0 ? null : raw[4] - 1,
traitParent: raw[5] === 0 ? null : raw[5] - 1, traitParent: raw[5] === 0 ? null : raw[5] - 1,
deprecated: raw[6] === 1 ? true : false, deprecated: raw[6] === 1 ? true : false,
associatedItemDisambiguator: raw.length === 7 ? null : raw[7], unstable: raw[7] === 1 ? true : false,
associatedItemDisambiguator: raw.length === 8 ? null : raw[8],
}; };
} }
@ -1946,6 +1949,7 @@ class DocSearch {
path, path,
functionData, functionData,
deprecated: entry ? entry.deprecated : false, deprecated: entry ? entry.deprecated : false,
unstable: entry ? entry.unstable : false,
parent, parent,
traitParent, traitParent,
}; };
@ -2858,6 +2862,13 @@ class DocSearch {
return a - b; return a - b;
} }
// sort unstable items later
a = Number(aai.unstable);
b = Number(bbi.unstable);
if (a !== b) {
return a - b;
}
// sort by crate (current crate comes first) // sort by crate (current crate comes first)
a = Number(aai.crate !== preferredCrate); a = Number(aai.crate !== preferredCrate);
b = Number(bbi.crate !== preferredCrate); b = Number(bbi.crate !== preferredCrate);

View file

@ -3,9 +3,9 @@ const EXPECTED = [
{ {
'query': 'generic:T -> generic:U', 'query': 'generic:T -> generic:U',
'others': [ 'others': [
{ 'path': 'core::mem', 'name': 'transmute' },
{ 'path': 'core::intrinsics::simd', 'name': 'simd_as' }, { 'path': 'core::intrinsics::simd', 'name': 'simd_as' },
{ 'path': 'core::intrinsics::simd', 'name': 'simd_cast' }, { 'path': 'core::intrinsics::simd', 'name': 'simd_cast' },
{ 'path': 'core::mem', 'name': 'transmute' },
], ],
}, },
]; ];

View file

@ -6,9 +6,9 @@ const EXPECTED = [
// should-fail tag and the search query below: // should-fail tag and the search query below:
'query': 'generic:T -> generic:T', 'query': 'generic:T -> generic:T',
'others': [ 'others': [
{ 'path': 'std::mem', 'name': 'transmute' },
{ 'path': 'std::intrinsics::simd', 'name': 'simd_as' }, { 'path': 'std::intrinsics::simd', 'name': 'simd_as' },
{ 'path': 'std::intrinsics::simd', 'name': 'simd_cast' }, { 'path': 'std::intrinsics::simd', 'name': 'simd_cast' },
{ 'path': 'std::mem', 'name': 'transmute' },
], ],
}, },
]; ];

View file

@ -5,9 +5,9 @@ const EXPECTED = [
// should-fail tag and the search query below: // should-fail tag and the search query below:
'query': 'generic:T -> generic:U', 'query': 'generic:T -> generic:U',
'others': [ 'others': [
{ 'path': 'std::mem', 'name': 'transmute' },
{ 'path': 'std::intrinsics::simd', 'name': 'simd_as' }, { 'path': 'std::intrinsics::simd', 'name': 'simd_as' },
{ 'path': 'std::intrinsics::simd', 'name': 'simd_cast' }, { 'path': 'std::intrinsics::simd', 'name': 'simd_cast' },
{ 'path': 'std::mem', 'name': 'transmute' },
], ],
}, },
]; ];

View file

@ -0,0 +1,9 @@
const EXPECTED = [
{
'query': 'foo',
'others': [
{"path": "sort_stability::old", "name": "foo"},
{"path": "sort_stability::new", "name": "foo"},
],
},
];

View file

@ -0,0 +1,16 @@
#![feature(staged_api)]
#![stable(feature = "foo_lib", since = "1.0.0")]
#[stable(feature = "old_foo", since = "1.0.1")]
pub mod old {
/// Old, stable foo
#[stable(feature = "old_foo", since = "1.0.1")]
pub fn foo() {}
}
#[unstable(feature = "new_foo", issue = "none")]
pub mod new {
/// New, unstable foo
#[unstable(feature = "new_foo", issue = "none")]
pub fn foo() {}
}