From 209c069ce70e7b28e9b0679cd8570484397239c1 Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Tue, 21 May 2019 14:05:50 -0400 Subject: [PATCH] rustdoc: generate JSON via serde --- Cargo.lock | 2 + src/librustdoc/Cargo.toml | 2 + src/librustdoc/clean/cfg.rs | 2 +- src/librustdoc/clean/mod.rs | 111 ++++++----- src/librustdoc/doctree.rs | 2 +- src/librustdoc/html/format.rs | 3 - src/librustdoc/html/item_type.rs | 1 - src/librustdoc/html/render.rs | 304 ++++++++++++++++++------------- src/librustdoc/lib.rs | 3 - 9 files changed, 237 insertions(+), 193 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 403fe4101eb7a..b0111dd6d938c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3186,6 +3186,8 @@ dependencies = [ "minifier 0.0.30 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index b75212d606fa5..d385dfd1a5e99 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -11,5 +11,7 @@ path = "lib.rs" [dependencies] pulldown-cmark = { version = "0.5.2", default-features = false } minifier = "0.0.30" +serde = { version = "1.0.82", features = ["derive"] } +serde_json = "1.0.33" tempfile = "3" parking_lot = "0.7" diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 67113787915a3..ad211763a6c46 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -16,7 +16,7 @@ use syntax_pos::Span; use crate::html::escape::Escape; -#[derive(Clone, RustcEncodable, RustcDecodable, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum Cfg { /// Accepts all configurations. True, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 4becb42d30551..2cbcb365c92f5 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -223,7 +223,7 @@ impl<'a, 'tcx> Clean for visit_ast::RustdocVisitor<'a, 'tcx> { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct ExternalCrate { pub name: String, pub src: FileName, @@ -355,7 +355,7 @@ impl Clean for CrateNum { /// Anything with a source location and set of attributes and, optionally, a /// name. That is, anything that can be documented. This doesn't correspond /// directly to the AST's concept of an item; it's a strict superset. -#[derive(Clone, RustcEncodable, RustcDecodable)] +#[derive(Clone)] pub struct Item { /// Stringified span pub source: Span, @@ -528,7 +528,7 @@ impl Item { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub enum ItemEnum { ExternCrateItem(String, Option), ImportItem(Import), @@ -594,7 +594,7 @@ impl ItemEnum { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Module { pub items: Vec, pub is_crate: bool, @@ -731,7 +731,7 @@ impl> NestedAttributesExt for I { /// Included files are kept separate from inline doc comments so that proper line-number /// information can be given when a doctest fails. Sugared doc comments and "raw" doc comments are /// kept separate because of issue #42760. -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub enum DocFragment { /// A doc fragment created from a `///` or `//!` doc comment. SugaredDoc(usize, syntax_pos::Span, String), @@ -781,7 +781,7 @@ impl<'a> FromIterator<&'a DocFragment> for String { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug, Default)] +#[derive(Clone, Debug, Default)] pub struct Attributes { pub doc_strings: Vec, pub other_attrs: Vec, @@ -1048,7 +1048,7 @@ impl Clean for [ast::Attribute] { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub enum GenericBound { TraitBound(PolyTrait, hir::TraitBoundModifier), Outlives(Lifetime), @@ -1231,7 +1231,7 @@ impl<'tcx> Clean>> for InternalSubsts<'tcx> { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct Lifetime(String); impl Lifetime { @@ -1326,7 +1326,7 @@ impl Clean> for ty::RegionKind { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub enum WherePredicate { BoundPredicate { ty: Type, bounds: Vec }, RegionPredicate { lifetime: Lifetime, bounds: Vec }, @@ -1464,7 +1464,7 @@ impl<'tcx> Clean for ty::ProjectionTy<'tcx> { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub enum GenericParamDefKind { Lifetime, Type { @@ -1498,7 +1498,7 @@ impl GenericParamDefKind { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct GenericParamDef { pub name: String, @@ -1610,7 +1610,7 @@ impl Clean for hir::GenericParam { } // maybe use a Generic enum and use Vec? -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Default, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Default, Hash)] pub struct Generics { pub params: Vec, pub where_predicates: Vec, @@ -1874,7 +1874,7 @@ pub fn get_all_types( (all_types.into_iter().collect(), ret_types) } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Method { pub generics: Generics, pub decl: FnDecl, @@ -1902,7 +1902,7 @@ impl<'a> Clean for (&'a hir::MethodSig, &'a hir::Generics, hir::BodyId, } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct TyMethod { pub header: hir::FnHeader, pub decl: FnDecl, @@ -1911,7 +1911,7 @@ pub struct TyMethod { pub ret_types: Vec, } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Function { pub decl: FnDecl, pub generics: Generics, @@ -1952,7 +1952,7 @@ impl Clean for doctree::Function { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct FnDecl { pub inputs: Arguments, pub output: FunctionRetTy, @@ -1989,7 +1989,7 @@ impl FnDecl { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct Arguments { pub values: Vec, } @@ -2063,13 +2063,13 @@ impl<'tcx> Clean for (DefId, ty::PolyFnSig<'tcx>) { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct Argument { pub type_: Type, pub name: String, } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)] +#[derive(Clone, PartialEq, Debug)] pub enum SelfTy { SelfValue, SelfBorrowed(Option, Mutability), @@ -2093,7 +2093,7 @@ impl Argument { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub enum FunctionRetTy { Return(Type), DefaultReturn, @@ -2117,7 +2117,7 @@ impl GetDefId for FunctionRetTy { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Trait { pub auto: bool, pub unsafety: hir::Unsafety, @@ -2153,7 +2153,7 @@ impl Clean for doctree::Trait { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct TraitAlias { pub generics: Generics, pub bounds: Vec, @@ -2437,7 +2437,7 @@ impl Clean for ty::AssocItem { } /// A trait reference, which may have higher ranked lifetimes. -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct PolyTrait { pub trait_: Type, pub generic_params: Vec, @@ -2446,7 +2446,7 @@ pub struct PolyTrait { /// A representation of a type suitable for hyperlinking purposes. Ideally, one can get the original /// type out of the AST/`TyCtxt` given one of these, if more information is needed. Most /// importantly, it does not preserve mutability or boxes. -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub enum Type { /// Structs/enums/traits (most that would be an `hir::TyKind::Path`). ResolvedPath { @@ -2469,7 +2469,6 @@ pub enum Type { Array(Box, String), Never, CVarArgs, - Unique(Box), RawPointer(Mutability, Box), BorrowedRef { lifetime: Option, @@ -2491,7 +2490,7 @@ pub enum Type { ImplTrait(Vec), } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Copy, Debug)] +#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)] pub enum PrimitiveType { Isize, I8, I16, I32, I64, I128, Usize, U8, U16, U32, U64, U128, @@ -2510,7 +2509,7 @@ pub enum PrimitiveType { CVarArgs, } -#[derive(Clone, RustcEncodable, RustcDecodable, Copy, Debug)] +#[derive(Clone, Copy, Debug)] pub enum TypeKind { Enum, Function, @@ -2520,7 +2519,6 @@ pub enum TypeKind { Struct, Union, Trait, - Variant, Typedef, Foreign, Macro, @@ -3189,7 +3187,7 @@ impl Clean for ty::FieldDef { } } -#[derive(Clone, PartialEq, Eq, RustcDecodable, RustcEncodable, Debug)] +#[derive(Clone, PartialEq, Eq, Debug)] pub enum Visibility { Public, Inherited, @@ -3218,7 +3216,7 @@ impl Clean> for ty::Visibility { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Struct { pub struct_type: doctree::StructType, pub generics: Generics, @@ -3226,7 +3224,7 @@ pub struct Struct { pub fields_stripped: bool, } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Union { pub struct_type: doctree::StructType, pub generics: Generics, @@ -3277,7 +3275,7 @@ impl Clean for doctree::Union { /// This is a more limited form of the standard Struct, different in that /// it lacks the things most items have (name, id, parameterization). Found /// only as a variant in an enum. -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct VariantStruct { pub struct_type: doctree::StructType, pub fields: Vec, @@ -3294,7 +3292,7 @@ impl Clean for ::rustc::hir::VariantData { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Enum { pub variants: IndexVec, pub generics: Generics, @@ -3320,7 +3318,7 @@ impl Clean for doctree::Enum { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Variant { pub kind: VariantKind, } @@ -3383,7 +3381,7 @@ impl Clean for ty::VariantDef { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub enum VariantKind { CLike, Tuple(Vec), @@ -3401,7 +3399,7 @@ impl Clean for hir::VariantData { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Span { pub filename: FileName, pub loline: usize, @@ -3447,7 +3445,7 @@ impl Clean for syntax_pos::Span { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct Path { pub global: bool, pub res: Res, @@ -3470,7 +3468,7 @@ impl Clean for hir::Path { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub enum GenericArg { Lifetime(Lifetime), Type(Type), @@ -3487,7 +3485,7 @@ impl fmt::Display for GenericArg { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub enum GenericArgs { AngleBracketed { args: Vec, @@ -3527,7 +3525,7 @@ impl Clean for hir::GenericArgs { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct PathSegment { pub name: String, pub args: GenericArgs, @@ -3552,7 +3550,6 @@ fn strip_type(ty: Type) -> Type { } Type::Slice(inner_ty) => Type::Slice(Box::new(strip_type(*inner_ty))), Type::Array(inner_ty, s) => Type::Array(Box::new(strip_type(*inner_ty)), s), - Type::Unique(inner_ty) => Type::Unique(Box::new(strip_type(*inner_ty))), Type::RawPointer(m, inner_ty) => Type::RawPointer(m, Box::new(strip_type(*inner_ty))), Type::BorrowedRef { lifetime, mutability, type_ } => { Type::BorrowedRef { lifetime, mutability, type_: Box::new(strip_type(*type_)) } @@ -3624,7 +3621,7 @@ impl Clean for InternedString { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Typedef { pub type_: Type, pub generics: Generics, @@ -3648,7 +3645,7 @@ impl Clean for doctree::Typedef { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Existential { pub bounds: Vec, pub generics: Generics, @@ -3672,7 +3669,7 @@ impl Clean for doctree::Existential { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct BareFunctionDecl { pub unsafety: hir::Unsafety, pub generic_params: Vec, @@ -3694,7 +3691,7 @@ impl Clean for hir::BareFnTy { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Static { pub type_: Type, pub mutability: Mutability, @@ -3724,7 +3721,7 @@ impl Clean for doctree::Static { } } -#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, PartialEq, Eq, Hash, Debug)] pub struct Constant { pub type_: Type, pub expr: String, @@ -3748,7 +3745,7 @@ impl Clean for doctree::Constant { } } -#[derive(Debug, Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Copy, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Copy, Hash)] pub enum Mutability { Mutable, Immutable, @@ -3763,7 +3760,7 @@ impl Clean for hir::Mutability { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Copy, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Copy, Debug, Hash)] pub enum ImplPolarity { Positive, Negative, @@ -3778,7 +3775,7 @@ impl Clean for hir::ImplPolarity { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Impl { pub unsafety: hir::Unsafety, pub generics: Generics, @@ -4002,7 +3999,7 @@ impl Clean> for doctree::Import { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub enum Import { // use source as str; Simple(String, ImportSource), @@ -4010,7 +4007,7 @@ pub enum Import { Glob(ImportSource) } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct ImportSource { pub path: Path, pub did: Option, @@ -4239,7 +4236,7 @@ fn resolve_use_source(cx: &DocContext<'_>, path: Path) -> ImportSource { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Macro { pub source: String, pub imported_from: Option, @@ -4268,7 +4265,7 @@ impl Clean for doctree::Macro { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct ProcMacro { pub kind: MacroKind, pub helpers: Vec, @@ -4292,7 +4289,7 @@ impl Clean for doctree::ProcMacro { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Stability { pub level: stability::StabilityLevel, pub feature: Option, @@ -4302,7 +4299,7 @@ pub struct Stability { pub issue: Option, } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Deprecation { pub since: Option, pub note: Option, @@ -4352,13 +4349,13 @@ impl Clean for attr::Deprecation { /// An type binding on an associated type (e.g., `A = Bar` in `Foo` or /// `A: Send + Sync` in `Foo`). -#[derive(Clone, PartialEq, Eq, RustcDecodable, RustcEncodable, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct TypeBinding { pub name: String, pub kind: TypeBindingKind, } -#[derive(Clone, PartialEq, Eq, RustcDecodable, RustcEncodable, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub enum TypeBindingKind { Equality { ty: Type, diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 7a528e50e9c3f..47f07786554ac 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -75,7 +75,7 @@ impl Module { } } -#[derive(Debug, Clone, RustcEncodable, RustcDecodable, Copy)] +#[derive(Debug, Clone, Copy)] pub enum StructType { /// A braced struct Plain, diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index fa3bc3f5f4f8b..9e5cc03b83123 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -737,9 +737,6 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> } } } - clean::Unique(..) => { - panic!("should have been cleaned") - } } } diff --git a/src/librustdoc/html/item_type.rs b/src/librustdoc/html/item_type.rs index 3f3f4c85e81fc..5f1a1b31616c1 100644 --- a/src/librustdoc/html/item_type.rs +++ b/src/librustdoc/html/item_type.rs @@ -110,7 +110,6 @@ impl From for ItemType { clean::TypeKind::Module => ItemType::Module, clean::TypeKind::Static => ItemType::Static, clean::TypeKind::Const => ItemType::Constant, - clean::TypeKind::Variant => ItemType::Variant, clean::TypeKind::Typedef => ItemType::Typedef, clean::TypeKind::Foreign => ItemType::ForeignType, clean::TypeKind::Macro => ItemType::Macro, diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index b42a78f1e226a..26ec6e8765754 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -33,7 +33,7 @@ use std::cmp::Ordering; use std::collections::{BTreeMap, VecDeque}; use std::default::Default; use std::error; -use std::fmt::{self, Display, Formatter, Write as FmtWrite}; +use std::fmt::{self, Display, Formatter}; use std::ffi::OsStr; use std::fs::{self, File, OpenOptions}; use std::io::prelude::*; @@ -45,7 +45,6 @@ use std::sync::Arc; use std::rc::Rc; use errors; -use serialize::json::{ToJson, Json, as_json}; use syntax::ast; use syntax::edition::Edition; use syntax::ext::base::MacroKind; @@ -73,6 +72,9 @@ use crate::html::markdown::{self, Markdown, MarkdownHtml, MarkdownSummaryLine, E use crate::html::{highlight, layout, static_files}; use minifier; +use serde::{Serialize, Serializer}; +use serde::ser::{SerializeSeq, SerializeStruct, SerializeTuple}; +use serde_json; /// A pair of name and its optional document. pub type NameDoc = (String, Option); @@ -418,19 +420,18 @@ struct IndexItem { search_type: Option, } -impl ToJson for IndexItem { - fn to_json(&self) -> Json { +impl Serialize for IndexItem { + fn serialize(&self, serializer: S) -> Result where S: Serializer { assert_eq!(self.parent.is_some(), self.parent_idx.is_some()); - let mut data = Vec::with_capacity(6); - data.push((self.ty as usize).to_json()); - data.push(self.name.to_json()); - data.push(self.path.to_json()); - data.push(self.desc.to_json()); - data.push(self.parent_idx.to_json()); - data.push(self.search_type.to_json()); - - Json::Array(data) + let mut tup = serializer.serialize_tuple(6)?; + tup.serialize_element(&(self.ty as usize))?; + tup.serialize_element(&self.name)?; + tup.serialize_element(&self.path)?; + tup.serialize_element(&self.desc)?; + tup.serialize_element(&self.parent_idx)?; + tup.serialize_element(&self.search_type)?; + tup.end() } } @@ -441,18 +442,18 @@ struct Type { generics: Option>, } -impl ToJson for Type { - fn to_json(&self) -> Json { - match self.name { - Some(ref name) => { - let mut data = Vec::with_capacity(2); - data.push(name.to_json()); - if let Some(ref generics) = self.generics { - data.push(generics.to_json()); +impl Serialize for Type { + fn serialize(&self, serializer: S) -> Result where S: Serializer { + match &self.name { + Some(name) => { + let mut seq = serializer.serialize_seq(None)?; + seq.serialize_element(&name)?; + if let Some(generics) = &self.generics { + seq.serialize_element(&generics)?; } - Json::Array(data) + seq.end() } - None => Json::Null, + None => serializer.serialize_none() } } } @@ -464,26 +465,26 @@ struct IndexItemFunctionType { output: Option>, } -impl ToJson for IndexItemFunctionType { - fn to_json(&self) -> Json { +impl Serialize for IndexItemFunctionType { + fn serialize(&self, serializer: S) -> Result where S: Serializer { // 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()), + if match &self.output { + Some(output) => iter.chain(output.iter()).any(|i| i.name.is_none()), + None => iter.any(|i| i.name.is_none()), } { - Json::Null + serializer.serialize_none() } else { - let mut data = Vec::with_capacity(2); - data.push(self.inputs.to_json()); - if let Some(ref output) = self.output { + let mut seq = serializer.serialize_seq(None)?; + seq.serialize_element(&self.inputs)?; + if let Some(output) = &self.output { if output.len() > 1 { - data.push(output.to_json()); + seq.serialize_element(&output)?; } else { - data.push(output[0].to_json()); + seq.serialize_element(&output[0])?; } } - Json::Array(data) + seq.end() } } } @@ -711,11 +712,18 @@ pub fn run(mut krate: clean::Crate, cx.krate(krate) } +#[derive(Debug, Serialize)] +struct IndexEntry<'a> { + doc: String, + i: Vec<&'a IndexItem>, + p: Vec<(usize, String)>, +} + /// Builds the search index from the collected metadata fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { let mut nodeid_to_pathid = FxHashMap::default(); let mut crate_items = Vec::with_capacity(cache.search_index.len()); - let mut crate_paths = Vec::::new(); + let mut crate_paths = vec![]; let Cache { ref mut search_index, ref orphan_impl_items, @@ -752,7 +760,7 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { lastpathid += 1; let &(ref fqp, short) = paths.get(&nodeid).unwrap(); - crate_paths.push(((short as usize), fqp.last().unwrap().clone()).to_json()); + crate_paths.push(((short as usize), fqp.last().unwrap().clone())); pathid } }); @@ -763,22 +771,24 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { } else { lastpath = item.path.clone(); } - crate_items.push(item.to_json()); + crate_items.push(&*item); } let crate_doc = krate.module.as_ref().map(|module| { plain_summary_line_short(module.doc_value()) - }).unwrap_or(String::new()); + }); - let mut crate_data = BTreeMap::new(); - crate_data.insert("doc".to_owned(), Json::String(crate_doc)); - crate_data.insert("i".to_owned(), Json::Array(crate_items)); - crate_data.insert("p".to_owned(), Json::Array(crate_paths)); + let entry = IndexEntry { + doc: crate_doc.unwrap_or_default(), + i: crate_items, + p: crate_paths, + }; - // Collect the index into a string - format!("searchIndex[{}] = {};", - as_json(&krate.name), - Json::Object(crate_data)) + format!( + r#"searchIndex["{}"] = {};"#, + krate.name, + serde_json::to_string(&entry).unwrap(), + ) } fn write_shared( @@ -879,7 +889,7 @@ function handleThemeButtonsBlur(e) {{ themePicker.onclick = switchThemeButtonState; themePicker.onblur = handleThemeButtonsBlur; -[{}].forEach(function(item) {{ +{}.forEach(function(item) {{ var but = document.createElement('button'); but.innerHTML = item; but.onclick = function(el) {{ @@ -888,11 +898,8 @@ themePicker.onblur = handleThemeButtonsBlur; but.onblur = handleThemeButtonsBlur; themes.appendChild(but); }});"#, - themes.iter() - .map(|s| format!("\"{}\"", s)) - .collect::>() - .join(",")).as_bytes(), - )?; + serde_json::to_string(&themes).unwrap(), + ))?; write_minify(cx.dst.join(&format!("main{}.js", cx.shared.resource_suffix)), static_files::MAIN_JS, @@ -986,33 +993,51 @@ themePicker.onblur = handleThemeButtonsBlur; Ok((ret, krates, variables)) } - fn show_item(item: &IndexItem, krate: &str) -> String { - format!("{{'crate':'{}','ty':{},'name':'{}','desc':'{}','p':'{}'{}}}", - krate, item.ty as usize, item.name, item.desc.replace("'", "\\'"), item.path, - if let Some(p) = item.parent_idx { - format!(",'parent':{}", p) - } else { - String::new() - }) - } - let dst = cx.dst.join(&format!("aliases{}.js", cx.shared.resource_suffix)); { + #[derive(Debug, Serialize)] + struct Item<'a> { + #[serde(rename = "crate")] + krate: &'a str, + ty: usize, + name: &'a str, + desc: &'a str, + p: &'a str, + #[serde(skip_serializing_if = "Option::is_none")] + parent: Option, + } + let (mut all_aliases, _, _) = try_err!(collect(&dst, &krate.name, "ALIASES", false), &dst); let mut w = try_err!(File::create(&dst), &dst); - let mut output = String::with_capacity(100); + + let mut alias_to_items = BTreeMap::new(); + for (alias, items) in &cache.aliases { if items.is_empty() { - continue + continue; } - output.push_str(&format!("\"{}\":[{}],", - alias, - items.iter() - .map(|v| show_item(v, &krate.name)) - .collect::>() - .join(","))); - } - all_aliases.push(format!("ALIASES[\"{}\"] = {{{}}};", krate.name, output)); + + alias_to_items.insert( + alias, + items + .iter() + .map(|i| Item { + krate: &krate.name, + ty: i.ty as usize, + name: &i.name, + desc: &i.desc, + p: &i.path, + parent: i.parent_idx, + }) + .collect::>(), + ); + } + + all_aliases.push(format!( + r#"ALIASES["{}"] = {};"#, + krate.name, + serde_json::to_string(&alias_to_items).unwrap() + )); all_aliases.sort(); try_err!(writeln!(&mut w, "var ALIASES = {{}};"), &dst); for aliases in &all_aliases { @@ -1037,32 +1062,33 @@ themePicker.onblur = handleThemeButtonsBlur; elems: FxHashSet::default(), } } + } + + impl Serialize for Hierarchy { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut hierarchy = serializer.serialize_struct("Hierarchy", 3)?; - fn to_json_string(&self) -> String { let mut subs: Vec<&Hierarchy> = self.children.values().collect(); subs.sort_unstable_by(|a, b| a.elem.cmp(&b.elem)); - let mut files = self.elems.iter() - .map(|s| format!("\"{}\"", - s.to_str() - .expect("invalid osstring conversion"))) - .collect::>(); - files.sort_unstable_by(|a, b| a.cmp(b)); - let subs = subs.iter().map(|s| s.to_json_string()).collect::>().join(","); - let dirs = if subs.is_empty() { - String::new() - } else { - format!(",\"dirs\":[{}]", subs) - }; - let files = files.join(","); - let files = if files.is_empty() { - String::new() - } else { - format!(",\"files\":[{}]", files) - }; - format!("{{\"name\":\"{name}\"{dirs}{files}}}", - name=self.elem.to_str().expect("invalid osstring conversion"), - dirs=dirs, - files=files) + hierarchy.serialize_field("dirs", &subs)?; + + let mut files: Vec<&str> = self + .elems + .iter() + .map(|s| s.to_str().expect("invalid osstring conversion")) + .collect(); + files.sort_unstable(); + hierarchy.serialize_field("files", &files)?; + + hierarchy.serialize_field( + "name", + &self.elem.to_str().expect("invalid osstring conversion"), + )?; + + hierarchy.end() } } @@ -1097,9 +1123,11 @@ themePicker.onblur = handleThemeButtonsBlur; let (mut all_sources, _krates, _) = try_err!(collect(&dst, &krate.name, "sourcesIndex", false), &dst); - all_sources.push(format!("sourcesIndex[\"{}\"] = {};", - &krate.name, - hierarchy.to_json_string())); + all_sources.push(format!( + r#"sourcesIndex["{}"] = {};"#, + &krate.name, + serde_json::to_string(&hierarchy).unwrap() + )); all_sources.sort(); let mut w = try_err!(File::create(&dst), &dst); try_err!(writeln!(&mut w, @@ -1190,29 +1218,39 @@ themePicker.onblur = handleThemeButtonsBlur; } }; - let mut have_impls = false; - let mut implementors = format!(r#"implementors["{}"] = ["#, krate.name); - for imp in imps { - // If the trait and implementation are in the same crate, then - // there's no need to emit information about it (there's inlining - // going on). If they're in different crates then the crate defining - // the trait will be interested in our implementation. - if imp.impl_item.def_id.krate == did.krate { continue } - // If the implementation is from another crate then that crate - // should add it. - if !imp.impl_item.def_id.is_local() { continue } - have_impls = true; - write!(implementors, "{{text:{},synthetic:{},types:{}}},", - as_json(&imp.inner_impl().to_string()), - imp.inner_impl().synthetic, - as_json(&collect_paths_for_type(imp.inner_impl().for_.clone()))).unwrap(); - } - implementors.push_str("];"); + #[derive(Debug, Serialize)] + struct Implementor { + text: String, + synthetic: bool, + types: Vec, + } + + let implementors = imps + .iter() + .filter_map(|imp| { + // If the trait and implementation are in the same crate, then + // there's no need to emit information about it (there's inlining + // going on). If they're in different crates then the crate defining + // the trait will be interested in our implementation. + // + // If the implementation is from another crate then that crate + // should add it. + if imp.impl_item.def_id.krate == did.krate || !imp.impl_item.def_id.is_local() { + return None; + } + + Some(Implementor { + text: imp.inner_impl().to_string(), + synthetic: imp.inner_impl().synthetic, + types: collect_paths_for_type(imp.inner_impl().for_.clone()), + }) + }) + .collect::>(); // Only create a js file if we have impls to add to it. If the trait is // documented locally though we always create the file to avoid dead // links. - if !have_impls && !cache.paths.contains_key(&did) { + if implementors.is_empty() && !cache.paths.contains_key(&did) { continue; } @@ -1228,7 +1266,13 @@ themePicker.onblur = handleThemeButtonsBlur; let (mut all_implementors, _, _) = try_err!(collect(&mydst, &krate.name, "implementors", false), &mydst); - all_implementors.push(implementors); + all_implementors.push( + format!( + r#"implementors["{}"] = {};"#, + krate.name, + serde_json::to_string(&implementors).unwrap(), + ), + ); // Sort the implementors by crate so the file will be generated // identically even with rustdoc running in parallel. all_implementors.sort(); @@ -1264,7 +1308,7 @@ fn render_sources(dst: &Path, scx: &mut SharedContext, /// Writes the entire contents of a string to a destination, not attempting to /// catch any errors. -fn write(dst: PathBuf, contents: &[u8]) -> Result<(), Error> { +fn write(dst: PathBuf, contents: impl AsRef<[u8]>) -> Result<(), Error> { Ok(try_err!(fs::write(&dst, contents), &dst)) } @@ -2246,8 +2290,14 @@ impl Context { let items = this.build_sidebar_items(&m); let js_dst = this.dst.join("sidebar-items.js"); let mut js_out = BufWriter::new(try_err!(File::create(&js_dst), &js_dst)); - try_err!(write!(&mut js_out, "initSidebarItems({});", - as_json(&items)), &js_dst); + try_err!( + write!( + &mut js_out, + "initSidebarItems({});", + serde_json::to_string(&items).unwrap() + ), + &js_dst + ); } for item in m.items { @@ -3343,8 +3393,11 @@ fn item_trait( write_loading_content(w, "")?; } } - write!(w, r#""#, - as_json(&synthetic_types))?; + write!( + w, + r#""#, + serde_json::to_string(&synthetic_types).unwrap(), + )?; write!(w, r#"