1 | //! Derive macros for [bytemuck](https://docs.rs/bytemuck) traits.
|
2 |
|
3 | extern crate proc_macro;
|
4 |
|
5 | mod traits;
|
6 |
|
7 | use proc_macro2::TokenStream;
|
8 | use quote::quote;
|
9 | use syn::{parse_macro_input, DeriveInput, Result};
|
10 |
|
11 | use crate::traits::{
|
12 | bytemuck_crate_name, AnyBitPattern, CheckedBitPattern, Contiguous, Derivable,
|
13 | NoUninit, Pod, TransparentWrapper, Zeroable,
|
14 | };
|
15 |
|
16 | /// Derive the `Pod` trait for a struct
|
17 | ///
|
18 | /// The macro ensures that the struct follows all the the safety requirements
|
19 | /// for the `Pod` trait.
|
20 | ///
|
21 | /// The following constraints need to be satisfied for the macro to succeed
|
22 | ///
|
23 | /// - All fields in the struct must implement `Pod`
|
24 | /// - The struct must be `#[repr(C)]` or `#[repr(transparent)]`
|
25 | /// - The struct must not contain any padding bytes
|
26 | /// - The struct contains no generic parameters, if it is not
|
27 | /// `#[repr(transparent)]`
|
28 | ///
|
29 | /// ## Examples
|
30 | ///
|
31 | /// ```rust
|
32 | /// # use std::marker::PhantomData;
|
33 | /// # use bytemuck_derive::{Pod, Zeroable};
|
34 | /// #[derive(Copy, Clone, Pod, Zeroable)]
|
35 | /// #[repr(C)]
|
36 | /// struct Test {
|
37 | /// a: u16,
|
38 | /// b: u16,
|
39 | /// }
|
40 | ///
|
41 | /// #[derive(Copy, Clone, Pod, Zeroable)]
|
42 | /// #[repr(transparent)]
|
43 | /// struct Generic<A, B> {
|
44 | /// a: A,
|
45 | /// b: PhantomData<B>,
|
46 | /// }
|
47 | /// ```
|
48 | ///
|
49 | /// If the struct is generic, it must be `#[repr(transparent)]` also.
|
50 | ///
|
51 | /// ```compile_fail
|
52 | /// # use bytemuck::{Pod, Zeroable};
|
53 | /// # use std::marker::PhantomData;
|
54 | /// #[derive(Copy, Clone, Pod, Zeroable)]
|
55 | /// #[repr(C)] // must be `#[repr(transparent)]`
|
56 | /// struct Generic<A> {
|
57 | /// a: A,
|
58 | /// }
|
59 | /// ```
|
60 | ///
|
61 | /// If the struct is generic and `#[repr(transparent)]`, then it is only `Pod`
|
62 | /// when all of its generics are `Pod`, not just its fields.
|
63 | ///
|
64 | /// ```
|
65 | /// # use bytemuck::{Pod, Zeroable};
|
66 | /// # use std::marker::PhantomData;
|
67 | /// #[derive(Copy, Clone, Pod, Zeroable)]
|
68 | /// #[repr(transparent)]
|
69 | /// struct Generic<A, B> {
|
70 | /// a: A,
|
71 | /// b: PhantomData<B>,
|
72 | /// }
|
73 | ///
|
74 | /// let _: u32 = bytemuck::cast(Generic { a: 4u32, b: PhantomData::<u32> });
|
75 | /// ```
|
76 | ///
|
77 | /// ```compile_fail
|
78 | /// # use bytemuck::{Pod, Zeroable};
|
79 | /// # use std::marker::PhantomData;
|
80 | /// # #[derive(Copy, Clone, Pod, Zeroable)]
|
81 | /// # #[repr (transparent)]
|
82 | /// # struct Generic<A, B> {
|
83 | /// # a: A,
|
84 | /// # b: PhantomData<B>,
|
85 | /// # }
|
86 | /// struct NotPod;
|
87 | ///
|
88 | /// let _: u32 = bytemuck::cast(Generic { a: 4u32, b: PhantomData::<NotPod> });
|
89 | /// ```
|
90 | #[proc_macro_derive (Pod, attributes(bytemuck))]
|
91 | pub fn derive_pod(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
92 | let expanded: TokenStream =
|
93 | derive_marker_trait::<Pod>(input:parse_macro_input!(input as DeriveInput));
|
94 |
|
95 | proc_macro::TokenStream::from(expanded)
|
96 | }
|
97 |
|
98 | /// Derive the `AnyBitPattern` trait for a struct
|
99 | ///
|
100 | /// The macro ensures that the struct follows all the the safety requirements
|
101 | /// for the `AnyBitPattern` trait.
|
102 | ///
|
103 | /// The following constraints need to be satisfied for the macro to succeed
|
104 | ///
|
105 | /// - All fields in the struct must to implement `AnyBitPattern`
|
106 | #[proc_macro_derive (AnyBitPattern, attributes(bytemuck))]
|
107 | pub fn derive_anybitpattern(
|
108 | input: proc_macro::TokenStream,
|
109 | ) -> proc_macro::TokenStream {
|
110 | let expanded: TokenStream = derive_marker_trait::<AnyBitPattern>(input:parse_macro_input!(
|
111 | input as DeriveInput
|
112 | ));
|
113 |
|
114 | proc_macro::TokenStream::from(expanded)
|
115 | }
|
116 |
|
117 | /// Derive the `Zeroable` trait for a type.
|
118 | ///
|
119 | /// The macro ensures that the type follows all the the safety requirements
|
120 | /// for the `Zeroable` trait.
|
121 | ///
|
122 | /// The following constraints need to be satisfied for the macro to succeed on a
|
123 | /// struct:
|
124 | ///
|
125 | /// - All fields in the struct must implement `Zeroable`
|
126 | ///
|
127 | /// The following constraints need to be satisfied for the macro to succeed on
|
128 | /// an enum:
|
129 | ///
|
130 | /// - The enum has an explicit `#[repr(Int)]`, `#[repr(C)]`, or `#[repr(C,
|
131 | /// Int)]`.
|
132 | /// - The enum has a variant with discriminant 0 (explicitly or implicitly).
|
133 | /// - All fields in the variant with discriminant 0 (if any) must implement
|
134 | /// `Zeroable`
|
135 | ///
|
136 | /// The macro always succeeds on unions.
|
137 | ///
|
138 | /// ## Example
|
139 | ///
|
140 | /// ```rust
|
141 | /// # use bytemuck_derive::{Zeroable};
|
142 | /// #[derive(Copy, Clone, Zeroable)]
|
143 | /// #[repr(C)]
|
144 | /// struct Test {
|
145 | /// a: u16,
|
146 | /// b: u16,
|
147 | /// }
|
148 | /// ```
|
149 | /// ```rust
|
150 | /// # use bytemuck_derive::{Zeroable};
|
151 | /// #[derive(Copy, Clone, Zeroable)]
|
152 | /// #[repr(i32)]
|
153 | /// enum Values {
|
154 | /// A = 0,
|
155 | /// B = 1,
|
156 | /// C = 2,
|
157 | /// }
|
158 | /// #[derive(Clone, Zeroable)]
|
159 | /// #[repr(C)]
|
160 | /// enum Implicit {
|
161 | /// A(bool, u8, char),
|
162 | /// B(String),
|
163 | /// C(std::num::NonZeroU8),
|
164 | /// }
|
165 | /// ```
|
166 | ///
|
167 | /// # Custom bounds
|
168 | ///
|
169 | /// Custom bounds for the derived `Zeroable` impl can be given using the
|
170 | /// `#[zeroable(bound = "")]` helper attribute.
|
171 | ///
|
172 | /// Using this attribute additionally opts-in to "perfect derive" semantics,
|
173 | /// where instead of adding bounds for each generic type parameter, bounds are
|
174 | /// added for each field's type.
|
175 | ///
|
176 | /// ## Examples
|
177 | ///
|
178 | /// ```rust
|
179 | /// # use bytemuck::Zeroable;
|
180 | /// # use std::marker::PhantomData;
|
181 | /// #[derive(Clone, Zeroable)]
|
182 | /// #[zeroable(bound = "" )]
|
183 | /// struct AlwaysZeroable<T> {
|
184 | /// a: PhantomData<T>,
|
185 | /// }
|
186 | ///
|
187 | /// AlwaysZeroable::<std::num::NonZeroU8>::zeroed();
|
188 | /// ```
|
189 | /// ```rust
|
190 | /// # use bytemuck::{Zeroable};
|
191 | /// #[derive(Copy, Clone, Zeroable)]
|
192 | /// #[repr(u8)]
|
193 | /// #[zeroable(bound = "" )]
|
194 | /// enum MyOption<T> {
|
195 | /// None,
|
196 | /// Some(T),
|
197 | /// }
|
198 | ///
|
199 | /// assert!(matches!(MyOption::<std::num::NonZeroU8>::zeroed(), MyOption::None));
|
200 | /// ```
|
201 | ///
|
202 | /// ```rust,compile_fail
|
203 | /// # use bytemuck::Zeroable;
|
204 | /// # use std::marker::PhantomData;
|
205 | /// #[derive(Clone, Zeroable)]
|
206 | /// #[zeroable(bound = "T: Copy" )]
|
207 | /// struct ZeroableWhenTIsCopy<T> {
|
208 | /// a: PhantomData<T>,
|
209 | /// }
|
210 | ///
|
211 | /// ZeroableWhenTIsCopy::<String>::zeroed();
|
212 | /// ```
|
213 | ///
|
214 | /// The restriction that all fields must be Zeroable is still applied, and this
|
215 | /// is enforced using the mentioned "perfect derive" semantics.
|
216 | ///
|
217 | /// ```rust
|
218 | /// # use bytemuck::Zeroable;
|
219 | /// #[derive(Clone, Zeroable)]
|
220 | /// #[zeroable(bound = "" )]
|
221 | /// struct ZeroableWhenTIsZeroable<T> {
|
222 | /// a: T,
|
223 | /// }
|
224 | /// ZeroableWhenTIsZeroable::<u32>::zeroed();
|
225 | /// ```
|
226 | ///
|
227 | /// ```rust,compile_fail
|
228 | /// # use bytemuck::Zeroable;
|
229 | /// # #[derive(Clone, Zeroable)]
|
230 | /// # #[zeroable(bound = "" )]
|
231 | /// # struct ZeroableWhenTIsZeroable<T> {
|
232 | /// # a: T,
|
233 | /// # }
|
234 | /// ZeroableWhenTIsZeroable::<String>::zeroed();
|
235 | /// ```
|
236 | #[proc_macro_derive (Zeroable, attributes(bytemuck, zeroable))]
|
237 | pub fn derive_zeroable(
|
238 | input: proc_macro::TokenStream,
|
239 | ) -> proc_macro::TokenStream {
|
240 | let expanded: TokenStream =
|
241 | derive_marker_trait::<Zeroable>(input:parse_macro_input!(input as DeriveInput));
|
242 |
|
243 | proc_macro::TokenStream::from(expanded)
|
244 | }
|
245 |
|
246 | /// Derive the `NoUninit` trait for a struct or enum
|
247 | ///
|
248 | /// The macro ensures that the type follows all the the safety requirements
|
249 | /// for the `NoUninit` trait.
|
250 | ///
|
251 | /// The following constraints need to be satisfied for the macro to succeed
|
252 | /// (the rest of the constraints are guaranteed by the `NoUninit` subtrait
|
253 | /// bounds, i.e. the type must be `Sized + Copy + 'static`):
|
254 | ///
|
255 | /// If applied to a struct:
|
256 | /// - All fields in the struct must implement `NoUninit`
|
257 | /// - The struct must be `#[repr(C)]` or `#[repr(transparent)]`
|
258 | /// - The struct must not contain any padding bytes
|
259 | /// - The struct must contain no generic parameters
|
260 | ///
|
261 | /// If applied to an enum:
|
262 | /// - The enum must be explicit `#[repr(Int)]`, `#[repr(C)]`, or both
|
263 | /// - All variants must be fieldless
|
264 | /// - The enum must contain no generic parameters
|
265 | #[proc_macro_derive (NoUninit, attributes(bytemuck))]
|
266 | pub fn derive_no_uninit(
|
267 | input: proc_macro::TokenStream,
|
268 | ) -> proc_macro::TokenStream {
|
269 | let expanded: TokenStream =
|
270 | derive_marker_trait::<NoUninit>(input:parse_macro_input!(input as DeriveInput));
|
271 |
|
272 | proc_macro::TokenStream::from(expanded)
|
273 | }
|
274 |
|
275 | /// Derive the `CheckedBitPattern` trait for a struct or enum.
|
276 | ///
|
277 | /// The macro ensures that the type follows all the the safety requirements
|
278 | /// for the `CheckedBitPattern` trait and derives the required `Bits` type
|
279 | /// definition and `is_valid_bit_pattern` method for the type automatically.
|
280 | ///
|
281 | /// The following constraints need to be satisfied for the macro to succeed:
|
282 | ///
|
283 | /// If applied to a struct:
|
284 | /// - All fields must implement `CheckedBitPattern`
|
285 | /// - The struct must be `#[repr(C)]` or `#[repr(transparent)]`
|
286 | /// - The struct must contain no generic parameters
|
287 | ///
|
288 | /// If applied to an enum:
|
289 | /// - The enum must be explicit `#[repr(Int)]`
|
290 | /// - All fields in variants must implement `CheckedBitPattern`
|
291 | /// - The enum must contain no generic parameters
|
292 | #[proc_macro_derive (CheckedBitPattern)]
|
293 | pub fn derive_maybe_pod(
|
294 | input: proc_macro::TokenStream,
|
295 | ) -> proc_macro::TokenStream {
|
296 | let expanded: TokenStream = derive_marker_trait::<CheckedBitPattern>(input:parse_macro_input!(
|
297 | input as DeriveInput
|
298 | ));
|
299 |
|
300 | proc_macro::TokenStream::from(expanded)
|
301 | }
|
302 |
|
303 | /// Derive the `TransparentWrapper` trait for a struct
|
304 | ///
|
305 | /// The macro ensures that the struct follows all the the safety requirements
|
306 | /// for the `TransparentWrapper` trait.
|
307 | ///
|
308 | /// The following constraints need to be satisfied for the macro to succeed
|
309 | ///
|
310 | /// - The struct must be `#[repr(transparent)]`
|
311 | /// - The struct must contain the `Wrapped` type
|
312 | /// - Any ZST fields must be [`Zeroable`][derive@Zeroable].
|
313 | ///
|
314 | /// If the struct only contains a single field, the `Wrapped` type will
|
315 | /// automatically be determined. If there is more then one field in the struct,
|
316 | /// you need to specify the `Wrapped` type using `#[transparent(T)]`
|
317 | ///
|
318 | /// ## Examples
|
319 | ///
|
320 | /// ```rust
|
321 | /// # use bytemuck_derive::TransparentWrapper;
|
322 | /// # use std::marker::PhantomData;
|
323 | /// #[derive(Copy, Clone, TransparentWrapper)]
|
324 | /// #[repr(transparent)]
|
325 | /// #[transparent(u16)]
|
326 | /// struct Test<T> {
|
327 | /// inner: u16,
|
328 | /// extra: PhantomData<T>,
|
329 | /// }
|
330 | /// ```
|
331 | ///
|
332 | /// If the struct contains more than one field, the `Wrapped` type must be
|
333 | /// explicitly specified.
|
334 | ///
|
335 | /// ```rust,compile_fail
|
336 | /// # use bytemuck_derive::TransparentWrapper;
|
337 | /// # use std::marker::PhantomData;
|
338 | /// #[derive(Copy, Clone, TransparentWrapper)]
|
339 | /// #[repr(transparent)]
|
340 | /// // missing `#[transparent(u16)]`
|
341 | /// struct Test<T> {
|
342 | /// inner: u16,
|
343 | /// extra: PhantomData<T>,
|
344 | /// }
|
345 | /// ```
|
346 | ///
|
347 | /// Any ZST fields must be `Zeroable`.
|
348 | ///
|
349 | /// ```rust,compile_fail
|
350 | /// # use bytemuck_derive::TransparentWrapper;
|
351 | /// # use std::marker::PhantomData;
|
352 | /// struct NonTransparentSafeZST;
|
353 | ///
|
354 | /// #[derive(TransparentWrapper)]
|
355 | /// #[repr(transparent)]
|
356 | /// #[transparent(u16)]
|
357 | /// struct Test<T> {
|
358 | /// inner: u16,
|
359 | /// extra: PhantomData<T>,
|
360 | /// another_extra: NonTransparentSafeZST, // not `Zeroable`
|
361 | /// }
|
362 | /// ```
|
363 | #[proc_macro_derive (TransparentWrapper, attributes(bytemuck, transparent))]
|
364 | pub fn derive_transparent(
|
365 | input: proc_macro::TokenStream,
|
366 | ) -> proc_macro::TokenStream {
|
367 | let expanded: TokenStream = derive_marker_trait::<TransparentWrapper>(input:parse_macro_input!(
|
368 | input as DeriveInput
|
369 | ));
|
370 |
|
371 | proc_macro::TokenStream::from(expanded)
|
372 | }
|
373 |
|
374 | /// Derive the `Contiguous` trait for an enum
|
375 | ///
|
376 | /// The macro ensures that the enum follows all the the safety requirements
|
377 | /// for the `Contiguous` trait.
|
378 | ///
|
379 | /// The following constraints need to be satisfied for the macro to succeed
|
380 | ///
|
381 | /// - The enum must be `#[repr(Int)]`
|
382 | /// - The enum must be fieldless
|
383 | /// - The enum discriminants must form a contiguous range
|
384 | ///
|
385 | /// ## Example
|
386 | ///
|
387 | /// ```rust
|
388 | /// # use bytemuck_derive::{Contiguous};
|
389 | ///
|
390 | /// #[derive(Copy, Clone, Contiguous)]
|
391 | /// #[repr(u8)]
|
392 | /// enum Test {
|
393 | /// A = 0,
|
394 | /// B = 1,
|
395 | /// C = 2,
|
396 | /// }
|
397 | /// ```
|
398 | #[proc_macro_derive (Contiguous)]
|
399 | pub fn derive_contiguous(
|
400 | input: proc_macro::TokenStream,
|
401 | ) -> proc_macro::TokenStream {
|
402 | let expanded: TokenStream =
|
403 | derive_marker_trait::<Contiguous>(input:parse_macro_input!(input as DeriveInput));
|
404 |
|
405 | proc_macro::TokenStream::from(expanded)
|
406 | }
|
407 |
|
408 | /// Derive the `PartialEq` and `Eq` trait for a type
|
409 | ///
|
410 | /// The macro implements `PartialEq` and `Eq` by casting both sides of the
|
411 | /// comparison to a byte slice and then compares those.
|
412 | ///
|
413 | /// ## Warning
|
414 | ///
|
415 | /// Since this implements a byte wise comparison, the behavior of floating point
|
416 | /// numbers does not match their usual comparison behavior. Additionally other
|
417 | /// custom comparison behaviors of the individual fields are also ignored. This
|
418 | /// also does not implement `StructuralPartialEq` / `StructuralEq` like
|
419 | /// `PartialEq` / `Eq` would. This means you can't pattern match on the values.
|
420 | ///
|
421 | /// ## Examples
|
422 | ///
|
423 | /// ```rust
|
424 | /// # use bytemuck_derive::{ByteEq, NoUninit};
|
425 | /// #[derive(Copy, Clone, NoUninit, ByteEq)]
|
426 | /// #[repr(C)]
|
427 | /// struct Test {
|
428 | /// a: u32,
|
429 | /// b: char,
|
430 | /// c: f32,
|
431 | /// }
|
432 | /// ```
|
433 | ///
|
434 | /// ```rust
|
435 | /// # use bytemuck_derive::ByteEq;
|
436 | /// # use bytemuck::NoUninit;
|
437 | /// #[derive(Copy, Clone, ByteEq)]
|
438 | /// #[repr(C)]
|
439 | /// struct Test<const N: usize> {
|
440 | /// a: [u32; N],
|
441 | /// }
|
442 | /// unsafe impl<const N: usize> NoUninit for Test<N> {}
|
443 | /// ```
|
444 | #[proc_macro_derive (ByteEq)]
|
445 | pub fn derive_byte_eq(
|
446 | input: proc_macro::TokenStream,
|
447 | ) -> proc_macro::TokenStream {
|
448 | let input: DeriveInput = parse_macro_input!(input as DeriveInput);
|
449 | let crate_name: TokenStream = bytemuck_crate_name(&input);
|
450 | let ident: Ident = input.ident;
|
451 | let (impl_generics: ImplGenerics<'_>, ty_generics: TypeGenerics<'_>, where_clause: Option<&WhereClause>) =
|
452 | input.generics.split_for_impl();
|
453 |
|
454 | proc_macro::TokenStream::from(quote! {
|
455 | impl #impl_generics ::core::cmp::PartialEq for #ident #ty_generics #where_clause {
|
456 | #[inline]
|
457 | #[must_use]
|
458 | fn eq(&self, other: &Self) -> bool {
|
459 | #crate_name::bytes_of(self) == #crate_name::bytes_of(other)
|
460 | }
|
461 | }
|
462 | impl #impl_generics ::core::cmp::Eq for #ident #ty_generics #where_clause { }
|
463 | })
|
464 | }
|
465 |
|
466 | /// Derive the `Hash` trait for a type
|
467 | ///
|
468 | /// The macro implements `Hash` by casting the value to a byte slice and hashing
|
469 | /// that.
|
470 | ///
|
471 | /// ## Warning
|
472 | ///
|
473 | /// The hash does not match the standard library's `Hash` derive.
|
474 | ///
|
475 | /// ## Examples
|
476 | ///
|
477 | /// ```rust
|
478 | /// # use bytemuck_derive::{ByteHash, NoUninit};
|
479 | /// #[derive(Copy, Clone, NoUninit, ByteHash)]
|
480 | /// #[repr(C)]
|
481 | /// struct Test {
|
482 | /// a: u32,
|
483 | /// b: char,
|
484 | /// c: f32,
|
485 | /// }
|
486 | /// ```
|
487 | ///
|
488 | /// ```rust
|
489 | /// # use bytemuck_derive::ByteHash;
|
490 | /// # use bytemuck::NoUninit;
|
491 | /// #[derive(Copy, Clone, ByteHash)]
|
492 | /// #[repr(C)]
|
493 | /// struct Test<const N: usize> {
|
494 | /// a: [u32; N],
|
495 | /// }
|
496 | /// unsafe impl<const N: usize> NoUninit for Test<N> {}
|
497 | /// ```
|
498 | #[proc_macro_derive (ByteHash)]
|
499 | pub fn derive_byte_hash(
|
500 | input: proc_macro::TokenStream,
|
501 | ) -> proc_macro::TokenStream {
|
502 | let input: DeriveInput = parse_macro_input!(input as DeriveInput);
|
503 | let crate_name: TokenStream = bytemuck_crate_name(&input);
|
504 | let ident: Ident = input.ident;
|
505 | let (impl_generics: ImplGenerics<'_>, ty_generics: TypeGenerics<'_>, where_clause: Option<&WhereClause>) =
|
506 | input.generics.split_for_impl();
|
507 |
|
508 | proc_macro::TokenStream::from(quote! {
|
509 | impl #impl_generics ::core::hash::Hash for #ident #ty_generics #where_clause {
|
510 | #[inline]
|
511 | fn hash<H: ::core::hash::Hasher>(&self, state: &mut H) {
|
512 | ::core::hash::Hash::hash_slice(#crate_name::bytes_of(self), state)
|
513 | }
|
514 |
|
515 | #[inline]
|
516 | fn hash_slice<H: ::core::hash::Hasher>(data: &[Self], state: &mut H) {
|
517 | ::core::hash::Hash::hash_slice(#crate_name::cast_slice::<_, u8>(data), state)
|
518 | }
|
519 | }
|
520 | })
|
521 | }
|
522 |
|
523 | /// Basic wrapper for error handling
|
524 | fn derive_marker_trait<Trait: Derivable>(input: DeriveInput) -> TokenStream {
|
525 | derive_marker_trait_inner::<Trait>(input)
|
526 | .unwrap_or_else(|err: Error| err.into_compile_error())
|
527 | }
|
528 |
|
529 | /// Find `#[name(key = "value")]` helper attributes on the struct, and return
|
530 | /// their `"value"`s parsed with `parser`.
|
531 | ///
|
532 | /// Returns an error if any attributes with the given `name` do not match the
|
533 | /// expected format. Returns `Ok([])` if no attributes with `name` are found.
|
534 | fn find_and_parse_helper_attributes<P: syn::parse::Parser + Copy>(
|
535 | attributes: &[syn::Attribute], name: &str, key: &str, parser: P,
|
536 | example_value: &str, invalid_value_msg: &str,
|
537 | ) -> Result<Vec<P::Output>> {
|
538 | let invalid_format_msg =
|
539 | format!(" {name} attribute must be ` {name}( {key} = \"{example_value}\")`" ,);
|
540 | let values_to_check = attributes.iter().filter_map(|attr| match &attr.meta {
|
541 | // If a `Path` matches our `name`, return an error, else ignore it.
|
542 | // e.g. `#[zeroable]`
|
543 | syn::Meta::Path(path) => path
|
544 | .is_ident(name)
|
545 | .then(|| Err(syn::Error::new_spanned(path, &invalid_format_msg))),
|
546 | // If a `NameValue` matches our `name`, return an error, else ignore it.
|
547 | // e.g. `#[zeroable = "hello"]`
|
548 | syn::Meta::NameValue(namevalue) => {
|
549 | namevalue.path.is_ident(name).then(|| {
|
550 | Err(syn::Error::new_spanned(&namevalue.path, &invalid_format_msg))
|
551 | })
|
552 | }
|
553 | // If a `List` matches our `name`, match its contents to our format, else
|
554 | // ignore it. If its contents match our format, return the value, else
|
555 | // return an error.
|
556 | syn::Meta::List(list) => list.path.is_ident(name).then(|| {
|
557 | let namevalue: syn::MetaNameValue = syn::parse2(list.tokens.clone())
|
558 | .map_err(|_| {
|
559 | syn::Error::new_spanned(&list.tokens, &invalid_format_msg)
|
560 | })?;
|
561 | if namevalue.path.is_ident(key) {
|
562 | match namevalue.value {
|
563 | syn::Expr::Lit(syn::ExprLit {
|
564 | lit: syn::Lit::Str(strlit), ..
|
565 | }) => Ok(strlit),
|
566 | _ => {
|
567 | Err(syn::Error::new_spanned(&namevalue.path, &invalid_format_msg))
|
568 | }
|
569 | }
|
570 | } else {
|
571 | Err(syn::Error::new_spanned(&namevalue.path, &invalid_format_msg))
|
572 | }
|
573 | }),
|
574 | });
|
575 | // Parse each value found with the given parser, and return them if no errors
|
576 | // occur.
|
577 | values_to_check
|
578 | .map(|lit| {
|
579 | let lit = lit?;
|
580 | lit.parse_with(parser).map_err(|err| {
|
581 | syn::Error::new_spanned(&lit, format!(" {invalid_value_msg}: {err}" ))
|
582 | })
|
583 | })
|
584 | .collect()
|
585 | }
|
586 |
|
587 | fn derive_marker_trait_inner<Trait: Derivable>(
|
588 | mut input: DeriveInput,
|
589 | ) -> Result<TokenStream> {
|
590 | let crate_name = bytemuck_crate_name(&input);
|
591 | let trait_ = Trait::ident(&input, &crate_name)?;
|
592 | // If this trait allows explicit bounds, and any explicit bounds were given,
|
593 | // then use those explicit bounds. Else, apply the default bounds (bound
|
594 | // each generic type on this trait).
|
595 | if let Some(name) = Trait::explicit_bounds_attribute_name() {
|
596 | // See if any explicit bounds were given in attributes.
|
597 | let explicit_bounds = find_and_parse_helper_attributes(
|
598 | &input.attrs,
|
599 | name,
|
600 | "bound" ,
|
601 | <syn::punctuated::Punctuated<syn::WherePredicate, syn::Token![,]>>::parse_terminated,
|
602 | "Type: Trait" ,
|
603 | "invalid where predicate" ,
|
604 | )?;
|
605 |
|
606 | if !explicit_bounds.is_empty() {
|
607 | // Explicit bounds were given.
|
608 | // Enforce explicitly given bounds, and emit "perfect derive" (i.e. add
|
609 | // bounds for each field's type).
|
610 | let explicit_bounds = explicit_bounds
|
611 | .into_iter()
|
612 | .flatten()
|
613 | .collect::<Vec<syn::WherePredicate>>();
|
614 |
|
615 | let fields = match (Trait::perfect_derive_fields(&input), &input.data) {
|
616 | (Some(fields), _) => fields,
|
617 | (None, syn::Data::Struct(syn::DataStruct { fields, .. })) => {
|
618 | fields.clone()
|
619 | }
|
620 | (None, syn::Data::Union(_)) => {
|
621 | return Err(syn::Error::new_spanned(
|
622 | trait_,
|
623 | &"perfect derive is not supported for unions" ,
|
624 | ));
|
625 | }
|
626 | (None, syn::Data::Enum(_)) => {
|
627 | return Err(syn::Error::new_spanned(
|
628 | trait_,
|
629 | &"perfect derive is not supported for enums" ,
|
630 | ));
|
631 | }
|
632 | };
|
633 |
|
634 | let predicates = &mut input.generics.make_where_clause().predicates;
|
635 |
|
636 | predicates.extend(explicit_bounds);
|
637 |
|
638 | for field in fields {
|
639 | let ty = field.ty;
|
640 | predicates.push(syn::parse_quote!(
|
641 | #ty: #trait_
|
642 | ));
|
643 | }
|
644 | } else {
|
645 | // No explicit bounds were given.
|
646 | // Enforce trait bound on all type generics.
|
647 | add_trait_marker(&mut input.generics, &trait_);
|
648 | }
|
649 | } else {
|
650 | // This trait does not allow explicit bounds.
|
651 | // Enforce trait bound on all type generics.
|
652 | add_trait_marker(&mut input.generics, &trait_);
|
653 | }
|
654 |
|
655 | let name = &input.ident;
|
656 |
|
657 | let (impl_generics, ty_generics, where_clause) =
|
658 | input.generics.split_for_impl();
|
659 |
|
660 | Trait::check_attributes(&input.data, &input.attrs)?;
|
661 | let asserts = Trait::asserts(&input, &crate_name)?;
|
662 | let (trait_impl_extras, trait_impl) = Trait::trait_impl(&input, &crate_name)?;
|
663 |
|
664 | let implies_trait = if let Some(implies_trait) =
|
665 | Trait::implies_trait(&crate_name)
|
666 | {
|
667 | quote!(unsafe impl #impl_generics #implies_trait for #name #ty_generics #where_clause {})
|
668 | } else {
|
669 | quote!()
|
670 | };
|
671 |
|
672 | let where_clause =
|
673 | if Trait::requires_where_clause() { where_clause } else { None };
|
674 |
|
675 | Ok(quote! {
|
676 | #asserts
|
677 |
|
678 | #trait_impl_extras
|
679 |
|
680 | unsafe impl #impl_generics #trait_ for #name #ty_generics #where_clause {
|
681 | #trait_impl
|
682 | }
|
683 |
|
684 | #implies_trait
|
685 | })
|
686 | }
|
687 |
|
688 | /// Add a trait marker to the generics if it is not already present
|
689 | fn add_trait_marker(generics: &mut syn::Generics, trait_name: &syn::Path) {
|
690 | // Get each generic type parameter.
|
691 | let type_params: Vec = genericsimpl Iterator
|
692 | .type_params()
|
693 | .map(|param: &TypeParam| ¶m.ident)
|
694 | .map(|param: &Ident| {
|
695 | syn::parse_quote!(
|
696 | #param: #trait_name
|
697 | )
|
698 | })
|
699 | .collect::<Vec<syn::WherePredicate>>();
|
700 |
|
701 | generics.make_where_clause().predicates.extend(iter:type_params);
|
702 | }
|
703 | |