From 1d81c5021a21453e77ca2a0cd7f2a8006e9775ae Mon Sep 17 00:00:00 2001 From: Luca Palmieri <20745048+LukeMathWalker@users.noreply.github.com> Date: Mon, 2 Mar 2026 12:54:24 +0100 Subject: [PATCH 1/2] feat(rustdoc-json): Add optional support for rkyv (de)serialization --- Cargo.lock | 124 ++++++++++ src/bootstrap/src/core/build_steps/test.rs | 2 +- src/rustdoc-json-types/Cargo.toml | 2 + src/rustdoc-json-types/lib.rs | 259 ++++++++++++++++++++- src/rustdoc-json-types/tests.rs | 115 +++++++++ 5 files changed, 497 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7f1cf4850c8a2..a913c39cef471 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" @@ -4789,6 +4906,7 @@ name = "rustdoc-json-types" version = "0.1.0" dependencies = [ "bincode", + "rkyv", "rustc-hash 2.1.1", "serde", "serde_derive", @@ -5127,6 +5245,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" diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 88f10775333d4..ab1d2b8a24b6e 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -3302,7 +3302,7 @@ impl Step for CrateRustdocJsonTypes { 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. diff --git a/src/rustdoc-json-types/Cargo.toml b/src/rustdoc-json-types/Cargo.toml index a38d34ef0e7d9..7e4e53ccaf0de 100644 --- a/src/rustdoc-json-types/Cargo.toml +++ b/src/rustdoc-json-types/Cargo.toml @@ -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" diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 9a59de4f844ab..3cf1fa22b2465 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -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,79 @@ //! 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`](rkyv::Archive), [`Serialize`](rkyv::Serialize) and [`Deserialize`](rkyv::Deserialize) +//! 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][3]. +//! 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://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` 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>` +// - One of the variants in `GenericArgs` has a field of type `Vec` +// - 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`. `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`, `Vec`) 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 +121,8 @@ pub const FORMAT_VERSION: u32 = 57; /// 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 +146,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 +178,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 +204,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 +223,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 +234,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 +257,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 +297,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 +346,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 +367,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 +388,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 +402,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, @@ -314,6 +413,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 +438,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, @@ -352,6 +455,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 +476,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 +504,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, /// The output type provided after the `->`, if present. + #[cfg_attr(feature = "rkyv_0_8", rkyv(omit_bounds))] output: Option, }, /// `T::method(..)` @@ -399,6 +518,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 +550,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 +571,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>, /// The kind of bound applied to the associated type/constant. pub binding: AssocItemConstraintKind, @@ -459,6 +596,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 +626,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 +635,9 @@ pub struct Id(pub u32); /// /// 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 +713,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 {}` @@ -684,6 +830,8 @@ pub enum ItemEnum { /// 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. /// @@ -699,6 +847,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, @@ -716,6 +866,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. @@ -729,6 +881,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. @@ -766,6 +920,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, @@ -781,6 +937,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, @@ -790,6 +948,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 @@ -833,6 +993,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. /// @@ -851,6 +1013,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, @@ -871,6 +1035,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 @@ -898,6 +1064,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, @@ -911,6 +1079,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. ``). pub params: Vec, @@ -920,6 +1090,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 @@ -934,6 +1106,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. @@ -956,6 +1140,7 @@ pub enum GenericParamDefKind { /// fn default2() -> [T; 2] where T: Clone { todo!() } /// // ^^^^^^^ /// ``` + #[cfg_attr(feature = "rkyv_0_8", rkyv(omit_bounds))] bounds: Vec, /// The default type for this parameter, if provided, e.g. /// @@ -963,6 +1148,7 @@ pub enum GenericParamDefKind { /// trait PartialEq {} /// // ^^^^ /// ``` + #[cfg_attr(feature = "rkyv_0_8", rkyv(omit_bounds))] default: Option, /// This is normally `false`, which means that this generic parameter is /// declared in the Rust source text. @@ -994,6 +1180,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. @@ -1007,6 +1194,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 @@ -1053,6 +1242,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. @@ -1083,6 +1274,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. @@ -1098,6 +1291,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. @@ -1115,6 +1310,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. @@ -1139,6 +1336,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` @@ -1150,15 +1359,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(#[cfg_attr(feature = "rkyv_0_8", rkyv(omit_bounds))] Box), /// A tuple type, e.g. `(String, u32, Box)` - Tuple(Vec), + Tuple(#[cfg_attr(feature = "rkyv_0_8", rkyv(omit_bounds))] Vec), /// An unsized slice type, e.g. `[u32]`. - Slice(Box), + Slice(#[cfg_attr(feature = "rkyv_0_8", rkyv(omit_bounds))] Box), /// 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, /// The stringified expression that is the length of the array. /// @@ -1171,6 +1381,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, #[doc(hidden)] __pat_unstable_do_not_use: String, @@ -1185,6 +1396,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, }, /// `&'a mut String`, `&str`, etc. @@ -1195,6 +1407,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, }, /// Associated types like `::Name` and `T::Item` where @@ -1213,6 +1426,7 @@ pub enum Type { /// as BetterIterator>::Item<'static> /// // ^^^^^^^^^ /// ``` + #[cfg_attr(feature = "rkyv_0_8", rkyv(omit_bounds))] args: Option>, /// The type with which this type is associated. /// @@ -1220,6 +1434,7 @@ pub enum Type { /// as Iterator>::Item /// // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /// ``` + #[cfg_attr(feature = "rkyv_0_8", rkyv(omit_bounds))] self_type: Box, /// `None` iff this is an *inherent* associated type. #[serde(rename = "trait")] @@ -1229,6 +1444,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. /// @@ -1252,11 +1480,14 @@ pub struct Path { /// std::borrow::Cow<'static, str> /// // ^^^^^^^^^^^^^^ /// ``` + #[cfg_attr(feature = "rkyv_0_8", rkyv(omit_bounds))] pub args: Option>, } /// 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, @@ -1273,6 +1504,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. /// @@ -1291,6 +1524,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. @@ -1315,6 +1550,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, @@ -1324,6 +1561,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, @@ -1362,6 +1601,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. @@ -1380,6 +1621,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, @@ -1403,6 +1646,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!()`. @@ -1415,6 +1660,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")] @@ -1425,6 +1672,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")] @@ -1455,6 +1704,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, diff --git a/src/rustdoc-json-types/tests.rs b/src/rustdoc-json-types/tests.rs index b9363fcf1b714..e878350e43b9b 100644 --- a/src/rustdoc-json-types/tests.rs +++ b/src/rustdoc-json-types/tests.rs @@ -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` 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` 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(value: &T) + where + T: PartialEq + + Debug + + Archive + + for<'a> rkyv::Serialize< + HighSerializer, rkyv::rancor::Error>, + >, + T::Archived: rkyv::Deserialize> + + Debug + + for<'a> CheckBytes< + Strategy, 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::(&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); + } +} From 1f05c768be37d3d54ae8ebb61357957602d40052 Mon Sep 17 00:00:00 2001 From: Luca Palmieri <20745048+LukeMathWalker@users.noreply.github.com> Date: Tue, 10 Mar 2026 09:46:45 +0100 Subject: [PATCH 2/2] doc: Avoid intra-doc links that don't resolve if the rkyv_0_8 feature isn't enabled --- src/rustdoc-json-types/lib.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 3cf1fa22b2465..21f83617ef34c 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -19,18 +19,20 @@ //! ## `rkyv_0_8` //! //! We expose a `rkyv_0_8` feature, disabled by default. When enabled, it derives `rkyv`'s -//! [`Archive`](rkyv::Archive), [`Serialize`](rkyv::Serialize) and [`Deserialize`](rkyv::Deserialize) -//! traits for all types in this crate. Furthermore, it exposes the corresponding `Archived*` types -//! (e.g. [`ArchivedId`] for [`Id`]). +//! [`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][3]. +//! 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://rkyv.org/zero-copy-deserialization.html +//! [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 //