From 9a0d277803d54383a7ae40348856e390c322ae25 Mon Sep 17 00:00:00 2001 From: Jack Wrenn Date: Wed, 27 May 2026 10:42:24 +0000 Subject: [PATCH] [wip] Introduce unstable `derive(most_traits)` gherrit-pr-id: G713b9f3eb6365b11e4e1777ee69e75a6fae758d3 --- zerocopy-derive/src/derive/mod.rs | 6 +++--- zerocopy-derive/src/lib.rs | 32 +++++++++++++++++++++++++++++++ zerocopy-derive/src/util.rs | 5 +++++ 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/zerocopy-derive/src/derive/mod.rs b/zerocopy-derive/src/derive/mod.rs index a3d066ed2b..943658ff56 100644 --- a/zerocopy-derive/src/derive/mod.rs +++ b/zerocopy-derive/src/derive/mod.rs @@ -13,8 +13,8 @@ use crate::{ util::{Ctx, DataExt, FieldBounds, ImplBlockBuilder, Trait}, }; -pub(crate) fn derive_immutable(ctx: &Ctx, _top_level: Trait) -> TokenStream { - match &ctx.ast.data { +pub(crate) fn derive_immutable(ctx: &Ctx, _top_level: Trait) -> Result { + Ok(match &ctx.ast.data { Data::Struct(strct) => { ImplBlockBuilder::new(ctx, strct, Trait::Immutable, FieldBounds::ALL_SELF).build() } @@ -24,7 +24,7 @@ pub(crate) fn derive_immutable(ctx: &Ctx, _top_level: Trait) -> TokenStream { Data::Union(unn) => { ImplBlockBuilder::new(ctx, unn, Trait::Immutable, FieldBounds::ALL_SELF).build() } - } + }) } pub(crate) fn derive_hash(ctx: &Ctx, _top_level: Trait) -> Result { diff --git a/zerocopy-derive/src/lib.rs b/zerocopy-derive/src/lib.rs index a1d10a2ada..fcc070d13c 100644 --- a/zerocopy-derive/src/lib.rs +++ b/zerocopy-derive/src/lib.rs @@ -127,6 +127,38 @@ derive!(ByteHash => derive_hash => crate::derive::derive_hash); derive!(ByteEq => derive_eq => crate::derive::derive_eq); derive!(SplitAt => derive_split_at => crate::derive::derive_split_at); +#[cfg(not(zerocopy_unstable_derive_on_error))] +#[proc_macro_derive(most_traits, attributes(zerocopy))] +pub fn most_traits(ts: proc_macro::TokenStream) -> proc_macro::TokenStream { + let ast = syn::parse_macro_input!(ts as DeriveInput); + let ctx = match Ctx::try_from_derive_input(ast) { + Ok(ctx) => ctx, + Err(e) => return e.into_compile_error().into(), + } + .skip_on_error(); + + // top-level traits for which to attempt a derive + let derives: [(fn(&Ctx, Trait) -> _, _); 4] = [ + (crate::derive::known_layout::derive, Trait::KnownLayout), + (crate::derive::derive_immutable, Trait::Immutable), + (crate::derive::try_from_bytes::derive_try_from_bytes, Trait::FromBytes), + (crate::derive::into_bytes::derive_into_bytes, Trait::IntoBytes), + ]; + + let mut tokens = proc_macro2::TokenStream::new(); + for (derive, t) in derives { + tokens.extend(derive(&ctx, t)) + } + + // We wrap in `const_block` as a backstop in case any derive fails + // to wrap its output in `const_block` (and thus fails to annotate) + // with the full set of `#[allow(...)]` attributes). + let ts = const_block([Some(tokens)]); + #[cfg(test)] + crate::util::testutil::check_hygiene(ts.clone()); + ts.into() +} + /// Deprecated: prefer [`FromZeros`] instead. #[deprecated(since = "0.8.0", note = "`FromZeroes` was renamed to `FromZeros`")] #[doc(hidden)] diff --git a/zerocopy-derive/src/util.rs b/zerocopy-derive/src/util.rs index 4ec28bf957..146d33bf97 100644 --- a/zerocopy-derive/src/util.rs +++ b/zerocopy-derive/src/util.rs @@ -96,6 +96,11 @@ impl Ctx { } } + pub(crate) fn skip_on_error(mut self) -> Self { + self.skip_on_error = true; + self + } + pub(crate) fn core_path(&self) -> TokenStream { let zerocopy_crate = &self.zerocopy_crate; quote!(#zerocopy_crate::util::macro_util::core_reexport)