Skip to content

Commit

Permalink
Use a union to access the block descriptor
Browse files Browse the repository at this point in the history
  • Loading branch information
madsmtm committed Jan 7, 2024
1 parent 157667e commit eb85fbf
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 43 deletions.
42 changes: 26 additions & 16 deletions crates/block2/src/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,22 +199,32 @@ pub struct BlockLayout {
/// additional hidden argument, which is a pointer to the space on the
/// stack allocated to hold the return value.
pub invoke: Option<unsafe extern "C" fn()>,
/// The block's descriptor. The actual type of this is:
/// ```pseudo-code
/// match (BLOCK_HAS_COPY_DISPOSE, BLOCK_HAS_SIGNATURE) {
/// (false, false) => BlockDescriptor,
/// (true, false) => BlockDescriptorCopyDispose,
/// (false, true) => BlockDescriptorSignature,
/// (true, true) => BlockDescriptorCopyDisposeSignature,
/// }
/// ```
///
/// Since all of these start with `BlockDescriptor`, it is always safe to
/// reinterpret this pointer as that.
///
/// Note: We don't use a `union` here, since that would be forced to have
/// a greater size than is actually required.
pub(crate) descriptor: *const c_void,
/// The block's descriptor.
pub(crate) descriptor: BlockDescriptorPtr,
}

/// The type of this is:
/// ```pseudo-code
/// match (BLOCK_HAS_COPY_DISPOSE, BLOCK_HAS_SIGNATURE) {
/// (false, false) => BlockDescriptor,
/// (true, false) => BlockDescriptorCopyDispose,
/// (false, true) => BlockDescriptorSignature,
/// (true, true) => BlockDescriptorCopyDisposeSignature,
/// }
/// ```
///
/// Since all of these start with `BlockDescriptor`, it is always safe to
/// use the `basic` field.
//
// Note: We use an union on top of the pointer, since otherwise the descriptor
// would be forced to have a greater size than is actually required.
#[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,
}

/// Basic block descriptor.
Expand Down
6 changes: 4 additions & 2 deletions crates/block2/src/concrete_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::os::raw::c_ulong;

use objc2::encode::{EncodeArgument, EncodeReturn, Encoding, RefEncode};

use crate::abi::{BlockDescriptorCopyDispose, BlockFlags, BlockLayout};
use crate::abi::{BlockDescriptorCopyDispose, BlockDescriptorPtr, BlockFlags, BlockLayout};
use crate::debug::debug_block_layout;
use crate::{ffi, Block, BlockArguments, RcBlock};

Expand Down Expand Up @@ -220,7 +220,9 @@ impl<A, R, F> ConcreteBlock<A, R, F> {
flags: Self::FLAGS,
reserved: MaybeUninit::new(0),
invoke: Some(invoke),
descriptor: &Self::DESCRIPTOR as *const BlockDescriptorCopyDispose as *mut c_void,
descriptor: BlockDescriptorPtr {
with_copy_dispose: &Self::DESCRIPTOR,
},
};
Self {
p: PhantomData,
Expand Down
30 changes: 8 additions & 22 deletions crates/block2/src/debug.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
use core::ffi::c_void;
use core::fmt::{Debug, DebugStruct, Error, Formatter};
use core::ptr;
use std::ffi::CStr;

use crate::abi::{
BlockDescriptor, BlockDescriptorCopyDispose, BlockDescriptorCopyDisposeSignature,
BlockDescriptorSignature, BlockFlags, BlockLayout,
};
use crate::abi::{BlockDescriptorPtr, BlockFlags, BlockLayout};
use crate::ffi;

#[derive(Clone, Copy, PartialEq, Eq)]
Expand Down Expand Up @@ -52,45 +48,35 @@ pub(crate) fn debug_block_layout(layout: &BlockLayout, f: &mut DebugStruct<'_, '
);
}

#[derive(Clone, Copy, PartialEq, Eq)]
#[derive(Clone, Copy)]
struct BlockDescriptorHelper {
has_copy_dispose: bool,
has_signature: bool,
descriptor: *const c_void,
descriptor: BlockDescriptorPtr,
}

impl Debug for BlockDescriptorHelper {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
if self.descriptor.is_null() {
if unsafe { self.descriptor.basic }.is_null() {
return f.write_str("(null)");
}

let mut f = f.debug_struct("BlockDescriptor");

let header = unsafe { self.descriptor.cast::<BlockDescriptor>().as_ref().unwrap() };
let header = unsafe { self.descriptor.basic.as_ref().unwrap() };

f.field("reserved", &header.reserved);
f.field("size", &header.size);

match (self.has_copy_dispose, self.has_signature) {
(false, false) => {}
(true, false) => {
let descriptor = unsafe {
self.descriptor
.cast::<BlockDescriptorCopyDispose>()
.as_ref()
.unwrap()
};
let descriptor = unsafe { self.descriptor.with_copy_dispose.as_ref().unwrap() };
f.field("copy", &descriptor.copy);
f.field("dispose", &descriptor.dispose);
}
(false, true) => {
let descriptor = unsafe {
self.descriptor
.cast::<BlockDescriptorSignature>()
.as_ref()
.unwrap()
};
let descriptor = unsafe { self.descriptor.with_signature.as_ref().unwrap() };
f.field(
"encoding",
&if descriptor.encoding.is_null() {
Expand All @@ -103,7 +89,7 @@ impl Debug for BlockDescriptorHelper {
(true, true) => {
let descriptor = unsafe {
self.descriptor
.cast::<BlockDescriptorCopyDisposeSignature>()
.with_copy_dispose_signature
.as_ref()
.unwrap()
};
Expand Down
8 changes: 5 additions & 3 deletions crates/block2/src/global.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
use core::fmt;
use core::marker::PhantomData;
use core::mem;
use core::mem::MaybeUninit;
use core::ops::Deref;
use core::ptr;
use core::{ffi::c_void, mem::MaybeUninit};
use std::os::raw::c_ulong;

use objc2::encode::EncodeReturn;

use crate::abi::{BlockDescriptor, BlockFlags, BlockLayout};
use crate::abi::{BlockDescriptor, BlockDescriptorPtr, BlockFlags, BlockLayout};
use crate::debug::debug_block_layout;
use crate::{Block, BlockArguments};

Expand Down Expand Up @@ -65,7 +65,9 @@ impl<A, R> GlobalBlock<A, R> {
reserved: MaybeUninit::new(0),
// Populated in `global_block!`
invoke: None,
descriptor: &GLOBAL_DESCRIPTOR as *const BlockDescriptor as *mut c_void,
descriptor: BlockDescriptorPtr {
basic: &GLOBAL_DESCRIPTOR,
},
};

/// Use the [`global_block`] macro instead.
Expand Down

0 comments on commit eb85fbf

Please sign in to comment.