bindgen/ir/
layout.rs

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