#![allow(unused)]
use core::fmt;
use core::{ffi::c_void, mem::MaybeUninit};
use std::os::raw::{c_char, c_int, c_ulong};
use alloc::format;
use crate::ffi::Class;
#[repr(transparent)]
#[derive(Clone, Copy, PartialEq, Eq)]
pub(crate) struct BlockFlags(pub(crate) c_int);
impl BlockFlags {
pub(crate) const EMPTY: Self = Self(0);
const BLOCK_DEALLOCATING: Self = Self(0x0001);
const BLOCK_REFCOUNT_MASK: Self = Self(if cfg!(feature = "gnustep-1-7") {
0x00ffffff
} else if cfg!(any(feature = "compiler-rt", feature = "unstable-objfw")) {
0xffff
} else if cfg!(target_vendor = "apple") {
0xfffe } else {
0
});
const BLOCK_INLINE_LAYOUT_STRING: Self = Self(1 << 21);
const BLOCK_SMALL_DESCRIPTOR: Self = Self(1 << 22);
pub(crate) const BLOCK_IS_NOESCAPE: Self = Self(1 << 23);
const BLOCK_NEEDS_FREE: Self = Self(1 << 24);
pub(crate) const BLOCK_HAS_COPY_DISPOSE: Self = Self(1 << 25);
#[doc(alias = "BLOCK_HAS_CXX_OBJ")]
pub(crate) const BLOCK_HAS_CTOR: Self = Self(1 << 26);
const BLOCK_IS_GC: Self = Self(1 << 27);
pub(crate) const BLOCK_IS_GLOBAL: Self = Self(1 << 28);
#[doc(alias = "BLOCK_USE_SRET")]
#[doc(alias = "BLOCK_HAS_DESCRIPTOR")]
pub(crate) const BLOCK_USE_STRET: Self = Self(1 << 29);
pub(crate) const BLOCK_HAS_SIGNATURE: Self = Self(1 << 30);
const BLOCK_HAS_EXTENDED_LAYOUT: Self = Self(1 << 31);
}
impl fmt::Debug for BlockFlags {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut f = f.debug_struct("BlockFlags");
f.field("value", &format!("{:032b}", self.0));
macro_rules! test_flags {
{$(
$(#[$m:meta])?
$name:ident: $flag:ident
);* $(;)?} => ($(
$(#[$m])?
f.field(stringify!($name), &(self.0 & Self::$flag.0 != 0));
)*)
}
test_flags! {
#[cfg(target_vendor = "apple")]
deallocating: BLOCK_DEALLOCATING;
#[cfg(target_vendor = "apple")]
inline_layout_string: BLOCK_INLINE_LAYOUT_STRING;
#[cfg(target_vendor = "apple")]
small_descriptor: BLOCK_SMALL_DESCRIPTOR;
#[cfg(target_vendor = "apple")]
is_noescape: BLOCK_IS_NOESCAPE;
#[cfg(target_vendor = "apple")]
needs_free: BLOCK_NEEDS_FREE;
has_copy_dispose: BLOCK_HAS_COPY_DISPOSE;
has_ctor: BLOCK_HAS_CTOR;
#[cfg(target_vendor = "apple")]
is_gc: BLOCK_IS_GC;
is_global: BLOCK_IS_GLOBAL;
use_stret: BLOCK_USE_STRET;
has_signature: BLOCK_HAS_SIGNATURE;
#[cfg(target_vendor = "apple")]
has_extended_layout: BLOCK_HAS_EXTENDED_LAYOUT;
}
f.field(
"over_referenced",
&(self.0 & Self::BLOCK_REFCOUNT_MASK.0 == Self::BLOCK_REFCOUNT_MASK.0),
);
f.field(
"reference_count",
&((self.0 & Self::BLOCK_REFCOUNT_MASK.0) >> 1),
);
f.finish_non_exhaustive()
}
}
pub(crate) const BLOCK_FIELD_IS_OBJECT: c_int = 3;
pub(crate) const BLOCK_FIELD_IS_BLOCK: c_int = 7;
pub(crate) const BLOCK_FIELD_IS_BYREF: c_int = 8;
pub(crate) const BLOCK_FIELD_IS_WEAK: c_int = 16;
pub(crate) const BLOCK_BYREF_CALLER: c_int = 128;
#[repr(C)]
#[doc(alias = "__block_literal")]
#[doc(alias = "Block_layout")]
#[doc(alias = "Block_basic")]
#[allow(missing_debug_implementations)]
#[derive(Clone, Copy)]
pub struct BlockHeader {
pub isa: *const Class,
#[doc(alias = "Block_flags")]
pub(crate) flags: BlockFlags,
#[doc(alias = "Block_size")]
pub(crate) reserved: MaybeUninit<c_int>,
pub invoke: Option<unsafe extern "C" fn()>,
pub(crate) descriptor: BlockDescriptorPtr,
}
#[repr(C)]
#[derive(Clone, Copy)]
pub(crate) union BlockDescriptorPtr {
pub(crate) basic: *const BlockDescriptor,
pub(crate) with_copy_dispose: *const BlockDescriptorCopyDispose,
pub(crate) with_signature: *const BlockDescriptorSignature,
pub(crate) with_copy_dispose_signature: *const BlockDescriptorCopyDisposeSignature,
}
#[repr(C)]
#[doc(alias = "__block_descriptor")]
#[doc(alias = "Block_descriptor_1")]
#[derive(Clone, Copy, Debug)]
pub(crate) struct BlockDescriptor {
pub(crate) reserved: c_ulong,
pub(crate) size: c_ulong,
}
#[repr(C)]
#[doc(alias = "__block_descriptor")]
#[doc(alias = "Block_descriptor_2")]
#[derive(Clone, Copy, Debug)]
pub(crate) struct BlockDescriptorCopyDispose {
pub(crate) reserved: c_ulong,
pub(crate) size: c_ulong,
pub(crate) copy: Option<unsafe extern "C" fn(dst: *mut c_void, src: *const c_void)>,
pub(crate) dispose: Option<unsafe extern "C" fn(src: *mut c_void)>,
}
#[repr(C)]
#[doc(alias = "__block_descriptor")]
#[doc(alias = "Block_descriptor_3")]
#[derive(Clone, Copy, Debug)]
pub(crate) struct BlockDescriptorSignature {
pub(crate) reserved: c_ulong,
pub(crate) size: c_ulong,
#[doc(alias = "signature")]
pub(crate) encoding: *const c_char,
}
#[repr(C)]
#[doc(alias = "__block_descriptor")]
#[doc(alias = "Block_descriptor_2")]
#[doc(alias = "Block_descriptor_3")]
#[derive(Clone, Copy, Debug)]
pub(crate) struct BlockDescriptorCopyDisposeSignature {
pub(crate) reserved: c_ulong,
pub(crate) size: c_ulong,
pub(crate) copy: Option<unsafe extern "C" fn(dst: *mut c_void, src: *const c_void)>,
pub(crate) dispose: Option<unsafe extern "C" fn(src: *mut c_void)>,
#[doc(alias = "signature")]
pub(crate) encoding: *const c_char,
}
#[cfg(test)]
mod tests {
use super::*;
fn assert_no_trailing_padding<T>() {
struct AddU8<T> {
t: T,
extra: u8,
}
assert_ne!(core::mem::size_of::<T>(), core::mem::size_of::<AddU8<T>>());
}
#[test]
fn no_types_have_padding() {
assert_no_trailing_padding::<BlockHeader>();
assert_no_trailing_padding::<BlockDescriptorPtr>();
assert_no_trailing_padding::<BlockDescriptor>();
assert_no_trailing_padding::<BlockDescriptorCopyDispose>();
assert_no_trailing_padding::<BlockDescriptorSignature>();
assert_no_trailing_padding::<BlockDescriptorCopyDisposeSignature>();
}
}