package objc_Foundation import "core:intrinsics" @(objc_class="NSConcreteGlobalBlock") Block :: struct {using _: Object} @(objc_type=Block, objc_name="createGlobal", objc_is_class_method=true) Block_createGlobal :: proc "c" (user_data: rawptr, user_proc: proc "c" (user_data: rawptr)) -> ^Block { return Block_createInternal(true, user_data, user_proc) } @(objc_type=Block, objc_name="createLocal", objc_is_class_method=true) Block_createLocal :: proc "c" (user_data: rawptr, user_proc: proc "c" (user_data: rawptr)) -> ^Block { return Block_createInternal(false, user_data, user_proc) } @(private) Internal_Block_Literal_Base :: struct { isa: ^intrinsics.objc_class, flags: u32, reserved: u32, invoke: proc "c" (^Internal_Block_Literal), descriptor: ^Block_Descriptor, } @(private) Internal_Block_Literal :: struct { using base: Internal_Block_Literal_Base, // Imported Variables user_proc: proc "c" (user_data: rawptr), user_data: rawptr, } @(private) Block_Descriptor :: struct { reserved: uint, size: uint, copy_helper: proc "c" (dst, src: rawptr), dispose_helper: proc "c" (src: rawptr), signature: cstring, } @(private) global_block_descriptor := Block_Descriptor{ reserved = 0, size = size_of(Internal_Block_Literal), } @(private="file") Block_createInternal :: proc "c" (is_global: bool, user_data: rawptr, user_proc: proc "c" (user_data: rawptr)) -> ^Block { // Set to true on blocks that have captures (and thus are not true // global blocks) but are known not to escape for various other // reasons. For backward compatibility with old runtimes, whenever // BLOCK_IS_NOESCAPE is set, BLOCK_IS_GLOBAL is set too. Copying a // non-escaping block returns the original block and releasing such a // block is a no-op, which is exactly how global blocks are handled. BLOCK_IS_NOESCAPE :: (1 << 23)|BLOCK_IS_GLOBAL BLOCK_HAS_COPY_DISPOSE :: 1 << 25 BLOCK_HAS_CTOR :: 1 << 26 // helpers have C++ code BLOCK_IS_GLOBAL :: 1 << 28 BLOCK_HAS_STRET :: 1 << 29 // IFF BLOCK_HAS_SIGNATURE BLOCK_HAS_SIGNATURE :: 1 << 30 extraBytes :: size_of(Internal_Block_Literal) - size_of(Internal_Block_Literal_Base) cls := intrinsics.objc_find_class("NSConcreteGlobalBlock") bl := (^Internal_Block_Literal)(AllocateObject(cls, extraBytes, nil)) bl.isa = cls bl.flags = BLOCK_IS_GLOBAL if is_global else 0 bl.invoke = proc "c" (bl: ^Internal_Block_Literal) { bl.user_proc(bl.user_data) } bl.descriptor = &global_block_descriptor bl.user_proc = user_proc bl.user_data = user_data return auto_cast bl }