1//! Intermediate representation for the physical layout of some type.
2
3use super::derive::CanDerive;
4use super::ty::{Type, TypeKind, RUST_DERIVE_IN_ARRAY_LIMIT};
5use crate::clang;
6use crate::ir::context::BindgenContext;
7use std::cmp;
8
9/// A type that represents the struct layout of a type.
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub(crate) struct Layout {
12 /// The size (in bytes) of this layout.
13 pub(crate) size: usize,
14 /// The alignment (in bytes) of this layout.
15 pub(crate) align: usize,
16 /// Whether this layout's members are packed or not.
17 pub(crate) packed: bool,
18}
19
20#[test]
21fn test_layout_for_size() {
22 use std::mem;
23
24 let ptr_size: usize = mem::size_of::<*mut ()>();
25 assert_eq!(
26 Layout::for_size_internal(ptr_size, ptr_size),
27 Layout::new(ptr_size, ptr_size)
28 );
29 assert_eq!(
30 Layout::for_size_internal(ptr_size, 3 * ptr_size),
31 Layout::new(3 * ptr_size, ptr_size)
32 );
33}
34
35impl Layout {
36 /// Gets the integer type name for a given known size.
37 pub(crate) fn known_type_for_size(
38 ctx: &BindgenContext,
39 size: usize,
40 ) -> Option<syn::Type> {
41 Some(match size {
42 16 if ctx.options().rust_features.i128_and_u128 => {
43 syn::parse_quote! { u128 }
44 }
45 8 => syn::parse_quote! { u64 },
46 4 => syn::parse_quote! { u32 },
47 2 => syn::parse_quote! { u16 },
48 1 => syn::parse_quote! { u8 },
49 _ => return None,
50 })
51 }
52
53 /// Construct a new `Layout` with the given `size` and `align`. It is not
54 /// packed.
55 pub(crate) fn new(size: usize, align: usize) -> Self {
56 Layout {
57 size,
58 align,
59 packed: false,
60 }
61 }
62
63 fn for_size_internal(ptr_size: usize, size: usize) -> Self {
64 let mut next_align = 2;
65 while size % next_align == 0 && next_align <= ptr_size {
66 next_align *= 2;
67 }
68 Layout {
69 size,
70 align: next_align / 2,
71 packed: false,
72 }
73 }
74
75 /// Creates a non-packed layout for a given size, trying to use the maximum
76 /// alignment possible.
77 pub(crate) fn for_size(ctx: &BindgenContext, size: usize) -> Self {
78 Self::for_size_internal(ctx.target_pointer_size(), size)
79 }
80
81 /// Get this layout as an opaque type.
82 pub(crate) fn opaque(&self) -> Opaque {
83 Opaque(*self)
84 }
85}
86
87/// When we are treating a type as opaque, it is just a blob with a `Layout`.
88#[derive(Clone, Debug, PartialEq, Eq)]
89pub(crate) struct Opaque(pub(crate) Layout);
90
91impl Opaque {
92 /// Construct a new opaque type from the given clang type.
93 pub(crate) fn from_clang_ty(
94 ty: &clang::Type,
95 ctx: &BindgenContext,
96 ) -> Type {
97 let layout = Layout::new(ty.size(ctx), ty.align(ctx));
98 let ty_kind = TypeKind::Opaque;
99 let is_const = ty.is_const();
100 Type::new(None, Some(layout), ty_kind, is_const)
101 }
102
103 /// Return the known rust type we should use to create a correctly-aligned
104 /// field with this layout.
105 pub(crate) fn known_rust_type_for_array(
106 &self,
107 ctx: &BindgenContext,
108 ) -> Option<syn::Type> {
109 Layout::known_type_for_size(ctx, self.0.align)
110 }
111
112 /// Return the array size that an opaque type for this layout should have if
113 /// we know the correct type for it, or `None` otherwise.
114 pub(crate) fn array_size(&self, ctx: &BindgenContext) -> Option<usize> {
115 if self.known_rust_type_for_array(ctx).is_some() {
116 Some(self.0.size / cmp::max(self.0.align, 1))
117 } else {
118 None
119 }
120 }
121
122 /// Return `true` if this opaque layout's array size will fit within the
123 /// maximum number of array elements that Rust allows deriving traits
124 /// with. Return `false` otherwise.
125 pub(crate) fn array_size_within_derive_limit(
126 &self,
127 ctx: &BindgenContext,
128 ) -> CanDerive {
129 if self
130 .array_size(ctx)
131 .map_or(false, |size| size <= RUST_DERIVE_IN_ARRAY_LIMIT)
132 {
133 CanDerive::Yes
134 } else {
135 CanDerive::Manually
136 }
137 }
138}
139