rust/src/rustdoc-json-types/lib.rs

555 lines
15 KiB
Rust

//! 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<String>,
/// 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<Id, Item>,
/// Maps IDs to fully qualified paths and other info helpful for generating links.
pub paths: HashMap<Id, ItemSummary>,
/// Maps `crate_id` of items to a crate name and html_root_url if it exists.
pub external_crates: HashMap<u32, ExternalCrate>,
/// 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<String>,
}
/// 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<String>,
/// 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<String>,
/// The source location of this item (absent if it came from a macro expansion or inline
/// assembly).
pub source: Option<Span>,
/// 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<String>,
/// 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<String, Id>,
/// Stringified versions of the attributes on this item (e.g. `"#[inline]"`)
pub attrs: Vec<String>,
pub deprecation: Option<Deprecation>,
#[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<String>,
pub note: Option<String>,
}
#[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<GenericArg>, bindings: Vec<TypeBinding> },
/// Fn(A, B) -> C
Parenthesized { inputs: Vec<Type>, output: Option<Type> },
}
#[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<String>,
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<GenericBound>),
}
#[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<String>,
},
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<String>,
},
AssocType {
bounds: Vec<GenericBound>,
/// e.g. `type X = usize;`
default: Option<Type>,
},
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct Module {
pub is_crate: bool,
pub items: Vec<Id>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct Union {
pub generics: Generics,
pub fields_stripped: bool,
pub fields: Vec<Id>,
pub impls: Vec<Id>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct Struct {
pub struct_type: StructType,
pub generics: Generics,
pub fields_stripped: bool,
pub fields: Vec<Id>,
pub impls: Vec<Id>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct Enum {
pub generics: Generics,
pub variants_stripped: bool,
pub variants: Vec<Id>,
pub impls: Vec<Id>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
#[serde(tag = "variant_kind", content = "variant_inner")]
pub enum Variant {
Plain,
Tuple(Vec<Type>),
Struct(Vec<Id>),
}
#[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<Qualifiers>,
pub abi: String,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct Method {
pub decl: FnDecl,
pub generics: Generics,
pub header: HashSet<Qualifiers>,
pub abi: String,
pub has_body: bool,
}
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
pub struct Generics {
pub params: Vec<GenericParamDef>,
pub where_predicates: Vec<WherePredicate>,
}
#[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<GenericBound>, default: Option<Type> },
Const(Type),
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum WherePredicate {
BoundPredicate { ty: Type, bounds: Vec<GenericBound> },
RegionPredicate { lifetime: String, bounds: Vec<GenericBound> },
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<GenericParamDef>,
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<Box<GenericArgs>>,
param_names: Vec<GenericBound>,
},
/// Parameterized types
Generic(String),
/// Fixed-size numeric types (plus int/usize/float), char, arrays, slices, and tuples
Primitive(String),
/// `extern "ABI" fn`
FunctionPointer(Box<FunctionPointer>),
/// `(String, u32, Box<usize>)`
Tuple(Vec<Type>),
/// `[u32]`
Slice(Box<Type>),
/// [u32; 15]
Array {
#[serde(rename = "type")]
type_: Box<Type>,
len: String,
},
/// `impl TraitA + TraitB + ...`
ImplTrait(Vec<GenericBound>),
/// `!`
Never,
/// `_`
Infer,
/// `*mut u32`, `*u8`, etc.
RawPointer {
mutable: bool,
#[serde(rename = "type")]
type_: Box<Type>,
},
/// `&'a mut String`, `&str`, etc.
BorrowedRef {
lifetime: Option<String>,
mutable: bool,
#[serde(rename = "type")]
type_: Box<Type>,
},
/// `<Type as Trait>::Name` or associated types like `T::Item` where `T: Iterator`
QualifiedPath {
name: String,
self_type: Box<Type>,
#[serde(rename = "trait")]
trait_: Box<Type>,
},
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct FunctionPointer {
pub decl: FnDecl,
pub generic_params: Vec<GenericParamDef>,
pub header: HashSet<Qualifiers>,
pub abi: String,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct FnDecl {
pub inputs: Vec<(String, Type)>,
pub output: Option<Type>,
pub c_variadic: bool,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct Trait {
pub is_auto: bool,
pub is_unsafe: bool,
pub items: Vec<Id>,
pub generics: Generics,
pub bounds: Vec<GenericBound>,
pub implementors: Vec<Id>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct TraitAlias {
pub generics: Generics,
pub params: Vec<GenericBound>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct Impl {
pub is_unsafe: bool,
pub generics: Generics,
pub provided_trait_methods: Vec<String>,
#[serde(rename = "trait")]
pub trait_: Option<Type>,
#[serde(rename = "for")]
pub for_: Type,
pub items: Vec<Id>,
pub negative: bool,
pub synthetic: bool,
pub blanket_impl: Option<Type>,
}
#[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<Id>, // 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<String>,
}
#[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<GenericBound>,
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);
}
}