summaryrefslogtreecommitdiffstats
path: root/third_party/rust/bindgen/ir/layout.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/bindgen/ir/layout.rs')
-rw-r--r--third_party/rust/bindgen/ir/layout.rs143
1 files changed, 143 insertions, 0 deletions
diff --git a/third_party/rust/bindgen/ir/layout.rs b/third_party/rust/bindgen/ir/layout.rs
new file mode 100644
index 0000000000..6f4503070a
--- /dev/null
+++ b/third_party/rust/bindgen/ir/layout.rs
@@ -0,0 +1,143 @@
+//! Intermediate representation for the physical layout of some type.
+
+use super::derive::CanDerive;
+use super::ty::{Type, TypeKind, RUST_DERIVE_IN_ARRAY_LIMIT};
+use crate::clang;
+use crate::ir::context::BindgenContext;
+use std::cmp;
+
+/// A type that represents the struct layout of a type.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct Layout {
+ /// The size (in bytes) of this layout.
+ pub size: usize,
+ /// The alignment (in bytes) of this layout.
+ pub align: usize,
+ /// Whether this layout's members are packed or not.
+ pub packed: bool,
+}
+
+#[test]
+fn test_layout_for_size() {
+ use std::mem;
+
+ let ptr_size = mem::size_of::<*mut ()>();
+ assert_eq!(
+ Layout::for_size_internal(ptr_size, ptr_size),
+ Layout::new(ptr_size, ptr_size)
+ );
+ assert_eq!(
+ Layout::for_size_internal(ptr_size, 3 * ptr_size),
+ Layout::new(3 * ptr_size, ptr_size)
+ );
+}
+
+impl Layout {
+ /// Gets the integer type name for a given known size.
+ pub fn known_type_for_size(
+ ctx: &BindgenContext,
+ size: usize,
+ ) -> Option<&'static str> {
+ Some(match size {
+ 16 if ctx.options().rust_features.i128_and_u128 => "u128",
+ 8 => "u64",
+ 4 => "u32",
+ 2 => "u16",
+ 1 => "u8",
+ _ => return None,
+ })
+ }
+
+ /// Construct a new `Layout` with the given `size` and `align`. It is not
+ /// packed.
+ pub fn new(size: usize, align: usize) -> Self {
+ Layout {
+ size,
+ align,
+ packed: false,
+ }
+ }
+
+ fn for_size_internal(ptr_size: usize, size: usize) -> Self {
+ let mut next_align = 2;
+ while size % next_align == 0 && next_align <= ptr_size {
+ next_align *= 2;
+ }
+ Layout {
+ size,
+ align: next_align / 2,
+ packed: false,
+ }
+ }
+
+ /// Creates a non-packed layout for a given size, trying to use the maximum
+ /// alignment possible.
+ pub fn for_size(ctx: &BindgenContext, size: usize) -> Self {
+ Self::for_size_internal(ctx.target_pointer_size(), size)
+ }
+
+ /// Is this a zero-sized layout?
+ pub fn is_zero(&self) -> bool {
+ self.size == 0 && self.align == 0
+ }
+
+ /// Construct a zero-sized layout.
+ pub fn zero() -> Self {
+ Self::new(0, 0)
+ }
+
+ /// Get this layout as an opaque type.
+ pub fn opaque(&self) -> Opaque {
+ Opaque(*self)
+ }
+}
+
+/// When we are treating a type as opaque, it is just a blob with a `Layout`.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct Opaque(pub Layout);
+
+impl Opaque {
+ /// Construct a new opaque type from the given clang type.
+ pub fn from_clang_ty(ty: &clang::Type, ctx: &BindgenContext) -> Type {
+ let layout = Layout::new(ty.size(ctx), ty.align(ctx));
+ let ty_kind = TypeKind::Opaque;
+ let is_const = ty.is_const();
+ Type::new(None, Some(layout), ty_kind, is_const)
+ }
+
+ /// Return the known rust type we should use to create a correctly-aligned
+ /// field with this layout.
+ pub fn known_rust_type_for_array(
+ &self,
+ ctx: &BindgenContext,
+ ) -> Option<&'static str> {
+ Layout::known_type_for_size(ctx, self.0.align)
+ }
+
+ /// Return the array size that an opaque type for this layout should have if
+ /// we know the correct type for it, or `None` otherwise.
+ pub fn array_size(&self, ctx: &BindgenContext) -> Option<usize> {
+ if self.known_rust_type_for_array(ctx).is_some() {
+ Some(self.0.size / cmp::max(self.0.align, 1))
+ } else {
+ None
+ }
+ }
+
+ /// Return `true` if this opaque layout's array size will fit within the
+ /// maximum number of array elements that Rust allows deriving traits
+ /// with. Return `false` otherwise.
+ pub fn array_size_within_derive_limit(
+ &self,
+ ctx: &BindgenContext,
+ ) -> CanDerive {
+ if self
+ .array_size(ctx)
+ .map_or(false, |size| size <= RUST_DERIVE_IN_ARRAY_LIMIT)
+ {
+ CanDerive::Yes
+ } else {
+ CanDerive::Manually
+ }
+ }
+}