//! Rustdoc's JSON output interface //! //! These types are the public API exposed through the `--output-format json` flag. The [`Crate`] //! struct is the root of the JSON blob and all other items are contained within. use std::collections::{HashMap, HashSet}; use std::path::PathBuf; use serde::{Deserialize, Serialize}; /// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information /// about the language items in the local crate, as well as info about external items to allow /// tools to find or link to them. #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct Crate { /// The id of the root [`Module`] item of the local crate. pub root: Id, /// The version string given to `--crate-version`, if any. pub crate_version: Option, /// Whether or not the output includes private items. pub includes_private: bool, /// A collection of all items in the local crate as well as some external traits and their /// items that are referenced locally. pub index: HashMap, /// Maps IDs to fully qualified paths and other info helpful for generating links. pub paths: HashMap, /// Maps `crate_id` of items to a crate name and html_root_url if it exists. pub external_crates: HashMap, /// A single version number to be used in the future when making backwards incompatible changes /// to the JSON output. pub format_version: u32, } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct ExternalCrate { pub name: String, pub html_root_url: Option, } /// For external (not defined in the local crate) items, you don't get the same level of /// information. This struct should contain enough to generate a link/reference to the item in /// question, or can be used by a tool that takes the json output of multiple crates to find /// the actual item definition with all the relevant info. #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct ItemSummary { /// Can be used to look up the name and html_root_url of the crate this item came from in the /// `external_crates` map. pub crate_id: u32, /// The list of path components for the fully qualified path of this item (e.g. /// `["std", "io", "lazy", "Lazy"]` for `std::io::lazy::Lazy`). pub path: Vec, /// Whether this item is a struct, trait, macro, etc. pub kind: ItemKind, } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct Item { /// The unique identifier of this item. Can be used to find this item in various mappings. pub id: Id, /// This can be used as a key to the `external_crates` map of [`Crate`] to see which crate /// this item came from. pub crate_id: u32, /// Some items such as impls don't have names. pub name: Option, /// The source location of this item (absent if it came from a macro expansion or inline /// assembly). pub source: Option, /// By default all documented items are public, but you can tell rustdoc to output private items /// so this field is needed to differentiate. pub visibility: Visibility, /// The full markdown docstring of this item. Absent if there is no documentation at all, /// Some("") if there is some documentation but it is empty (EG `#[doc = ""]`). pub docs: Option, /// This mapping resolves [intra-doc links](https://github.com/rust-lang/rfcs/blob/master/text/1946-intra-rustdoc-links.md) from the docstring to their IDs pub links: HashMap, /// Stringified versions of the attributes on this item (e.g. `"#[inline]"`) pub attrs: Vec, pub deprecation: Option, #[serde(flatten)] pub inner: ItemEnum, } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct Span { /// The path to the source file for this span relative to the path `rustdoc` was invoked with. pub filename: PathBuf, /// Zero indexed Line and Column of the first character of the `Span` pub begin: (usize, usize), /// Zero indexed Line and Column of the last character of the `Span` pub end: (usize, usize), } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct Deprecation { pub since: Option, pub note: Option, } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "snake_case")] pub enum Visibility { Public, /// For the most part items are private by default. The exceptions are associated items of /// public traits and variants of public enums. Default, Crate, /// For `pub(in path)` visibility. `parent` is the module it's restricted to and `path` is how /// that module was referenced (like `"super::super"` or `"crate::foo::bar"`). Restricted { parent: Id, path: String, }, } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "snake_case")] pub enum GenericArgs { /// <'a, 32, B: Copy, C = u32> AngleBracketed { args: Vec, bindings: Vec }, /// Fn(A, B) -> C Parenthesized { inputs: Vec, output: Option }, } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "snake_case")] pub enum GenericArg { Lifetime(String), Type(Type), Const(Constant), } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct Constant { #[serde(rename = "type")] pub type_: Type, pub expr: String, pub value: Option, pub is_literal: bool, } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct TypeBinding { pub name: String, pub binding: TypeBindingKind, } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "snake_case")] pub enum TypeBindingKind { Equality(Type), Constraint(Vec), } #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct Id(pub String); #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "snake_case")] pub enum ItemKind { Module, ExternCrate, Import, Struct, StructField, Union, Enum, Variant, Function, Typedef, OpaqueTy, Constant, Trait, TraitAlias, Method, Impl, Static, ForeignType, Macro, ProcAttribute, ProcDerive, AssocConst, AssocType, Primitive, Keyword, } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[serde(tag = "kind", content = "inner", rename_all = "snake_case")] pub enum ItemEnum { Module(Module), ExternCrate { name: String, rename: Option, }, Import(Import), Union(Union), Struct(Struct), StructField(Type), Enum(Enum), Variant(Variant), Function(Function), Trait(Trait), TraitAlias(TraitAlias), Method(Method), Impl(Impl), Typedef(Typedef), OpaqueTy(OpaqueTy), Constant(Constant), Static(Static), /// `type`s from an extern block ForeignType, /// Declarative macro_rules! macro Macro(String), ProcMacro(ProcMacro), AssocConst { #[serde(rename = "type")] type_: Type, /// e.g. `const X: usize = 5;` default: Option, }, AssocType { bounds: Vec, /// e.g. `type X = usize;` default: Option, }, } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct Module { pub is_crate: bool, pub items: Vec, } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct Union { pub generics: Generics, pub fields_stripped: bool, pub fields: Vec, pub impls: Vec, } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct Struct { pub struct_type: StructType, pub generics: Generics, pub fields_stripped: bool, pub fields: Vec, pub impls: Vec, } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct Enum { pub generics: Generics, pub variants_stripped: bool, pub variants: Vec, pub impls: Vec, } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "snake_case")] #[serde(tag = "variant_kind", content = "variant_inner")] pub enum Variant { Plain, Tuple(Vec), Struct(Vec), } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "snake_case")] pub enum StructType { Plain, Tuple, Unit, } #[non_exhaustive] #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)] #[serde(rename_all = "snake_case")] pub enum Qualifiers { Const, Unsafe, Async, } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct Function { pub decl: FnDecl, pub generics: Generics, pub header: HashSet, pub abi: String, } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct Method { pub decl: FnDecl, pub generics: Generics, pub header: HashSet, pub abi: String, pub has_body: bool, } #[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)] pub struct Generics { pub params: Vec, pub where_predicates: Vec, } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct GenericParamDef { pub name: String, pub kind: GenericParamDefKind, } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "snake_case")] pub enum GenericParamDefKind { Lifetime, Type { bounds: Vec, default: Option }, Const(Type), } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "snake_case")] pub enum WherePredicate { BoundPredicate { ty: Type, bounds: Vec }, RegionPredicate { lifetime: String, bounds: Vec }, EqPredicate { lhs: Type, rhs: Type }, } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "snake_case")] pub enum GenericBound { TraitBound { #[serde(rename = "trait")] trait_: Type, /// Used for HRTBs generic_params: Vec, modifier: TraitBoundModifier, }, Outlives(String), } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "snake_case")] pub enum TraitBoundModifier { None, Maybe, MaybeConst, } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "snake_case")] #[serde(tag = "kind", content = "inner")] pub enum Type { /// Structs, enums, and traits ResolvedPath { name: String, id: Id, args: Option>, param_names: Vec, }, /// Parameterized types Generic(String), /// Fixed-size numeric types (plus int/usize/float), char, arrays, slices, and tuples Primitive(String), /// `extern "ABI" fn` FunctionPointer(Box), /// `(String, u32, Box)` Tuple(Vec), /// `[u32]` Slice(Box), /// [u32; 15] Array { #[serde(rename = "type")] type_: Box, len: String, }, /// `impl TraitA + TraitB + ...` ImplTrait(Vec), /// `!` Never, /// `_` Infer, /// `*mut u32`, `*u8`, etc. RawPointer { mutable: bool, #[serde(rename = "type")] type_: Box, }, /// `&'a mut String`, `&str`, etc. BorrowedRef { lifetime: Option, mutable: bool, #[serde(rename = "type")] type_: Box, }, /// `::Name` or associated types like `T::Item` where `T: Iterator` QualifiedPath { name: String, self_type: Box, #[serde(rename = "trait")] trait_: Box, }, } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct FunctionPointer { pub decl: FnDecl, pub generic_params: Vec, pub header: HashSet, pub abi: String, } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct FnDecl { pub inputs: Vec<(String, Type)>, pub output: Option, pub c_variadic: bool, } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct Trait { pub is_auto: bool, pub is_unsafe: bool, pub items: Vec, pub generics: Generics, pub bounds: Vec, pub implementors: Vec, } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct TraitAlias { pub generics: Generics, pub params: Vec, } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct Impl { pub is_unsafe: bool, pub generics: Generics, pub provided_trait_methods: Vec, #[serde(rename = "trait")] pub trait_: Option, #[serde(rename = "for")] pub for_: Type, pub items: Vec, pub negative: bool, pub synthetic: bool, pub blanket_impl: Option, } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "snake_case")] pub struct Import { /// The full path being imported. pub span: String, /// May be different from the last segment of `source` when renaming imports: /// `use source as name;` pub name: String, /// The ID of the item being imported. pub id: Option, // FIXME is this actually ever None? /// Whether this import uses a glob: `use source::*;` pub glob: bool, } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct ProcMacro { pub kind: MacroKind, pub helpers: Vec, } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "snake_case")] pub enum MacroKind { /// A bang macro `foo!()`. Bang, /// An attribute macro `#[foo]`. Attr, /// A derive macro `#[derive(Foo)]` Derive, } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct Typedef { #[serde(rename = "type")] pub type_: Type, pub generics: Generics, } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct OpaqueTy { pub bounds: Vec, pub generics: Generics, } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct Static { #[serde(rename = "type")] pub type_: Type, pub mutable: bool, pub expr: String, } #[cfg(test)] mod tests { use super::*; #[test] fn test_struct_info_roundtrip() { let s = ItemEnum::Struct(Struct { struct_type: StructType::Plain, generics: Generics { params: vec![], where_predicates: vec![] }, fields_stripped: false, fields: vec![], impls: vec![], }); let struct_json = serde_json::to_string(&s).unwrap(); let de_s = serde_json::from_str(&struct_json).unwrap(); assert_eq!(s, de_s); } #[test] fn test_union_info_roundtrip() { let u = ItemEnum::Union(Union { generics: Generics { params: vec![], where_predicates: vec![] }, fields_stripped: false, fields: vec![], impls: vec![], }); let union_json = serde_json::to_string(&u).unwrap(); let de_u = serde_json::from_str(&union_json).unwrap(); assert_eq!(u, de_u); } }