Rollup merge of #153283 - LukeMathWalker:add-rkyv-support, r=aDotInTheVoid

feat(rustdoc-json): Add optional support for rkyv (de)serialization

## Motivation

The JSON documents produced by `rustdoc-json` are _big_. More often than not, tools need to access a small fraction of that output—e.g. a couple of types from a transitive dependency, or a subset of the fields on a given `rustdoc-json-types` type.

Using a binary (de)serialization format and a cache helps to drive down the performance cost of deserialization: you invoke `rustdoc-json` to get the JSON output you need, re-serialize it using a more perfomant format as target (e.g. `bincode` or `postcard`) and thus amortize the cost of future queries that hit the persistent cache rather than `rustdoc-json`.
This is _better_, but still not great: the deserialization cost for crates like `std` still shows up prominently in flamegraphs.

## An Alternative Approach: rkyv

`rkyv` provides a different opportunity: you avoid paying the deserialization cost _upfront_ thanks to [zero-copy deserialization](https://rkyv.org/zero-copy-deserialization.html).
You're often able to determine if you need a certain entry from the JSON document using the archived version of that type, thus incurring the full deserialization cost only for the subset of items you actually need ([example](https://github.com/LukeMathWalker/pavex/pull/574/changes/d067e7e0cfa38da5b0a3c8713b1c53beb0b29a5d)).

## The Change

This PR adds support for `rkyv` behind a feature flag (`rkyv_0_8`).
For most types, it's a straight-forward `derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)` annotation. For co-recursive types, we need to adjust the generated bounds, using the techniques from [`rkyv`'s JSON example](https://github.com/rkyv/rkyv/blob/985b0230a0b9cb9fce4a4ee9facb6af148e27c8e/rkyv/examples/json_like_schema.rs).

I have added new round-trip tests to ensure `rkyv` works as expected.

r? @aDotInTheVoid
This commit is contained in:
Jonathan Brouwer
2026-03-10 22:44:05 +01:00
committed by GitHub
5 changed files with 499 additions and 5 deletions
+124
View File
@@ -376,12 +376,41 @@ version = "3.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
[[package]]
name = "bytecheck"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0caa33a2c0edca0419d15ac723dff03f1956f7978329b1e3b5fdaaaed9d3ca8b"
dependencies = [
"bytecheck_derive",
"ptr_meta",
"rancor",
"simdutf8",
]
[[package]]
name = "bytecheck_derive"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89385e82b5d1821d2219e0b095efa2cc1f246cbf99080f3be46a1a85c0d392d9"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.110",
]
[[package]]
name = "bytecount"
version = "0.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e"
[[package]]
name = "bytes"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
[[package]]
name = "camino"
version = "1.2.1"
@@ -2476,6 +2505,26 @@ dependencies = [
name = "miropt-test-tools"
version = "0.1.0"
[[package]]
name = "munge"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e17401f259eba956ca16491461b6e8f72913a0a114e39736ce404410f915a0c"
dependencies = [
"munge_macro",
]
[[package]]
name = "munge_macro"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4568f25ccbd45ab5d5603dc34318c1ec56b117531781260002151b8530a9f931"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.110",
]
[[package]]
name = "new_debug_unreachable"
version = "1.0.6"
@@ -3047,6 +3096,26 @@ dependencies = [
"cc",
]
[[package]]
name = "ptr_meta"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b9a0cf95a1196af61d4f1cbdab967179516d9a4a4312af1f31948f8f6224a79"
dependencies = [
"ptr_meta_derive",
]
[[package]]
name = "ptr_meta_derive"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7347867d0a7e1208d93b46767be83e2b8f978c3dad35f775ac8d8847551d6fe1"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.110",
]
[[package]]
name = "pulldown-cmark"
version = "0.11.3"
@@ -3092,6 +3161,15 @@ version = "5.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
[[package]]
name = "rancor"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a063ea72381527c2a0561da9c80000ef822bdd7c3241b1cc1b12100e3df081ee"
dependencies = [
"ptr_meta",
]
[[package]]
name = "rand"
version = "0.8.5"
@@ -3275,6 +3353,15 @@ dependencies = [
name = "remote-test-server"
version = "0.1.0"
[[package]]
name = "rend"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cadadef317c2f20755a64d7fdc48f9e7178ee6b0e1f7fce33fa60f1d68a276e6"
dependencies = [
"bytecheck",
]
[[package]]
name = "replace-version-placeholder"
version = "0.1.0"
@@ -3283,6 +3370,36 @@ dependencies = [
"walkdir",
]
[[package]]
name = "rkyv"
version = "0.8.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a30e631b7f4a03dee9056b8ef6982e8ba371dd5bedb74d3ec86df4499132c70"
dependencies = [
"bytecheck",
"bytes",
"hashbrown 0.16.1",
"indexmap",
"munge",
"ptr_meta",
"rancor",
"rend",
"rkyv_derive",
"tinyvec",
"uuid",
]
[[package]]
name = "rkyv_derive"
version = "0.8.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8100bb34c0a1d0f907143db3149e6b4eea3c33b9ee8b189720168e818303986f"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.110",
]
[[package]]
name = "run_make_support"
version = "0.0.0"
@@ -4790,6 +4907,7 @@ name = "rustdoc-json-types"
version = "0.1.0"
dependencies = [
"bincode",
"rkyv",
"rustc-hash 2.1.1",
"serde",
"serde_derive",
@@ -5128,6 +5246,12 @@ version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
[[package]]
name = "simdutf8"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
[[package]]
name = "similar"
version = "2.7.0"
+1 -1
View File
@@ -3315,7 +3315,7 @@ fn run(self, builder: &Builder<'_>) {
builder.kind,
"src/rustdoc-json-types",
SourceType::InTree,
&[],
&["rkyv_0_8".to_owned()],
);
// FIXME: this looks very wrong, libtest doesn't accept `-C` arguments and the quotes are fishy.
+2
View File
@@ -8,11 +8,13 @@ path = "lib.rs"
[features]
default = ["rustc-hash"]
rkyv_0_8 = ["dep:rkyv"]
[dependencies]
serde = "1.0"
serde_derive = "1.0"
rustc-hash = { version = "2.0", optional = true }
rkyv = { version = "0.8", optional = true }
[dev-dependencies]
serde_json = "1.0"
+257 -4
View File
@@ -3,7 +3,11 @@
//! 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.
//!
//! We expose a `rustc-hash` feature that is disabled by default. This feature switches the
//! # Feature Flags
//!
//! ## `rustc-hash`
//!
//! We expose a `rustc-hash` feature, disabled by default. This feature switches the
//! [`std::collections::HashMap`] for [`rustc_hash::FxHashMap`] to improve the performance of said
//! `HashMap` in specific situations.
//!
@@ -12,8 +16,81 @@
//! turning this feature on, as [`FxHashMap`][2] only concerns itself with hash speed, and may
//! increase the number of collisions.
//!
//! ## `rkyv_0_8`
//!
//! We expose a `rkyv_0_8` feature, disabled by default. When enabled, it derives `rkyv`'s
//! [`Archive`][3], [`Serialize`][4] and [`Deserialize`][5] traits for all types in this crate.
//! Furthermore, it exposes the corresponding `Archived*` types (e.g. `ArchivedId` for [`Id`]).
//!
//! `rkyv` lets you works with JSON output without paying the deserialization cost _upfront_,
//! thanks to [zero-copy deserialization][6].
//! You can perform various types of analyses on the `Archived*` version of the relevant types,
//! incurring the full deserialization cost only for the subset of items you actually need.
//!
//! [1]: https://rust-lang.zulipchat.com/#narrow/channel/266220-t-rustdoc/topic/rustc-hash.20and.20performance.20of.20rustdoc-types/near/474855731
//! [2]: https://crates.io/crates/rustc-hash
//! [3]: https://docs.rs/rkyv/0.8.15/rkyv/trait.Archive.html
//! [4]: https://docs.rs/rkyv/0.8.15/rkyv/trait.Serialize.html
//! [5]: https://docs.rs/rkyv/0.8.15/rkyv/trait.Deserialize.html
//! [6]: https://rkyv.org/zero-copy-deserialization.html
// # On `rkyv` Derives
//
// In most cases, it's enough to add `#[derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]`
// on top of a type to derive the relevant `rkyv` traits.
//
// There are a few exceptions, though, where more complex macro options are required.
// The following sections break down the patterns that are showcased by `rkyv'`s
// [JSON schema example](https://github.com/rkyv/rkyv/blob/985b0230a0b9cb9fce4a4ee9facb6af148e27c8e/rkyv/examples/json_like_schema.rs).
//
// ## Recursive Types
//
// Let's look at the `Type` enum as an example. It stores a `Box<Type>` in its `Slice` variant.
// A "vanilla" `rkyv` annotation will cause an overflow in the compiler when
// building the crate, since the bounds generated by the macro will be self-referential and thus
// trap the compiler into a never-ending loop.
//
// To prevent this issue, `#[rkyv(omit_bounds)]` must be added to the relevant field.
//
// ## Co-Recursive Types
//
// The same problem occurs if a type is co-recursive—i.e. it doesn't _directly_ store a pointer
// to another instance of the same type, but one of its fields does, transitively.
//
// For example, let's look at `Path`:
//
// - `Path` has a field of type `Option<Box<GenericArgs>>`
// - One of the variants in `GenericArgs` has a field of type `Vec<GenericArg>`
// - One of the variants of `GenericArg` has a field of type `Type`
// - `Type::ResolvedPath` stores a `Path` instance
//
// The same logic of the recursive case applies here: we must use `#[rkyv(omit_bounds)]` to break the cycle.
//
// ## Additional Bounds
//
// Whenever `#[rkyv(omit_bounds)]` is added to a field or variant, `rkyv` omits _all_ traits bounds for that
// field in the generated impl. This may result in compilation errors due to insufficient bounds in the
// generated code.
//
// To add _some_ bounds back, `rkyv` exposes four knobs:
//
// - `#[rkyv(archive_bounds(..))]` to add predicates to all generated impls
// - `#[rkyv(serialize_bounds(..))]` to add predicates to just the `Serialize` impl
// - `#[rkyv(deserialize_bounds(..))]` to add predicates to just the `Deserialize` impl
// - `#[rkyv(bytecheck(bounds(..)))]` to add predicates to just the `CheckBytes` impl
//
// In particular, we use the following annotations in this crate:
//
// - `serialize_bounds(__S: rkyv::ser::Writer + rkyv::ser::Allocator, __S::Error: rkyv::rancor::Source)` for serializing
// variable-length types like `Vec<T>`. `rkyv`'s zero-copy format requires the serializer to be able
// to write bytes (`Writer`) and allocate scratch space (`Allocator`) for these types
// ([`rkyv`'s `Vec` impl bounds](https://docs.rs/rkyv/0.8.15/rkyv/trait.Serialize.html#impl-Serialize%3CS%3E-for-Vec%3CT%3E)).
// The `Error: Source` bound lets error types compose.
// - `deserialize_bounds(__D::Error: rkyv::rancor::Source)` so that errors from deserializing fields behind
// `omit_bounds` (e.g. `Box<T>`, `Vec<T>`) can compose via the `Source` trait.
// - `bytecheck(bounds(__C: rkyv::validation::ArchiveContext, __C::Error: rkyv::rancor::Source))` for validating
// archived data. Checking that bytes represent a valid archived value requires an `ArchiveContext` that tracks
// validation state (e.g. subtree ranges, to prevent overlapping/out-of-bounds archived data).
#[cfg(not(feature = "rustc-hash"))]
use std::collections::HashMap;
@@ -46,6 +123,8 @@
/// 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, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
pub struct Crate {
/// The id of the root [`Module`] item of the local crate.
pub root: Id,
@@ -69,6 +148,8 @@ pub struct Crate {
/// Information about a target
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
pub struct Target {
/// The target triple for which this documentation was generated
pub triple: String,
@@ -99,6 +180,8 @@ pub struct Target {
/// [1]: https://doc.rust-lang.org/stable/reference/attributes/codegen.html#the-target_feature-attribute
/// [2]: https://doc.rust-lang.org/reference/conditional-compilation.html#target_feature
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
pub struct TargetFeature {
/// The name of this target feature.
pub name: String,
@@ -123,6 +206,8 @@ pub struct TargetFeature {
/// Metadata of a crate, either the same crate on which `rustdoc` was invoked, or its dependency.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
pub struct ExternalCrate {
/// The name of the crate.
///
@@ -140,6 +225,7 @@ pub struct ExternalCrate {
///
/// This will typically be a `.rlib` or `.rmeta`. It can be used to determine which crate
/// this was in terms of whatever build-system invoked rustc.
#[cfg_attr(feature = "rkyv_0_8", rkyv(with = rkyv::with::AsString))]
pub path: PathBuf,
}
@@ -150,6 +236,8 @@ pub struct ExternalCrate {
/// 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, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
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.
@@ -171,6 +259,8 @@ pub struct ItemSummary {
/// The `Item` data type holds fields that can apply to any of these,
/// and leaves kind-specific details (like function args or enum variants) to the `inner` field.
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
pub struct Item {
/// The unique identifier of this item. Can be used to find this item in various mappings.
pub id: Id,
@@ -209,6 +299,8 @@ pub struct Item {
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
#[serde(rename_all = "snake_case")]
/// An attribute, e.g. `#[repr(C)]`
///
@@ -256,6 +348,8 @@ pub enum Attribute {
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
/// The contents of a `#[repr(...)]` attribute.
///
/// Used in [`Attribute::Repr`].
@@ -275,6 +369,8 @@ pub struct AttributeRepr {
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
#[serde(rename_all = "snake_case")]
/// The kind of `#[repr]`.
///
@@ -294,8 +390,11 @@ pub enum ReprKind {
/// A range of source code.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
pub struct Span {
/// The path to the source file for this span relative to the path `rustdoc` was invoked with.
#[cfg_attr(feature = "rkyv_0_8", rkyv(with = rkyv::with::AsString))]
pub filename: PathBuf,
/// One indexed Line and Column of the first character of the `Span`.
pub begin: (usize, usize),
@@ -305,6 +404,8 @@ pub struct Span {
/// Information about the deprecation of an [`Item`].
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
pub struct Deprecation {
/// Usually a version number when this [`Item`] first became deprecated.
pub since: Option<String>,
@@ -314,6 +415,8 @@ pub struct Deprecation {
/// Visibility of an [`Item`].
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
#[serde(rename_all = "snake_case")]
pub enum Visibility {
/// Explicitly public visibility set with `pub`.
@@ -337,6 +440,8 @@ pub enum Visibility {
/// Dynamic trait object type (`dyn Trait`).
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
pub struct DynTrait {
/// All the traits implemented. One of them is the vtable, and the rest must be auto traits.
pub traits: Vec<PolyTrait>,
@@ -352,6 +457,8 @@ pub struct DynTrait {
/// A trait and potential HRTBs
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
pub struct PolyTrait {
/// The path to the trait.
#[serde(rename = "trait")]
@@ -371,6 +478,18 @@ pub struct PolyTrait {
/// ^^^^^
/// ```
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(serialize_bounds(
__S: rkyv::ser::Writer + rkyv::ser::Allocator,
__S::Error: rkyv::rancor::Source,
)))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(deserialize_bounds(
__D::Error: rkyv::rancor::Source,
)))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(bytecheck(bounds(
__C: rkyv::validation::ArchiveContext,
))))]
#[serde(rename_all = "snake_case")]
pub enum GenericArgs {
/// `<'a, 32, B: Copy, C = u32>`
@@ -387,8 +506,10 @@ pub enum GenericArgs {
/// `Fn(A, B) -> C`
Parenthesized {
/// The input types, enclosed in parentheses.
#[cfg_attr(feature = "rkyv_0_8", rkyv(omit_bounds))]
inputs: Vec<Type>,
/// The output type provided after the `->`, if present.
#[cfg_attr(feature = "rkyv_0_8", rkyv(omit_bounds))]
output: Option<Type>,
},
/// `T::method(..)`
@@ -399,6 +520,8 @@ pub enum GenericArgs {
///
/// Part of [`GenericArgs`].
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
#[serde(rename_all = "snake_case")]
pub enum GenericArg {
/// A lifetime argument.
@@ -429,6 +552,8 @@ pub enum GenericArg {
/// A constant.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
pub struct Constant {
/// The stringified expression of this constant. Note that its mapping to the original
/// source code is unstable and it's not guaranteed that it'll match the source code.
@@ -448,10 +573,24 @@ pub struct Constant {
/// ^^^^^^^^^^ ^^^^^^^^^^^^^^^
/// ```
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(serialize_bounds(
__S: rkyv::ser::Writer + rkyv::ser::Allocator,
__S::Error: rkyv::rancor::Source,
)))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(deserialize_bounds(
__D::Error: rkyv::rancor::Source,
)))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(bytecheck(bounds(
__C: rkyv::validation::ArchiveContext,
<__C as rkyv::rancor::Fallible>::Error: rkyv::rancor::Source,
))))]
pub struct AssocItemConstraint {
/// The name of the associated type/constant.
pub name: String,
/// Arguments provided to the associated type/constant.
#[cfg_attr(feature = "rkyv_0_8", rkyv(omit_bounds))]
pub args: Option<Box<GenericArgs>>,
/// The kind of bound applied to the associated type/constant.
pub binding: AssocItemConstraintKind,
@@ -459,6 +598,8 @@ pub struct AssocItemConstraint {
/// The way in which an associate type/constant is bound.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
#[serde(rename_all = "snake_case")]
pub enum AssocItemConstraintKind {
/// The required value/type is specified exactly. e.g.
@@ -487,6 +628,8 @@ pub enum AssocItemConstraintKind {
/// should treat them as opaque keys to lookup items, and avoid attempting
/// to parse them, or otherwise depend on any implementation details.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)))]
// FIXME(aDotInTheVoid): Consider making this non-public in rustdoc-types.
pub struct Id(pub u32);
@@ -494,6 +637,9 @@ pub enum AssocItemConstraintKind {
///
/// Part of [`ItemSummary`].
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(compare(PartialEq)))]
#[serde(rename_all = "snake_case")]
pub enum ItemKind {
/// A module declaration, e.g. `mod foo;` or `mod foo {}`
@@ -569,6 +715,8 @@ pub enum ItemKind {
///
/// Part of [`Item`].
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
#[serde(rename_all = "snake_case")]
pub enum ItemEnum {
/// A module declaration, e.g. `mod foo;` or `mod foo {}`
@@ -723,6 +871,8 @@ pub fn item_kind(&self) -> ItemKind {
/// A module declaration, e.g. `mod foo;` or `mod foo {}`.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
pub struct Module {
/// Whether this is the root item of a crate.
///
@@ -738,6 +888,8 @@ pub struct Module {
/// A `union`.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
pub struct Union {
/// The generic parameters and where clauses on this union.
pub generics: Generics,
@@ -755,6 +907,8 @@ pub struct Union {
/// A `struct`.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
pub struct Struct {
/// The kind of the struct (e.g. unit, tuple-like or struct-like) and the data specific to it,
/// i.e. fields.
@@ -768,6 +922,8 @@ pub struct Struct {
/// The kind of a [`Struct`] and the data specific to it, i.e. fields.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
#[serde(rename_all = "snake_case")]
pub enum StructKind {
/// A struct with no fields and no parentheses.
@@ -805,6 +961,8 @@ pub enum StructKind {
/// An `enum`.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
pub struct Enum {
/// Information about the type parameters and `where` clauses of the enum.
pub generics: Generics,
@@ -820,6 +978,8 @@ pub struct Enum {
/// A variant of an enum.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
pub struct Variant {
/// Whether the variant is plain, a tuple-like, or struct-like. Contains the fields.
pub kind: VariantKind,
@@ -829,6 +989,8 @@ pub struct Variant {
/// The kind of an [`Enum`] [`Variant`] and the data specific to it, i.e. fields.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
#[serde(rename_all = "snake_case")]
pub enum VariantKind {
/// A variant with no parentheses
@@ -872,6 +1034,8 @@ pub enum VariantKind {
/// The value that distinguishes a variant in an [`Enum`] from other variants.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
pub struct Discriminant {
/// The expression that produced the discriminant.
///
@@ -890,6 +1054,8 @@ pub struct Discriminant {
/// A set of fundamental properties of a function.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
pub struct FunctionHeader {
/// Is this function marked as `const`?
pub is_const: bool,
@@ -910,6 +1076,8 @@ pub struct FunctionHeader {
/// See the [Rustonomicon section](https://doc.rust-lang.org/nightly/nomicon/ffi.html#ffi-and-unwinding)
/// on unwinding for more info.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
pub enum Abi {
// We only have a concrete listing here for stable ABI's because there are so many
// See rustc_ast_passes::feature_gate::PostExpansionVisitor::check_abi for the list
@@ -937,6 +1105,8 @@ pub enum Abi {
/// A function declaration (including methods and other associated functions).
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
pub struct Function {
/// Information about the function signature, or declaration.
pub sig: FunctionSignature,
@@ -950,6 +1120,8 @@ pub struct Function {
/// Generic parameters accepted by an item and `where` clauses imposed on it and the parameters.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
pub struct Generics {
/// A list of generic parameter definitions (e.g. `<T: Clone + Hash, U: Copy>`).
pub params: Vec<GenericParamDef>,
@@ -959,6 +1131,8 @@ pub struct Generics {
/// One generic parameter accepted by an item.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
pub struct GenericParamDef {
/// Name of the parameter.
/// ```rust
@@ -973,6 +1147,18 @@ pub struct GenericParamDef {
/// The kind of a [`GenericParamDef`].
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(serialize_bounds(
__S: rkyv::ser::Writer + rkyv::ser::Allocator,
__S::Error: rkyv::rancor::Source,
)))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(deserialize_bounds(
__D::Error: rkyv::rancor::Source,
)))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(bytecheck(bounds(
__C: rkyv::validation::ArchiveContext,
))))]
#[serde(rename_all = "snake_case")]
pub enum GenericParamDefKind {
/// Denotes a lifetime parameter.
@@ -995,6 +1181,7 @@ pub enum GenericParamDefKind {
/// fn default2<T: Default>() -> [T; 2] where T: Clone { todo!() }
/// // ^^^^^^^
/// ```
#[cfg_attr(feature = "rkyv_0_8", rkyv(omit_bounds))]
bounds: Vec<GenericBound>,
/// The default type for this parameter, if provided, e.g.
///
@@ -1002,6 +1189,7 @@ pub enum GenericParamDefKind {
/// trait PartialEq<Rhs = Self> {}
/// // ^^^^
/// ```
#[cfg_attr(feature = "rkyv_0_8", rkyv(omit_bounds))]
default: Option<Type>,
/// This is normally `false`, which means that this generic parameter is
/// declared in the Rust source text.
@@ -1033,6 +1221,7 @@ pub enum GenericParamDefKind {
Const {
/// The type of the constant as declared.
#[serde(rename = "type")]
#[cfg_attr(feature = "rkyv_0_8", rkyv(omit_bounds))]
type_: Type,
/// The stringified expression for the default value, if provided. It's not guaranteed that
/// it'll match the actual source code for the default value.
@@ -1046,6 +1235,8 @@ pub enum GenericParamDefKind {
/// // ^^^^^^^^^^
/// ```
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
#[serde(rename_all = "snake_case")]
pub enum WherePredicate {
/// A type is expected to comply with a set of bounds
@@ -1092,6 +1283,8 @@ pub enum WherePredicate {
/// Either a trait bound or a lifetime bound.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
#[serde(rename_all = "snake_case")]
pub enum GenericBound {
/// A trait bound.
@@ -1122,6 +1315,8 @@ pub enum GenericBound {
/// A set of modifiers applied to a trait.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
#[serde(rename_all = "snake_case")]
pub enum TraitBoundModifier {
/// Marks the absence of a modifier.
@@ -1137,6 +1332,8 @@ pub enum TraitBoundModifier {
/// One precise capturing argument. See [the rust reference](https://doc.rust-lang.org/reference/types/impl-trait.html#precise-capturing).
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
#[serde(rename_all = "snake_case")]
pub enum PreciseCapturingArg {
/// A lifetime.
@@ -1154,6 +1351,8 @@ pub enum PreciseCapturingArg {
/// Either a type or a constant, usually stored as the right-hand side of an equation in places like
/// [`AssocItemConstraint`]
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
#[serde(rename_all = "snake_case")]
pub enum Term {
/// A type.
@@ -1178,6 +1377,18 @@ pub enum Term {
/// A type.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(serialize_bounds(
__S: rkyv::ser::Writer + rkyv::ser::Allocator,
__S::Error: rkyv::rancor::Source,
)))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(deserialize_bounds(
__D::Error: rkyv::rancor::Source,
)))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(bytecheck(bounds(
__C: rkyv::validation::ArchiveContext,
))))]
#[serde(rename_all = "snake_case")]
pub enum Type {
/// Structs, enums, unions and type aliases, e.g. `std::option::Option<u32>`
@@ -1189,15 +1400,16 @@ pub enum Type {
/// Built-in numeric types (e.g. `u32`, `f32`), `bool`, `char`.
Primitive(String),
/// A function pointer type, e.g. `fn(u32) -> u32`, `extern "C" fn() -> *const u8`
FunctionPointer(Box<FunctionPointer>),
FunctionPointer(#[cfg_attr(feature = "rkyv_0_8", rkyv(omit_bounds))] Box<FunctionPointer>),
/// A tuple type, e.g. `(String, u32, Box<usize>)`
Tuple(Vec<Type>),
Tuple(#[cfg_attr(feature = "rkyv_0_8", rkyv(omit_bounds))] Vec<Type>),
/// An unsized slice type, e.g. `[u32]`.
Slice(Box<Type>),
Slice(#[cfg_attr(feature = "rkyv_0_8", rkyv(omit_bounds))] Box<Type>),
/// An array type, e.g. `[u32; 15]`
Array {
/// The type of the contained element.
#[serde(rename = "type")]
#[cfg_attr(feature = "rkyv_0_8", rkyv(omit_bounds))]
type_: Box<Type>,
/// The stringified expression that is the length of the array.
///
@@ -1210,6 +1422,7 @@ pub enum Type {
Pat {
/// The base type, e.g. the `u32` in `u32 is 1..`
#[serde(rename = "type")]
#[cfg_attr(feature = "rkyv_0_8", rkyv(omit_bounds))]
type_: Box<Type>,
#[doc(hidden)]
__pat_unstable_do_not_use: String,
@@ -1224,6 +1437,7 @@ pub enum Type {
is_mutable: bool,
/// The type of the pointee.
#[serde(rename = "type")]
#[cfg_attr(feature = "rkyv_0_8", rkyv(omit_bounds))]
type_: Box<Type>,
},
/// `&'a mut String`, `&str`, etc.
@@ -1234,6 +1448,7 @@ pub enum Type {
is_mutable: bool,
/// The type of the pointee, e.g. the `i32` in `&'a mut i32`
#[serde(rename = "type")]
#[cfg_attr(feature = "rkyv_0_8", rkyv(omit_bounds))]
type_: Box<Type>,
},
/// Associated types like `<Type as Trait>::Name` and `T::Item` where
@@ -1252,6 +1467,7 @@ pub enum Type {
/// <core::slice::IterMut<'static, u32> as BetterIterator>::Item<'static>
/// // ^^^^^^^^^
/// ```
#[cfg_attr(feature = "rkyv_0_8", rkyv(omit_bounds))]
args: Option<Box<GenericArgs>>,
/// The type with which this type is associated.
///
@@ -1259,6 +1475,7 @@ pub enum Type {
/// <core::array::IntoIter<u32, 42> as Iterator>::Item
/// // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/// ```
#[cfg_attr(feature = "rkyv_0_8", rkyv(omit_bounds))]
self_type: Box<Type>,
/// `None` iff this is an *inherent* associated type.
#[serde(rename = "trait")]
@@ -1268,6 +1485,19 @@ pub enum Type {
/// A type that has a simple path to it. This is the kind of type of structs, unions, enums, etc.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(serialize_bounds(
__S: rkyv::ser::Writer + rkyv::ser::Allocator,
__S::Error: rkyv::rancor::Source,
)))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(deserialize_bounds(
__D::Error: rkyv::rancor::Source,
)))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(bytecheck(bounds(
__C: rkyv::validation::ArchiveContext,
<__C as rkyv::rancor::Fallible>::Error: rkyv::rancor::Source,
))))]
pub struct Path {
/// The path of the type.
///
@@ -1291,11 +1521,14 @@ pub struct Path {
/// std::borrow::Cow<'static, str>
/// // ^^^^^^^^^^^^^^
/// ```
#[cfg_attr(feature = "rkyv_0_8", rkyv(omit_bounds))]
pub args: Option<Box<GenericArgs>>,
}
/// A type that is a function pointer.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
pub struct FunctionPointer {
/// The signature of the function.
pub sig: FunctionSignature,
@@ -1312,6 +1545,8 @@ pub struct FunctionPointer {
/// The signature of a function.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
pub struct FunctionSignature {
/// List of argument names and their type.
///
@@ -1330,6 +1565,8 @@ pub struct FunctionSignature {
/// A `trait` declaration.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
pub struct Trait {
/// Whether the trait is marked `auto` and is thus implemented automatically
/// for all applicable types.
@@ -1354,6 +1591,8 @@ pub struct Trait {
///
/// See [the tracking issue](https://github.com/rust-lang/rust/issues/41517)
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
pub struct TraitAlias {
/// Information about the type parameters and `where` clauses of the alias.
pub generics: Generics,
@@ -1363,6 +1602,8 @@ pub struct TraitAlias {
/// An `impl` block.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
pub struct Impl {
/// Whether this impl is for an unsafe trait.
pub is_unsafe: bool,
@@ -1401,6 +1642,8 @@ pub struct Impl {
/// A `use` statement.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
#[serde(rename_all = "snake_case")]
pub struct Use {
/// The full path being imported.
@@ -1419,6 +1662,8 @@ pub struct Use {
/// A procedural macro.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
pub struct ProcMacro {
/// How this macro is supposed to be called: `foo!()`, `#[foo]` or `#[derive(foo)]`
pub kind: MacroKind,
@@ -1442,6 +1687,8 @@ pub struct ProcMacro {
/// The way a [`ProcMacro`] is declared to be used.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
#[serde(rename_all = "snake_case")]
pub enum MacroKind {
/// A bang macro `foo!()`.
@@ -1454,6 +1701,8 @@ pub enum MacroKind {
/// A type alias declaration, e.g. `type Pig = std::borrow::Cow<'static, str>;`
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
pub struct TypeAlias {
/// The type referred to by this alias.
#[serde(rename = "type")]
@@ -1464,6 +1713,8 @@ pub struct TypeAlias {
/// A `static` declaration.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
pub struct Static {
/// The type of the static.
#[serde(rename = "type")]
@@ -1494,6 +1745,8 @@ pub struct Static {
/// A primitive type declaration. Declarations of this kind can only come from the core library.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
pub struct Primitive {
/// The name of the type.
pub name: String,
+115
View File
@@ -38,3 +38,118 @@ fn test_union_info_roundtrip() {
let decoded: ItemEnum = bincode::deserialize(&encoded).unwrap();
assert_eq!(u, decoded);
}
#[cfg(feature = "rkyv_0_8")]
mod rkyv {
use std::fmt::Debug;
use rkyv::Archive;
use rkyv::api::high::{HighDeserializer, HighSerializer};
use rkyv::bytecheck::CheckBytes;
use rkyv::rancor::Strategy;
use rkyv::ser::allocator::ArenaHandle;
use rkyv::util::AlignedVec;
use rkyv::validation::Validator;
use rkyv::validation::archive::ArchiveValidator;
use rkyv::validation::shared::SharedValidator;
use crate::*;
#[test]
/// A test to exercise the (de)serialization roundtrip for a representative selection of types,
/// covering most of the rkyv-specific attributes we had to had.
fn test_rkyv_roundtrip() {
// Standard derives: a plain struct and union, mirroring the existing serde/bincode tests.
let s = ItemEnum::Struct(Struct {
generics: Generics { params: vec![], where_predicates: vec![] },
kind: StructKind::Plain { fields: vec![Id(1), Id(2)], has_stripped_fields: false },
impls: vec![Id(3)],
});
rkyv_roundtrip(&s);
let u = ItemEnum::Union(Union {
generics: Generics { params: vec![], where_predicates: vec![] },
has_stripped_fields: false,
fields: vec![Id(1)],
impls: vec![],
});
rkyv_roundtrip(&u);
// Extra trait derives, via rkyv(derive(PartialEq, Eq, PartialOrd, Ord, Hash)), on the archived type.
rkyv_roundtrip(&Id(99));
// Recursive cycle-breaking: `BorrowedRef` has omit_bounds on its `Box<Type>` field.
let ty = Type::BorrowedRef {
lifetime: Some("'a".to_string()),
is_mutable: false,
type_: Box::new(Type::Primitive("str".to_string())),
};
rkyv_roundtrip(&ty);
// `Slice` and `Tuple` are tuple-variant fields with omit_bounds on the unnamed field,
// which required special syntax (attribute inside the parentheses) to compile.
let ty = Type::Slice(Box::new(Type::Tuple(vec![
Type::Primitive("u32".to_string()),
Type::Generic("T".to_string()),
])));
rkyv_roundtrip(&ty);
// `Path` has serialize_bounds/deserialize_bounds and omit_bounds on its `args` field.
// `GenericArgs::AngleBracketed` exercises the full recursive chain: `Path` -> `GenericArgs` -> `GenericArg` -> `Type`.
let path = Path {
path: "std::option::Option".to_string(),
id: Id(42),
args: Some(Box::new(GenericArgs::AngleBracketed {
args: vec![GenericArg::Type(Type::Primitive("u32".to_string()))],
constraints: vec![],
})),
};
rkyv_roundtrip(&path);
// `FunctionPointer` is a `Box<FunctionPointer>` behind `omit_bounds` in `Type`.
// It transitively contains `Type` via `FunctionSignature`, exercising the cycle from the other direction.
let fp = Type::FunctionPointer(Box::new(FunctionPointer {
sig: FunctionSignature {
inputs: vec![("x".to_string(), Type::Primitive("i32".to_string()))],
output: Some(Type::Primitive("bool".to_string())),
is_c_variadic: false,
},
generic_params: vec![],
header: FunctionHeader {
is_const: false,
is_unsafe: false,
is_async: false,
abi: Abi::Rust,
},
}));
rkyv_roundtrip(&fp);
}
/// A helper function for roundtrip testing of rkyv-powered deserialization.
fn rkyv_roundtrip<T>(value: &T)
where
T: PartialEq
+ Debug
+ Archive
+ for<'a> rkyv::Serialize<
HighSerializer<AlignedVec, ArenaHandle<'a>, rkyv::rancor::Error>,
>,
T::Archived: rkyv::Deserialize<T, HighDeserializer<rkyv::rancor::Error>>
+ Debug
+ for<'a> CheckBytes<
Strategy<Validator<ArchiveValidator<'a>, SharedValidator>, rkyv::rancor::Error>,
>,
{
let bytes =
rkyv::api::high::to_bytes_in::<_, rkyv::rancor::Error>(value, AlignedVec::new())
.unwrap();
let archived = rkyv::api::high::access::<T::Archived, rkyv::rancor::Error>(&bytes)
.expect("Failed to access archived data");
let deserialized: T = rkyv::api::deserialize_using::<_, _, rkyv::rancor::Error>(
archived,
&mut rkyv::de::Pool::new(),
)
.unwrap();
assert_eq!(value, &deserialized);
}
}