diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 84d684e0c95f9..c3b1e3eb6c087 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -144,7 +144,7 @@ pub(crate) struct IndexItem { } /// A type used for the search index. -#[derive(Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq)] struct RenderType { id: Option, generics: Option>, @@ -301,7 +301,7 @@ impl RenderTypeId { } /// Full type of functions/methods in the search index. -#[derive(Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq)] pub(crate) struct IndexItemFunctionType { inputs: Vec, output: Vec, diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 253d90294687e..67a88b1d2c57c 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -1,9 +1,13 @@ pub(crate) mod encode; +mod serde; use std::collections::BTreeSet; use std::collections::hash_map::Entry; use std::path::Path; +use ::serde::de::{self, Deserializer, Error as _}; +use ::serde::ser::{SerializeSeq, Serializer}; +use ::serde::{Deserialize, Serialize}; use rustc_ast::join_path_syms; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_hir::attrs::AttributeKind; @@ -12,9 +16,6 @@ use rustc_middle::ty::TyCtxt; use rustc_span::def_id::DefId; use rustc_span::sym; use rustc_span::symbol::{Symbol, kw}; -use serde::de::{self, Deserializer, Error as _}; -use serde::ser::{SerializeSeq, Serializer}; -use serde::{Deserialize, Serialize}; use stringdex::internals as stringdex_internals; use thin_vec::ThinVec; use tracing::instrument; @@ -34,7 +35,7 @@ pub(crate) struct SerializedSearchIndex { path_data: Vec>, entry_data: Vec>, descs: Vec, - function_data: Vec>, + function_data: Vec>, alias_pointers: Vec>, // inverted index for concrete types and generics type_data: Vec>, @@ -61,7 +62,7 @@ impl SerializedSearchIndex { let mut path_data: Vec> = Vec::new(); let mut entry_data: Vec> = Vec::new(); let mut descs: Vec = Vec::new(); - let mut function_data: Vec> = Vec::new(); + let mut function_data: Vec> = Vec::new(); let mut type_data: Vec> = Vec::new(); let mut alias_pointers: Vec> = Vec::new(); @@ -207,7 +208,7 @@ impl SerializedSearchIndex { path_data: Option, entry_data: Option, desc: String, - function_data: Option, + function_data: Option, type_data: Option, alias_pointer: Option, ) -> usize { @@ -446,73 +447,62 @@ impl SerializedSearchIndex { ..other_entry_data.clone() }), other.descs[other_entryid].clone(), - other.function_data[other_entryid].as_ref().map(|function_data| FunctionData { - function_signature: { - let (mut func, _offset) = - IndexItemFunctionType::read_from_string_without_param_names( - function_data.function_signature.as_bytes(), - ); - fn map_fn_sig_item( - map_other_pathid_to_self_pathid: &mut Vec, - ty: &mut RenderType, - ) { - match ty.id { - None => {} - Some(RenderTypeId::Index(generic)) if generic < 0 => {} - Some(RenderTypeId::Index(id)) => { - let id = usize::try_from(id).unwrap(); - let id = map_other_pathid_to_self_pathid[id]; - assert!(id != !0); - ty.id = - Some(RenderTypeId::Index(isize::try_from(id).unwrap())); - } - _ => unreachable!(), + other.function_data[other_entryid].clone().map(|mut func| { + fn map_fn_sig_item( + map_other_pathid_to_self_pathid: &mut Vec, + ty: &mut RenderType, + ) { + match ty.id { + None => {} + Some(RenderTypeId::Index(generic)) if generic < 0 => {} + Some(RenderTypeId::Index(id)) => { + let id = usize::try_from(id).unwrap(); + let id = map_other_pathid_to_self_pathid[id]; + assert!(id != !0); + ty.id = Some(RenderTypeId::Index(isize::try_from(id).unwrap())); } - if let Some(generics) = &mut ty.generics { - for generic in generics { - map_fn_sig_item(map_other_pathid_to_self_pathid, generic); - } + _ => unreachable!(), + } + if let Some(generics) = &mut ty.generics { + for generic in generics { + map_fn_sig_item(map_other_pathid_to_self_pathid, generic); } - if let Some(bindings) = &mut ty.bindings { - for (param, constraints) in bindings { - *param = match *param { - param @ RenderTypeId::Index(generic) if generic < 0 => { - param - } - RenderTypeId::Index(id) => { - let id = usize::try_from(id).unwrap(); - let id = map_other_pathid_to_self_pathid[id]; - assert!(id != !0); - RenderTypeId::Index(isize::try_from(id).unwrap()) - } - _ => unreachable!(), - }; - for constraint in constraints { - map_fn_sig_item( - map_other_pathid_to_self_pathid, - constraint, - ); + } + if let Some(bindings) = &mut ty.bindings { + for (param, constraints) in bindings { + *param = match *param { + param @ RenderTypeId::Index(generic) if generic < 0 => { + param + } + RenderTypeId::Index(id) => { + let id = usize::try_from(id).unwrap(); + let id = map_other_pathid_to_self_pathid[id]; + assert!(id != !0); + RenderTypeId::Index(isize::try_from(id).unwrap()) } + _ => unreachable!(), + }; + for constraint in constraints { + map_fn_sig_item( + map_other_pathid_to_self_pathid, + constraint, + ); } } } - for input in &mut func.inputs { - map_fn_sig_item(&mut map_other_pathid_to_self_pathid, input); - } - for output in &mut func.output { - map_fn_sig_item(&mut map_other_pathid_to_self_pathid, output); - } - for clause in &mut func.where_clause { - for entry in clause { - map_fn_sig_item(&mut map_other_pathid_to_self_pathid, entry); - } + } + for input in &mut func.inputs { + map_fn_sig_item(&mut map_other_pathid_to_self_pathid, input); + } + for output in &mut func.output { + map_fn_sig_item(&mut map_other_pathid_to_self_pathid, output); + } + for clause in &mut func.where_clause { + for entry in clause { + map_fn_sig_item(&mut map_other_pathid_to_self_pathid, entry); } - let mut result = - String::with_capacity(function_data.function_signature.len()); - func.write_to_string_without_param_names(&mut result); - result - }, - param_names: function_data.param_names.clone(), + } + func }), other.type_data[other_entryid].as_ref().map(|type_data| TypeData { inverted_function_inputs_index: type_data @@ -626,69 +616,55 @@ impl SerializedSearchIndex { }, ), self.descs[id].clone(), - self.function_data[id].as_ref().map( - |FunctionData { function_signature, param_names }| FunctionData { - function_signature: { - let (mut func, _offset) = - IndexItemFunctionType::read_from_string_without_param_names( - function_signature.as_bytes(), - ); - fn map_fn_sig_item(map: &FxHashMap, ty: &mut RenderType) { - match ty.id { - None => {} - Some(RenderTypeId::Index(generic)) if generic < 0 => {} - Some(RenderTypeId::Index(id)) => { + self.function_data[id].clone().map(|mut func| { + fn map_fn_sig_item(map: &FxHashMap, ty: &mut RenderType) { + match ty.id { + None => {} + Some(RenderTypeId::Index(generic)) if generic < 0 => {} + Some(RenderTypeId::Index(id)) => { + let id = usize::try_from(id).unwrap(); + let id = *map.get(&id).unwrap(); + assert!(id != !0); + ty.id = Some(RenderTypeId::Index(isize::try_from(id).unwrap())); + } + _ => unreachable!(), + } + if let Some(generics) = &mut ty.generics { + for generic in generics { + map_fn_sig_item(map, generic); + } + } + if let Some(bindings) = &mut ty.bindings { + for (param, constraints) in bindings { + *param = match *param { + param @ RenderTypeId::Index(generic) if generic < 0 => param, + RenderTypeId::Index(id) => { let id = usize::try_from(id).unwrap(); let id = *map.get(&id).unwrap(); assert!(id != !0); - ty.id = - Some(RenderTypeId::Index(isize::try_from(id).unwrap())); + RenderTypeId::Index(isize::try_from(id).unwrap()) } _ => unreachable!(), + }; + for constraint in constraints { + map_fn_sig_item(map, constraint); } - if let Some(generics) = &mut ty.generics { - for generic in generics { - map_fn_sig_item(map, generic); - } - } - if let Some(bindings) = &mut ty.bindings { - for (param, constraints) in bindings { - *param = match *param { - param @ RenderTypeId::Index(generic) if generic < 0 => { - param - } - RenderTypeId::Index(id) => { - let id = usize::try_from(id).unwrap(); - let id = *map.get(&id).unwrap(); - assert!(id != !0); - RenderTypeId::Index(isize::try_from(id).unwrap()) - } - _ => unreachable!(), - }; - for constraint in constraints { - map_fn_sig_item(map, constraint); - } - } - } - } - for input in &mut func.inputs { - map_fn_sig_item(&map, input); - } - for output in &mut func.output { - map_fn_sig_item(&map, output); } - for clause in &mut func.where_clause { - for entry in clause { - map_fn_sig_item(&map, entry); - } - } - let mut result = String::with_capacity(function_signature.len()); - func.write_to_string_without_param_names(&mut result); - result - }, - param_names: param_names.clone(), - }, - ), + } + } + for input in &mut func.inputs { + map_fn_sig_item(&map, input); + } + for output in &mut func.output { + map_fn_sig_item(&map, output); + } + for clause in &mut func.where_clause { + for entry in clause { + map_fn_sig_item(&map, entry); + } + } + func + }), self.type_data[id].as_ref().map( |TypeData { search_unbox, @@ -1259,48 +1235,6 @@ impl<'de> Deserialize<'de> for SerializedOptional32 { } } -#[derive(Clone, Debug)] -pub struct FunctionData { - function_signature: String, - param_names: Vec, -} - -impl Serialize for FunctionData { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut seq = serializer.serialize_seq(None)?; - seq.serialize_element(&self.function_signature)?; - seq.serialize_element(&self.param_names)?; - seq.end() - } -} - -impl<'de> Deserialize<'de> for FunctionData { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - struct FunctionDataVisitor; - impl<'de> de::Visitor<'de> for FunctionDataVisitor { - type Value = FunctionData; - fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(formatter, "fn data") - } - fn visit_seq>(self, mut v: A) -> Result { - let function_signature: String = v - .next_element()? - .ok_or_else(|| A::Error::missing_field("function_signature"))?; - let param_names: Vec = - v.next_element()?.ok_or_else(|| A::Error::missing_field("param_names"))?; - Ok(FunctionData { function_signature, param_names }) - } - } - deserializer.deserialize_any(FunctionDataVisitor) - } -} - /// Builds the search index from the collected metadata pub(crate) fn build_index( krate: &clean::Crate, @@ -1927,18 +1861,7 @@ pub(crate) fn build_index( // because the postings list has to fill in an empty array for each // unoccupied size. if item.ty.is_fn_like() { 0 } else { 16 }; - serialized_index.function_data[new_entry_id] = Some(FunctionData { - function_signature: { - let mut function_signature = String::new(); - search_type.write_to_string_without_param_names(&mut function_signature); - function_signature - }, - param_names: search_type - .param_names - .iter() - .map(|sym| sym.map(|sym| sym.to_string()).unwrap_or(String::new())) - .collect::>(), - }); + serialized_index.function_data[new_entry_id] = Some(search_type.clone()); for index in used_in_function_inputs { let postings = if index >= 0 { assert!(serialized_index.path_data[index as usize].is_some()); diff --git a/src/librustdoc/html/render/search_index/serde.rs b/src/librustdoc/html/render/search_index/serde.rs new file mode 100644 index 0000000000000..2ba91a56031d5 --- /dev/null +++ b/src/librustdoc/html/render/search_index/serde.rs @@ -0,0 +1,102 @@ +use std::fmt::{self, Formatter}; + +use rustc_span::Symbol; +use serde::de::{self, SeqAccess}; +use serde::ser::SerializeSeq as _; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +use crate::html::render::IndexItemFunctionType; + +impl Serialize for IndexItemFunctionType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + struct ParamNames<'a>(&'a [Option]); + + impl<'a> Serialize for ParamNames<'a> { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.collect_seq( + self.0 + .iter() + .map(|symbol| symbol.as_ref().map(Symbol::as_str).unwrap_or_default()), + ) + } + } + + let mut seq = serializer.serialize_seq(Some(2))?; + + let mut fn_type = String::new(); + self.write_to_string_without_param_names(&mut fn_type); + seq.serialize_element(&fn_type)?; + + seq.serialize_element(&ParamNames(&self.param_names))?; + + seq.end() + } +} + +impl<'de> Deserialize<'de> for IndexItemFunctionType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + #[derive(Deserialize)] + struct Deserialized { + #[serde(deserialize_with = "function_signature")] + function_signature: IndexItemFunctionType, + #[serde(deserialize_with = "param_names")] + param_names: Vec>, + } + + fn function_signature<'de, D: Deserializer<'de>>( + deserializer: D, + ) -> Result { + String::deserialize(deserializer).map(|sig| { + IndexItemFunctionType::read_from_string_without_param_names(sig.as_bytes()).0 + }) + } + + fn param_names<'de, D: Deserializer<'de>>( + deserializer: D, + ) -> Result>, D::Error> { + struct Visitor; + + impl<'de> de::Visitor<'de> for Visitor { + type Value = Vec>; + + fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_str("seq of param names") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let mut param_names = Vec::with_capacity(seq.size_hint().unwrap_or_default()); + + while let Some(symbol) = seq.next_element::()? { + param_names.push(if symbol.is_empty() { + None + } else { + Some(Symbol::intern(&symbol)) + }); + } + + Ok(param_names) + } + } + + deserializer.deserialize_seq(Visitor) + } + + let Deserialized { mut function_signature, param_names } = + Deserialized::deserialize(deserializer)?; + function_signature.param_names = param_names; + + Ok(function_signature) + } +}