Skip to content

Commit 101b175

Browse files
committed
Add initial structs and constants to block sys crate
1 parent 985b784 commit 101b175

File tree

1 file changed

+335
-2
lines changed

1 file changed

+335
-2
lines changed

objc2_block_sys/src/lib.rs

Lines changed: 335 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//!
22
//! See:
33
//! - https://github.com/apple/swift-corelibs-libdispatch/tree/main/src/BlocksRuntime
4+
//! - https://github.com/apple/swift-corelibs-foundation/tree/main/Sources/BlocksRuntime
45
//! - https://clang.llvm.org/docs/BlockLanguageSpec.html
56
//! - https://clang.llvm.org/docs/Block-ABI-Apple.html
67
@@ -14,6 +15,7 @@ extern crate objc2_sys;
1415
use core::cell::UnsafeCell;
1516
use core::ffi::c_void;
1617
use core::marker::{PhantomData, PhantomPinned};
18+
use std::os::raw::{c_char, c_ulong};
1719

1820
#[repr(C)]
1921
pub struct Class {
@@ -28,6 +30,127 @@ pub struct Class {
2830
_opaque: PhantomData<(UnsafeCell<*const ()>, PhantomPinned)>,
2931
}
3032

33+
/// Block descriptor flags.
34+
/// Values for Block_layout->flags to describe block objects
35+
#[allow(non_camel_case_types)]
36+
pub type block_flags = i32;
37+
38+
#[cfg(feature = "apple")]
39+
pub const BLOCK_DEALLOCATING: block_flags = 0x0001;
40+
41+
/// Mask for the reference count in byref structure's flags field. The low
42+
/// 3 bytes are reserved for the reference count, the top byte for the flags.
43+
#[cfg(feature = "gnustep-1-7")]
44+
pub const BLOCK_REFCOUNT_MASK: block_flags = 0x00ffffff;
45+
#[cfg(any(feature = "compiler-rt", feature = "objfw"))]
46+
pub const BLOCK_REFCOUNT_MASK: block_flags = 0xffff;
47+
#[cfg(feature = "apple")]
48+
/// runtime
49+
pub const BLOCK_REFCOUNT_MASK: block_flags = 0xfffe;
50+
51+
#[cfg(feature = "apple")]
52+
/// compiler
53+
pub const BLOCK_INLINE_LAYOUT_STRING: block_flags = 1 << 21;
54+
55+
#[cfg(feature = "apple")]
56+
/// compiler
57+
pub const BLOCK_SMALL_DESCRIPTOR: block_flags = 1 << 22;
58+
59+
#[cfg(feature = "apple")] // Part of ABI?
60+
/// compiler
61+
pub const BLOCK_IS_NOESCAPE: block_flags = 1 << 23;
62+
63+
#[cfg(feature = "apple")]
64+
/// runtime
65+
pub const BLOCK_NEEDS_FREE: block_flags = 1 << 24;
66+
67+
/// The block descriptor contains copy and dispose helpers.
68+
/// compiler
69+
pub const BLOCK_HAS_COPY_DISPOSE: block_flags = 1 << 25;
70+
71+
/// The helpers have C++ code.
72+
/// compiler: helpers have C++ code
73+
pub const BLOCK_HAS_CTOR: block_flags = 1 << 26;
74+
75+
#[cfg(feature = "apple")]
76+
/// compiler
77+
pub const BLOCK_IS_GC: block_flags = 1 << 27;
78+
79+
/// Block is stored in global memory and does not need to be copied.
80+
/// compiler
81+
pub const BLOCK_IS_GLOBAL: block_flags = 1 << 28;
82+
83+
/// Block function uses a calling convention that returns a structure via a
84+
/// pointer passed in by the caller.
85+
///
86+
/// match (BLOCK_USE_STRET, BLOCK_HAS_SIGNATURE) {
87+
/// (false, false) => 10.6.ABI, no signature field available
88+
/// (true, false) => 10.6.ABI, no signature field available
89+
/// (false, true) => ABI.2010.3.16, regular calling convention, presence of signature field
90+
/// (true, true) => ABI.2010.3.16, stret calling convention, presence of signature field,
91+
/// }
92+
///
93+
/// See https://clang.llvm.org/docs/Block-ABI-Apple.html#high-level
94+
#[doc(alias = "BLOCK_USE_SRET")]
95+
#[doc(alias = "BLOCK_HAS_DESCRIPTOR")] // compiler-rt || macOS 10.6
96+
pub const BLOCK_USE_STRET: block_flags = 1 << 29;
97+
98+
/// Block has an Objective-C type encoding.
99+
/// compiler
100+
pub const BLOCK_HAS_SIGNATURE: block_flags = 1 << 30;
101+
102+
#[cfg(feature = "apple")]
103+
/// compiler
104+
pub const BLOCK_HAS_EXTENDED_LAYOUT: block_flags = 1 << 31;
105+
106+
/// Flags used in the final argument to _Block_object_assign() and
107+
/// _Block_object_dispose(). These indicate the type of copy or dispose to
108+
/// perform.
109+
/// Values for _Block_object_assign() and _Block_object_dispose() parameters
110+
///
111+
/// This is a helper type, in the sources this type does not have a name!
112+
#[allow(non_camel_case_types)]
113+
pub type block_assign_dispose_flags = i32;
114+
115+
/// The value is of some id-like type, and should be copied as an Objective-C
116+
/// object: i.e. by sending -retain or via the GC assign functions in GC mode
117+
/// (not yet supported).
118+
///
119+
/// id, NSObject, __attribute__((NSObject)), block, ...
120+
pub const BLOCK_FIELD_IS_OBJECT: block_assign_dispose_flags = 3;
121+
122+
/// The field is a block. This must be copied by the block copy functions.
123+
///
124+
/// a block variable
125+
pub const BLOCK_FIELD_IS_BLOCK: block_assign_dispose_flags = 7;
126+
127+
/// The field is an indirect reference to a variable declared with the __block
128+
/// storage qualifier.
129+
///
130+
/// the on stack structure holding the __block variable
131+
pub const BLOCK_FIELD_IS_BYREF: block_assign_dispose_flags = 8;
132+
133+
/// The field is an indirect reference to a variable declared with the __block
134+
/// storage qualifier.
135+
///
136+
/// declared __weak, only used in byref copy helpers
137+
pub const BLOCK_FIELD_IS_WEAK: block_assign_dispose_flags = 16;
138+
139+
/// The field is an indirect reference to a variable declared with the __block
140+
/// storage qualifier.
141+
///
142+
/// called from __block (byref) copy/dispose support routines.
143+
pub const BLOCK_BYREF_CALLER: block_assign_dispose_flags = 128;
144+
145+
#[cfg(feature = "apple")]
146+
pub const BLOCK_ALL_COPY_DISPOSE_FLAGS: block_assign_dispose_flags = BLOCK_FIELD_IS_OBJECT
147+
| BLOCK_FIELD_IS_BLOCK
148+
| BLOCK_FIELD_IS_BYREF
149+
| BLOCK_FIELD_IS_WEAK
150+
| BLOCK_BYREF_CALLER;
151+
152+
// TODO: BLOCK_LAYOUT_X
153+
31154
extern "C" {
32155
// the raw data space for runtime classes for blocks
33156
// class+meta used for stack, malloc, and collectable based blocks
@@ -41,9 +164,219 @@ extern "C" {
41164

42165
/// Runtime entry point called by compiler when assigning objects inside
43166
/// copy helper routines
44-
pub fn _Block_object_assign(dest_addr: *mut c_void, object: *const c_void, flags: i32);
167+
pub fn _Block_object_assign(
168+
dest_addr: *mut c_void,
169+
object: *const c_void,
170+
flags: block_assign_dispose_flags,
171+
);
45172

46173
/// runtime entry point called by the compiler when disposing of objects
47174
/// inside dispose helper routine
48-
pub fn _Block_object_dispose(object: *const c_void, flags: i32);
175+
pub fn _Block_object_dispose(object: *const c_void, flags: block_assign_dispose_flags);
176+
}
177+
178+
#[cfg(feature = "apple")]
179+
extern "C" {
180+
// Whether the return value of the block is on the stack.
181+
// macOS 10.7
182+
// pub fn _Block_use_stret(block: *mut c_void) -> bool;
183+
184+
// Returns a string describing the block's GC layout.
185+
// This uses the GC skip/scan encoding.
186+
// May return NULL.
187+
// macOS 10.7
188+
// pub fn _Block_layout(block: *mut c_void) -> *const c_char;
189+
190+
// Returns a string describing the block's layout.
191+
// This uses the "extended layout" form described above.
192+
// May return NULL.
193+
// macOS 10.8
194+
// pub fn _Block_extended_layout(block: *mut c_void) -> *const c_char;
195+
196+
// Callable only from the ARR weak subsystem while in exclusion zone
197+
// macOS 10.7
198+
// pub fn _Block_tryRetain(block: *const c_void) -> bool;
199+
200+
// Callable only from the ARR weak subsystem while in exclusion zone
201+
// macOS 10.7
202+
// pub fn _Block_isDeallocating(block: *const c_void) -> bool;
203+
}
204+
205+
#[cfg(any(feature = "apple", feature = "compiler-rt"))]
206+
extern "C" {
207+
// the raw data space for runtime classes for blocks
208+
// class+meta used for stack, malloc, and collectable based blocks
209+
210+
pub static _NSConcreteAutoBlock: Class;
211+
pub static _NSConcreteFinalizingBlock: Class;
212+
pub static _NSConcreteWeakBlockVariable: Class;
213+
214+
pub fn Block_size(block: *mut c_void) -> c_ulong; // usize
215+
}
216+
217+
#[cfg(any(feature = "apple", feature = "gnustep-1-7"))]
218+
extern "C" {
219+
// indicates whether block was compiled with compiler that sets the ABI
220+
// related metadata bits
221+
// macOS 10.7
222+
// pub fn _Block_has_signature(block: *mut c_void) -> bool;
223+
224+
// Returns a string describing the block's parameter and return types.
225+
// The encoding scheme is the same as Objective-C @encode.
226+
// Returns NULL for blocks compiled with some compilers.
227+
// macOS 10.7
228+
// pub fn _Block_signature(block: *mut c_void) -> *const c_char;
229+
}
230+
231+
#[repr(C)]
232+
pub struct Block_layout {
233+
/// Class pointer. Always initialised to &_NSConcreteStackBlock for blocks
234+
/// that are created on the stack or &_NSConcreteGlobalBlock for blocks
235+
/// that are created in global storage.
236+
pub isa: *mut Class,
237+
/// Flags.
238+
/// See the `block_flags` enumerated type for possible values.
239+
/// Contains ref count in Apple and ObjFW.
240+
pub flags: block_flags,
241+
/// Reserved - always initialised to 0 by the compiler (but this is not
242+
/// said in the specification).
243+
///
244+
/// Used for the reference count in GNUStep and WinObjC.
245+
pub reserved: i32,
246+
/// The function that implements the block. The first argument is this
247+
/// structure, the subsequent arguments are the block's explicit
248+
/// parameters. If the BLOCK_USE_SRET & BLOCK_HAS_SIGNATURE flag is set,
249+
/// there is an additional hidden argument, which is a pointer to the
250+
/// space on the stack allocated to hold the return value.
251+
pub invoke: Option<unsafe extern "C" fn(block: *mut Block_layout, ...)>,
252+
/// The block's descriptor. The actual type of this is:
253+
/// ```ignore
254+
/// match (BLOCK_HAS_COPY_DISPOSE, BLOCK_HAS_SIGNATURE) {
255+
/// (false, false) => Block_descriptor_header,
256+
/// (true, false) => Block_descriptor,
257+
/// (false, true) => Block_descriptor_basic,
258+
/// (true, true) => Block_descriptor_with_signature,
259+
/// }
260+
/// ```
261+
///
262+
/// But it is safe to access this through just `Block_descriptor_header`.
263+
pub descriptor: *mut Block_descriptor_header,
264+
}
265+
266+
#[repr(C)]
267+
pub struct Block_descriptor_header {
268+
/// Reserved for future use. Currently always 0.
269+
pub reserved: c_ulong, // usize
270+
/// Size of the block.
271+
pub size: c_ulong, // usize
272+
}
273+
274+
/// Block descriptor that contains copy and dispose operations.
275+
///
276+
/// Requires BLOCK_HAS_COPY_DISPOSE
277+
#[repr(C)]
278+
pub struct Block_descriptor {
279+
pub header: Block_descriptor_header,
280+
/// Copy function, generated by the compiler to help copy the block if it
281+
/// contains nontrivial copy operations.
282+
pub copy: Option<unsafe extern "C" fn(dst: *mut Block_byref, src: *mut Block_byref)>,
283+
/// Dispose function, generated by the compiler to help copy the block if
284+
/// it contains nontrivial destructors.
285+
pub dispose: Option<unsafe extern "C" fn(src: *mut Block_byref)>,
286+
}
287+
288+
/// Extended block descriptor that does not contain copy and dispose helper
289+
/// functions.
290+
///
291+
/// Requires BLOCK_HAS_SIGNATURE
292+
#[repr(C)]
293+
#[cfg(not(feature = "objfw"))]
294+
pub struct Block_descriptor_basic {
295+
pub header: Block_descriptor_header,
296+
297+
/// Objective-C type encoding of the block.
298+
#[doc(alias = "signature")]
299+
pub encoding: *const c_char,
300+
}
301+
302+
/// Requires BLOCK_HAS_COPY_DISPOSE and BLOCK_HAS_SIGNATURE
303+
#[repr(C)]
304+
pub struct Block_descriptor_with_signature {
305+
pub inner: Block_descriptor,
306+
307+
/// Objective-C type encoding of the block.
308+
#[doc(alias = "signature")]
309+
pub encoding: *const c_char,
310+
}
311+
312+
// #[cfg(feature = "apple")]
313+
// pub layout: *const c_char,
314+
315+
// #[repr(C)]
316+
// pub struct Block_descriptor_small {
317+
// pub size: u32,
318+
// pub signature: i32,
319+
// pub layout: i32,
320+
// pub copy: i32,
321+
// pub dispose: i32,
322+
// }
323+
324+
// #[repr(C)]
325+
// pub struct Block_basic {
326+
// pub isa: *mut c_void,
327+
// pub Block_flags: i32,
328+
// pub Block_size: i32,
329+
// pub Block_invoke: Option<unsafe extern "C" fn(block: *mut c_void)>,
330+
// pub Block_copy: Option<unsafe extern "C" fn(dst: *mut c_void, src: *mut c_void)>,
331+
// pub Block_dispose: Option<unsafe extern "C" fn(block: *mut c_void)>,
332+
// }
333+
// Example usage: https://opensource.apple.com/source/libdispatch/libdispatch-84.5/src/once.c.auto.html
334+
335+
/// Structure used for on-stack variables that are referenced by blocks.
336+
#[repr(C)]
337+
#[doc(alias = "Block_byref_1")]
338+
pub struct Block_byref_header {
339+
/// Class pointer. Currently unused on GNUStep and always NULL. Could be
340+
/// used in the future to support introspection.
341+
pub isa: *mut c_void,
342+
/// The pointer to the structure that contains the real version of the
343+
/// data. All accesses go via this pointer. If an on-stack byref structure
344+
/// is copied to the heap, then its forwarding pointer should point to the
345+
/// heap version. Otherwise it should point to itself.
346+
pub forwarding: *mut Block_byref_header,
347+
/// Flags and reference count.
348+
///
349+
/// TODO: Volatile!
350+
pub flags: block_flags,
351+
#[cfg(feature = "apple")]
352+
/// Size of this structure.
353+
pub size: u32,
354+
#[cfg(not(feature = "apple"))]
355+
/// Size of this structure.
356+
pub size: i32,
357+
}
358+
359+
/// Structure used for on-stack variables that are referenced by blocks.
360+
///
361+
/// requires BLOCK_BYREF_HAS_COPY_DISPOSE
362+
#[repr(C)]
363+
#[doc(alias = "Block_byref_2")]
364+
pub struct Block_byref {
365+
pub header: Block_byref_header,
366+
/// Copy function.
367+
pub keep:
368+
Option<unsafe extern "C" fn(dst: *mut Block_byref_header, src: *mut Block_byref_header)>,
369+
/// Dispose function.
370+
pub destroy: Option<unsafe extern "C" fn(src: *mut Block_byref_header)>,
371+
}
372+
373+
#[cfg(feature = "apple")]
374+
/// Structure used for on-stack variables that are referenced by blocks.
375+
///
376+
/// requires BLOCK_BYREF_LAYOUT_EXTENDED
377+
#[repr(C)]
378+
#[doc(alias = "Block_byref_3")]
379+
pub struct Block_byref_extended {
380+
pub inner: Block_byref,
381+
pub layout: *const c_char,
49382
}

0 commit comments

Comments
 (0)