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