diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index df2f67b..65cf4fc 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -12,13 +12,11 @@ env: jobs: cargo-test: runs-on: ubuntu-latest - strategy: - matrix: - features: - - default - - rustc-hash steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable + - uses: taiki-e/install-action@a37010ded18ff788be4440302bd6830b1ae50d8b # v2.68.25 + with: + tool: cargo-hack@0.6.43 - uses: Swatinem/rust-cache@v2 - - run: cargo test --no-default-features --features '${{ matrix.features }}' + - run: cargo hack test --feature-powerset diff --git a/COMMIT.txt b/COMMIT.txt index deaea35..ee50144 100644 --- a/COMMIT.txt +++ b/COMMIT.txt @@ -1 +1 @@ -931e2c4e43fde6a308ee9933538142ed0927f6d9 +1d81c5021a21453e77ca2a0cd7f2a8006e9775ae diff --git a/Cargo.toml b/Cargo.toml index 9c760ce..76708bd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,15 +12,13 @@ include = ["Cargo.toml", "CHANGELOG.md", "README.md", "LICENSE-MIT", "LICENSE-AP serde = {version="1.0.186"} serde_derive = {version="1.0.186"} rustc-hash = {version="2", optional=true} +rkyv = { version = "0.8", optional = true } [features] -default = [] +default = [] # TODO: Remove this next time we make a breaking release -# Switch the hashmaps used in rustdoc-types to the FxHashMap from rustc-hash. -# -# This might improve performace if your are reading the rustdoc JSON from large -# crates like aws_sdk_ec2 rustc-hash = ["dep:rustc-hash"] +rkyv_0_8 = ["dep:rkyv"] [dev-dependencies] bincode = "1.3.3" diff --git a/src/lib.rs b/src/lib.rs index b45ead9..42cf5c9 100644 --- a/src/lib.rs +++ b/src/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; @@ -45,6 +120,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, @@ -68,6 +145,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, @@ -98,6 +177,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, @@ -122,6 +203,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. /// @@ -139,6 +222,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, } @@ -149,6 +233,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. @@ -170,6 +256,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, @@ -208,6 +296,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)]` /// @@ -255,6 +345,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`]. @@ -274,6 +366,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]`. /// @@ -293,8 +387,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), @@ -304,6 +401,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, @@ -313,6 +412,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`. @@ -336,6 +437,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, @@ -351,6 +454,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")] @@ -370,6 +475,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>` @@ -386,8 +503,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(..)` @@ -398,6 +517,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. @@ -428,6 +549,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. @@ -447,10 +570,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, @@ -458,6 +595,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. @@ -486,6 +625,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); @@ -493,6 +634,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 {}` @@ -568,6 +712,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 {}` @@ -681,41 +827,10 @@ pub enum ItemEnum { }, } -impl ItemEnum { - /// Returns the [`ItemKind`] of this item. - pub fn item_kind(&self) -> ItemKind { - match self { - ItemEnum::Module(_) => ItemKind::Module, - ItemEnum::ExternCrate { .. } => ItemKind::ExternCrate, - ItemEnum::Use(_) => ItemKind::Use, - ItemEnum::Union(_) => ItemKind::Union, - ItemEnum::Struct(_) => ItemKind::Struct, - ItemEnum::StructField(_) => ItemKind::StructField, - ItemEnum::Enum(_) => ItemKind::Enum, - ItemEnum::Variant(_) => ItemKind::Variant, - ItemEnum::Function(_) => ItemKind::Function, - ItemEnum::Trait(_) => ItemKind::Trait, - ItemEnum::TraitAlias(_) => ItemKind::TraitAlias, - ItemEnum::Impl(_) => ItemKind::Impl, - ItemEnum::TypeAlias(_) => ItemKind::TypeAlias, - ItemEnum::Constant { .. } => ItemKind::Constant, - ItemEnum::Static(_) => ItemKind::Static, - ItemEnum::ExternType => ItemKind::ExternType, - ItemEnum::Macro(_) => ItemKind::Macro, - ItemEnum::ProcMacro(pm) => match pm.kind { - MacroKind::Bang => ItemKind::Macro, - MacroKind::Attr => ItemKind::ProcAttribute, - MacroKind::Derive => ItemKind::ProcDerive, - }, - ItemEnum::Primitive(_) => ItemKind::Primitive, - ItemEnum::AssocConst { .. } => ItemKind::AssocConst, - ItemEnum::AssocType { .. } => ItemKind::AssocType, - } - } -} - /// 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. /// @@ -731,6 +846,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, @@ -748,6 +865,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. @@ -761,6 +880,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. @@ -798,6 +919,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, @@ -813,6 +936,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, @@ -822,6 +947,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 @@ -865,6 +992,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. /// @@ -883,6 +1012,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, @@ -903,6 +1034,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 @@ -930,6 +1063,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, @@ -943,6 +1078,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, @@ -952,6 +1089,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 @@ -966,6 +1105,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. @@ -988,6 +1139,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. /// @@ -995,6 +1147,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. @@ -1026,6 +1179,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. @@ -1039,6 +1193,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 @@ -1085,6 +1241,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. @@ -1115,6 +1273,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. @@ -1130,6 +1290,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. @@ -1147,6 +1309,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. @@ -1171,6 +1335,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` @@ -1182,15 +1358,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. /// @@ -1203,6 +1380,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, @@ -1217,6 +1395,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. @@ -1227,6 +1406,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 @@ -1245,6 +1425,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. /// @@ -1252,6 +1433,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")] @@ -1261,6 +1443,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. /// @@ -1284,11 +1479,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, @@ -1305,6 +1503,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. /// @@ -1323,6 +1523,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. @@ -1347,6 +1549,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, @@ -1356,6 +1560,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, @@ -1394,6 +1600,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. @@ -1412,6 +1620,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, @@ -1435,6 +1645,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!()`. @@ -1447,6 +1659,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")] @@ -1457,6 +1671,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")] @@ -1487,6 +1703,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/tests.rs b/src/tests.rs index b9363fc..e878350 100644 --- a/src/tests.rs +++ b/src/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); + } +}