diff options
Diffstat (limited to 'third_party/rust/bindgen/ir/layout.rs')
-rw-r--r-- | third_party/rust/bindgen/ir/layout.rs | 143 |
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 + } + } +} |