Skip to content

Commit 0a6543b

Browse files
committed
[derive] Use macro to generate some scaffolding
This allows us to define proc macros as functions that take an already-parsed `&DeriveInput` rather than just a `TokenStream` which must be parsed. This, in turn, allows us to pass an already-parsed `&DeriveInput` when one proc macro invokes another (e.g., when the derive for `FromBytes` invokes the derive for `FromZeros`) rather than needing to clone the `TokenStream`.
1 parent 11ced18 commit 0a6543b

File tree

1 file changed

+67
-79
lines changed

1 file changed

+67
-79
lines changed

zerocopy-derive/src/lib.rs

Lines changed: 67 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,39 @@ macro_rules! try_or_print {
7272
// (https://doc.rust-lang.org/nightly/proc_macro/struct.Span.html#method.error),
7373
// which is currently unstable. Revisit this once it's stable.
7474

75-
#[proc_macro_derive(KnownLayout)]
76-
pub fn derive_known_layout(ts: proc_macro::TokenStream) -> proc_macro::TokenStream {
77-
let ast = syn::parse_macro_input!(ts as DeriveInput);
75+
/// Defines a derive function named `$outer` which parses its input
76+
/// `TokenStream` as a `DeriveInput` and then invokes the `$inner` function.
77+
///
78+
/// Note that the separate `$outer` parameter is required - proc macro functions
79+
/// are currently required to live at the crate root, and so the caller must
80+
/// specify the name in order to avoid name collisions.
81+
macro_rules! derive {
82+
($trait:ident => $outer:ident => $inner:ident) => {
83+
#[proc_macro_derive($trait)]
84+
pub fn $outer(ts: proc_macro::TokenStream) -> proc_macro::TokenStream {
85+
let ast = syn::parse_macro_input!(ts as DeriveInput);
86+
$inner(&ast).into()
87+
}
88+
};
89+
}
90+
91+
derive!(KnownLayout => derive_known_layout => derive_known_layout_inner);
92+
derive!(NoCell => derive_no_cell => derive_no_cell_inner);
93+
derive!(TryFromBytes => derive_try_from_bytes => derive_try_from_bytes_inner);
94+
derive!(FromZeros => derive_from_zeros => derive_from_zeros_inner);
95+
derive!(FromBytes => derive_from_bytes => derive_from_bytes_inner);
96+
derive!(IntoBytes => derive_as_bytes => derive_as_bytes_inner);
97+
derive!(Unaligned => derive_unaligned => derive_unaligned_inner);
98+
99+
/// Deprecated: prefer [`FromZeros`] instead.
100+
#[deprecated(since = "0.8.0", note = "`FromZeroes` was renamed to `FromZeros`")]
101+
#[doc(hidden)]
102+
#[proc_macro_derive(FromZeroes)]
103+
pub fn derive_from_zeroes(ts: proc_macro::TokenStream) -> proc_macro::TokenStream {
104+
derive_from_zeros(ts)
105+
}
78106

107+
fn derive_known_layout_inner(ast: &DeriveInput) -> proc_macro2::TokenStream {
79108
let is_repr_c_struct = match &ast.data {
80109
Data::Struct(..) => {
81110
let reprs = try_or_print!(repr::reprs::<Repr>(&ast.attrs));
@@ -208,7 +237,7 @@ pub fn derive_known_layout(ts: proc_macro::TokenStream) -> proc_macro::TokenStre
208237
// of an usized trailing field requires that the field is
209238
// `KnownLayout`.
210239
impl_block(
211-
&ast,
240+
ast,
212241
strct,
213242
Trait::KnownLayout,
214243
require_trait_bound_on_field_types,
@@ -221,7 +250,7 @@ pub fn derive_known_layout(ts: proc_macro::TokenStream) -> proc_macro::TokenStre
221250
// A bound on the trailing field is not required, since enums cannot
222251
// currently be unsized.
223252
impl_block(
224-
&ast,
253+
ast,
225254
enm,
226255
Trait::KnownLayout,
227256
FieldBounds::None,
@@ -234,7 +263,7 @@ pub fn derive_known_layout(ts: proc_macro::TokenStream) -> proc_macro::TokenStre
234263
// A bound on the trailing field is not required, since unions
235264
// cannot currently be unsized.
236265
impl_block(
237-
&ast,
266+
ast,
238267
unn,
239268
Trait::KnownLayout,
240269
FieldBounds::None,
@@ -244,112 +273,71 @@ pub fn derive_known_layout(ts: proc_macro::TokenStream) -> proc_macro::TokenStre
244273
)
245274
}
246275
}
247-
.into()
248276
}
249277

250-
#[proc_macro_derive(NoCell)]
251-
pub fn derive_no_cell(ts: proc_macro::TokenStream) -> proc_macro::TokenStream {
252-
let ast = syn::parse_macro_input!(ts as DeriveInput);
278+
fn derive_no_cell_inner(ast: &DeriveInput) -> proc_macro2::TokenStream {
253279
match &ast.data {
254280
Data::Struct(strct) => impl_block(
255-
&ast,
281+
ast,
256282
strct,
257283
Trait::NoCell,
258284
FieldBounds::ALL_SELF,
259285
SelfBounds::None,
260286
None,
261287
None,
262288
),
263-
Data::Enum(enm) => impl_block(
264-
&ast,
265-
enm,
266-
Trait::NoCell,
267-
FieldBounds::ALL_SELF,
268-
SelfBounds::None,
269-
None,
270-
None,
271-
),
272-
Data::Union(unn) => impl_block(
273-
&ast,
274-
unn,
275-
Trait::NoCell,
276-
FieldBounds::ALL_SELF,
277-
SelfBounds::None,
278-
None,
279-
None,
280-
),
289+
Data::Enum(enm) => {
290+
impl_block(ast, enm, Trait::NoCell, FieldBounds::ALL_SELF, SelfBounds::None, None, None)
291+
}
292+
Data::Union(unn) => {
293+
impl_block(ast, unn, Trait::NoCell, FieldBounds::ALL_SELF, SelfBounds::None, None, None)
294+
}
281295
}
282-
.into()
283296
}
284297

285-
#[proc_macro_derive(TryFromBytes)]
286-
pub fn derive_try_from_bytes(ts: proc_macro::TokenStream) -> proc_macro::TokenStream {
287-
let ast = syn::parse_macro_input!(ts as DeriveInput);
298+
fn derive_try_from_bytes_inner(ast: &DeriveInput) -> proc_macro2::TokenStream {
288299
match &ast.data {
289-
Data::Struct(strct) => derive_try_from_bytes_struct(&ast, strct),
290-
Data::Enum(enm) => derive_try_from_bytes_enum(&ast, enm),
291-
Data::Union(unn) => derive_try_from_bytes_union(&ast, unn),
300+
Data::Struct(strct) => derive_try_from_bytes_struct(ast, strct),
301+
Data::Enum(enm) => derive_try_from_bytes_enum(ast, enm),
302+
Data::Union(unn) => derive_try_from_bytes_union(ast, unn),
292303
}
293-
.into()
294304
}
295305

296-
#[proc_macro_derive(FromZeros)]
297-
pub fn derive_from_zeros(ts: proc_macro::TokenStream) -> proc_macro::TokenStream {
298-
let try_from_bytes = derive_try_from_bytes(ts.clone());
299-
300-
let ast = syn::parse_macro_input!(ts as DeriveInput);
306+
fn derive_from_zeros_inner(ast: &DeriveInput) -> proc_macro2::TokenStream {
307+
let try_from_bytes = derive_try_from_bytes_inner(ast);
301308
let from_zeros = match &ast.data {
302-
Data::Struct(strct) => derive_from_zeros_struct(&ast, strct),
303-
Data::Enum(enm) => derive_from_zeros_enum(&ast, enm),
304-
Data::Union(unn) => derive_from_zeros_union(&ast, unn),
305-
}
306-
.into();
309+
Data::Struct(strct) => derive_from_zeros_struct(ast, strct),
310+
Data::Enum(enm) => derive_from_zeros_enum(ast, enm),
311+
Data::Union(unn) => derive_from_zeros_union(ast, unn),
312+
};
307313
IntoIterator::into_iter([try_from_bytes, from_zeros]).collect()
308314
}
309315

310-
/// Deprecated: prefer [`FromZeros`] instead.
311-
#[deprecated(since = "0.8.0", note = "`FromZeroes` was renamed to `FromZeros`")]
312-
#[doc(hidden)]
313-
#[proc_macro_derive(FromZeroes)]
314-
pub fn derive_from_zeroes(ts: proc_macro::TokenStream) -> proc_macro::TokenStream {
315-
derive_from_zeros(ts)
316-
}
317-
318-
#[proc_macro_derive(FromBytes)]
319-
pub fn derive_from_bytes(ts: proc_macro::TokenStream) -> proc_macro::TokenStream {
320-
let from_zeros = derive_from_zeros(ts.clone());
321-
322-
let ast = syn::parse_macro_input!(ts as DeriveInput);
316+
fn derive_from_bytes_inner(ast: &DeriveInput) -> proc_macro2::TokenStream {
317+
let from_zeros = derive_from_zeros_inner(ast);
323318
let from_bytes = match &ast.data {
324-
Data::Struct(strct) => derive_from_bytes_struct(&ast, strct),
325-
Data::Enum(enm) => derive_from_bytes_enum(&ast, enm),
326-
Data::Union(unn) => derive_from_bytes_union(&ast, unn),
327-
}
328-
.into();
319+
Data::Struct(strct) => derive_from_bytes_struct(ast, strct),
320+
Data::Enum(enm) => derive_from_bytes_enum(ast, enm),
321+
Data::Union(unn) => derive_from_bytes_union(ast, unn),
322+
};
329323

330324
IntoIterator::into_iter([from_zeros, from_bytes]).collect()
331325
}
332326

333-
#[proc_macro_derive(IntoBytes)]
334-
pub fn derive_as_bytes(ts: proc_macro::TokenStream) -> proc_macro::TokenStream {
335-
let ast = syn::parse_macro_input!(ts as DeriveInput);
327+
fn derive_as_bytes_inner(ast: &DeriveInput) -> proc_macro2::TokenStream {
336328
match &ast.data {
337-
Data::Struct(strct) => derive_as_bytes_struct(&ast, strct),
338-
Data::Enum(enm) => derive_as_bytes_enum(&ast, enm),
339-
Data::Union(unn) => derive_as_bytes_union(&ast, unn),
329+
Data::Struct(strct) => derive_as_bytes_struct(ast, strct),
330+
Data::Enum(enm) => derive_as_bytes_enum(ast, enm),
331+
Data::Union(unn) => derive_as_bytes_union(ast, unn),
340332
}
341-
.into()
342333
}
343334

344-
#[proc_macro_derive(Unaligned)]
345-
pub fn derive_unaligned(ts: proc_macro::TokenStream) -> proc_macro::TokenStream {
346-
let ast = syn::parse_macro_input!(ts as DeriveInput);
335+
fn derive_unaligned_inner(ast: &DeriveInput) -> proc_macro2::TokenStream {
347336
match &ast.data {
348-
Data::Struct(strct) => derive_unaligned_struct(&ast, strct),
349-
Data::Enum(enm) => derive_unaligned_enum(&ast, enm),
350-
Data::Union(unn) => derive_unaligned_union(&ast, unn),
337+
Data::Struct(strct) => derive_unaligned_struct(ast, strct),
338+
Data::Enum(enm) => derive_unaligned_enum(ast, enm),
339+
Data::Union(unn) => derive_unaligned_union(ast, unn),
351340
}
352-
.into()
353341
}
354342

355343
// A struct is `TryFromBytes` if:

0 commit comments

Comments
 (0)