aboutsummaryrefslogtreecommitdiff
path: root/core/sys/darwin/Foundation/NSBlock.odin
diff options
context:
space:
mode:
authorgingerBill <gingerBill@users.noreply.github.com>2024-04-08 16:30:44 +0100
committerGitHub <noreply@github.com>2024-04-08 16:30:44 +0100
commita00d96c0de2c0b6e4df76e58c1c394373e173751 (patch)
treec12fb1c6a72d3c5282b1ff5a4ae241c11334a3c1 /core/sys/darwin/Foundation/NSBlock.odin
parentecac3aef3275e199deac2ce568647d14049f9e49 (diff)
parentef82f3e71e6ad08ecffa578b44a6dd1323676f0b (diff)
Merge pull request #3395 from odin-lang/darwin-reorganizationdev-2024-04
Move `vendor:darwin/Foundation` to `core:sys/darwin/Foundation`
Diffstat (limited to 'core/sys/darwin/Foundation/NSBlock.odin')
-rw-r--r--core/sys/darwin/Foundation/NSBlock.odin120
1 files changed, 120 insertions, 0 deletions
diff --git a/core/sys/darwin/Foundation/NSBlock.odin b/core/sys/darwin/Foundation/NSBlock.odin
new file mode 100644
index 000000000..b9d94bfee
--- /dev/null
+++ b/core/sys/darwin/Foundation/NSBlock.odin
@@ -0,0 +1,120 @@
+package objc_Foundation
+
+import "base:intrinsics"
+import "base:builtin"
+import "core:mem"
+
+@(objc_class="NSBlock")
+Block :: struct {using _: Object}
+
+@(objc_type=Block, objc_name="createGlobal", objc_is_class_method=true)
+Block_createGlobal :: proc (user_data: rawptr, user_proc: proc "c" (user_data: rawptr), allocator := context.allocator) -> (^Block, mem.Allocator_Error) #optional_allocator_error {
+ return Block_createInternal(true, user_data, user_proc, allocator)
+}
+@(objc_type=Block, objc_name="createLocal", objc_is_class_method=true)
+Block_createLocal :: proc (user_data: rawptr, user_proc: proc "c" (user_data: rawptr)) -> ^Block {
+ b, _ := Block_createInternal(false, user_data, user_proc, {})
+ return b
+}
+@(objc_type=Block, objc_name="createGlobalWithParam", objc_is_class_method=true)
+Block_createGlobalWithParam :: proc (user_data: rawptr, user_proc: proc "c" (user_data: rawptr, t: $T), allocator := context.allocator) -> (^Block, mem.Allocator_Error) #optional_allocator_error {
+ return Block_createInternalWithParam(true, user_data, user_proc, allocator)
+}
+@(objc_type=Block, objc_name="createLocalWithParam", objc_is_class_method=true)
+Block_createLocalWithParam :: proc (user_data: rawptr, user_proc: proc "c" (user_data: rawptr, t: $T)) -> ^Block {
+ b, _ := Block_createInternalWithParam(false, user_data, user_proc, {})
+ return b
+}
+
+@(private)
+Internal_Block_Literal_Base :: struct {
+ isa: ^intrinsics.objc_class,
+ flags: u32,
+ reserved: u32,
+ invoke: rawptr, // contains a pointer to a proc "c" (^Internal_Block_Literal, ...)
+ descriptor: ^Block_Descriptor,
+}
+
+@(private)
+Internal_Block_Literal :: struct {
+ using base: Internal_Block_Literal_Base,
+ // Imported Variables
+ user_proc: rawptr, // contains a pointer to a 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),
+}
+
+foreign import libSystem "system:System.framework"
+foreign libSystem {
+ _NSConcreteGlobalBlock: intrinsics.objc_class
+ _NSConcreteStackBlock: intrinsics.objc_class
+}
+
+@(private="file")
+internal_block_literal_make :: proc (is_global: bool, user_data: rawptr, user_proc: rawptr, invoke: rawptr, allocator: mem.Allocator) -> (b: ^Block, err: mem.Allocator_Error) {
+ _init :: proc(bl: ^Internal_Block_Literal, is_global: bool, user_data: rawptr, user_proc: rawptr, invoke: rawptr) {
+ // 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
+
+ bl.isa = is_global ? &_NSConcreteGlobalBlock : &_NSConcreteStackBlock
+ bl.flags = BLOCK_IS_GLOBAL if is_global else 0
+ bl.invoke = invoke
+ bl.descriptor = &global_block_descriptor
+ bl.user_proc = auto_cast user_proc
+ bl.user_data = user_data
+ }
+ if is_global {
+ bl := builtin.new (Internal_Block_Literal, allocator) or_return
+ _init(bl, true, user_data, user_proc, invoke)
+ return auto_cast bl, .None
+ } else {
+ // malloc blocks are created by calling 'copy' on a stack block
+ bl: Internal_Block_Literal
+ _init(&bl, false, user_data, user_proc, invoke)
+ return auto_cast copy(cast(^Copying(Block))(&bl)), .None
+ }
+}
+
+@(private="file")
+Block_createInternal :: proc (is_global: bool, user_data: rawptr, user_proc: proc "c" (user_data: rawptr), allocator: mem.Allocator) -> (b: ^Block, err: mem.Allocator_Error) {
+ invoke :: proc "c" (bl: ^Internal_Block_Literal) {
+ user_proc := (proc "c" (rawptr))(bl.user_proc)
+ user_proc(bl.user_data)
+ }
+ return internal_block_literal_make(is_global, user_data, auto_cast user_proc, auto_cast invoke, allocator)
+}
+
+@(private="file")
+Block_createInternalWithParam :: proc (is_global: bool, user_data: rawptr, user_proc: proc "c" (user_data: rawptr, t: $T), allocator: mem.Allocator) -> (b: ^Block, err: mem.Allocator_Error) {
+ invoke :: proc "c" (bl: ^Internal_Block_Literal, t: T) {
+ user_proc := (proc "c" (rawptr, T))(bl.user_proc)
+ user_proc(bl.user_data, t)
+ }
+ return internal_block_literal_make(is_global, user_data, auto_cast user_proc, auto_cast invoke, allocator)
+}
+