1 // SPDX-License-Identifier: (BSD-2-Clause OR Apache-2.0) OR MIT 2 3 use proc_macro2::{Span, TokenStream}; 4 use syn::{Data, DataEnum, DataStruct, DataUnion, Error}; 5 6 use crate::{ 7 repr::{EnumRepr, StructUnionRepr}, 8 util::{Ctx, FieldBounds, ImplBlockBuilder, Trait}, 9 }; 10 11 pub(crate) fn derive_unaligned(ctx: &Ctx, _top_level: Trait) -> Result<TokenStream, Error> { 12 match &ctx.ast.data { 13 Data::Struct(strct) => derive_unaligned_struct(ctx, strct), 14 Data::Enum(enm) => derive_unaligned_enum(ctx, enm), 15 Data::Union(unn) => derive_unaligned_union(ctx, unn), 16 } 17 } 18 19 /// A struct is `Unaligned` if: 20 /// - `repr(align)` is no more than 1 and either 21 /// - `repr(C)` or `repr(transparent)` and 22 /// - all fields `Unaligned` 23 /// - `repr(packed)` 24 fn derive_unaligned_struct(ctx: &Ctx, strct: &DataStruct) -> Result<TokenStream, Error> { 25 let repr = StructUnionRepr::from_attrs(&ctx.ast.attrs)?; 26 repr.unaligned_validate_no_align_gt_1()?; 27 28 let field_bounds = if repr.is_packed_1() { 29 FieldBounds::None 30 } else if repr.is_c() || repr.is_transparent() { 31 FieldBounds::ALL_SELF 32 } else { 33 return ctx.error_or_skip(Error::new( 34 Span::call_site(), 35 "must have #[repr(C)], #[repr(transparent)], or #[repr(packed)] attribute in order to guarantee this type's alignment", 36 )); 37 }; 38 39 Ok(ImplBlockBuilder::new(ctx, strct, Trait::Unaligned, field_bounds).build()) 40 } 41 42 /// An enum is `Unaligned` if: 43 /// - No `repr(align(N > 1))` 44 /// - `repr(u8)` or `repr(i8)` 45 fn derive_unaligned_enum(ctx: &Ctx, enm: &DataEnum) -> Result<TokenStream, Error> { 46 let repr = EnumRepr::from_attrs(&ctx.ast.attrs)?; 47 repr.unaligned_validate_no_align_gt_1()?; 48 49 if !repr.is_u8() && !repr.is_i8() { 50 return ctx.error_or_skip(Error::new( 51 Span::call_site(), 52 "must have #[repr(u8)] or #[repr(i8)] attribute in order to guarantee this type's alignment", 53 )); 54 } 55 56 Ok(ImplBlockBuilder::new(ctx, enm, Trait::Unaligned, FieldBounds::ALL_SELF).build()) 57 } 58 59 /// Like structs, a union is `Unaligned` if: 60 /// - `repr(align)` is no more than 1 and either 61 /// - `repr(C)` or `repr(transparent)` and 62 /// - all fields `Unaligned` 63 /// - `repr(packed)` 64 fn derive_unaligned_union(ctx: &Ctx, unn: &DataUnion) -> Result<TokenStream, Error> { 65 let repr = StructUnionRepr::from_attrs(&ctx.ast.attrs)?; 66 repr.unaligned_validate_no_align_gt_1()?; 67 68 let field_type_trait_bounds = if repr.is_packed_1() { 69 FieldBounds::None 70 } else if repr.is_c() || repr.is_transparent() { 71 FieldBounds::ALL_SELF 72 } else { 73 return ctx.error_or_skip(Error::new( 74 Span::call_site(), 75 "must have #[repr(C)], #[repr(transparent)], or #[repr(packed)] attribute in order to guarantee this type's alignment", 76 )); 77 }; 78 79 Ok(ImplBlockBuilder::new(ctx, unn, Trait::Unaligned, field_type_trait_bounds).build()) 80 } 81