detached aa1b0f6

objc: add protocol support (#46)

needed for ebitengien#2326
commit
aa1b0f680473761735af9ba5c3c0ee717fdb39db
author
TotallyGamerJet · · 2022-09-15 04:40 UTC
committer
GitHub · · 2022-09-15 04:40 UTC
parent
02d7b30
signature
GPG Unverified4AEE18F83AFDEB23 The key is unknown
1 file · +22 -0
M objc/objc_runtime_darwin.go +22 -0
@@ -25,6 +25,7 @@ var (
2525 objc_msgSend = purego.Dlsym(objc, "objc_msgSend")
2626 objc_msgSendSuper2 = purego.Dlsym(objc, "objc_msgSendSuper2")
2727 objc_getClass = purego.Dlsym(objc, "objc_getClass")
28+ objc_getProtocol = purego.Dlsym(objc, "objc_getProtocol")
2829 objc_allocateClassPair = purego.Dlsym(objc, "objc_allocateClassPair")
2930 objc_registerClassPair = purego.Dlsym(objc, "objc_registerClassPair")
3031 sel_registerName = purego.Dlsym(objc, "sel_registerName")
@@ -32,6 +33,7 @@ var (
3233 class_getInstanceVariable = purego.Dlsym(objc, "class_getInstanceVariable")
3334 class_addMethod = purego.Dlsym(objc, "class_addMethod")
3435 class_addIvar = purego.Dlsym(objc, "class_addIvar")
36+ class_addProtocol = purego.Dlsym(objc, "class_addProtocol")
3537 ivar_getOffset = purego.Dlsym(objc, "ivar_getOffset")
3638 object_getClass = purego.Dlsym(objc, "object_getClass")
3739 )
@@ -189,6 +191,14 @@ func (c Class) AddIvar(name string, ty interface{}, types string) bool {
189191 return byte(ret) != 0
190192 }
191193
194+// AddProtocol adds a protocol to a class.
195+// Returns true if the protocol was added successfully, otherwise false (for example,
196+// the class already conforms to that protocol).
197+func (c Class) AddProtocol(protocol *Protocol) bool {
198+ ret, _, _ := purego.SyscallN(class_addProtocol, uintptr(c), uintptr(unsafe.Pointer(protocol)))
199+ return byte(ret) != 0
200+}
201+
192202 // InstanceVariable returns an Ivar data structure containing information about the instance variable specified by name.
193203 func (c Class) InstanceVariable(name string) Ivar {
194204 n := strings.CString(name)
@@ -215,6 +225,18 @@ func (i Ivar) Offset() uintptr {
215225 return ret
216226 }
217227
228+// Protocol is a type that declares methods that can be implemented by any class.
229+type Protocol uintptr
230+
231+// GetProtocol returns the protocol for the given name or nil if there is no protocol by that name.
232+func GetProtocol(name string) *Protocol {
233+ n := strings.CString(name)
234+ p, _, _ := purego.SyscallN(objc_getProtocol, uintptr(unsafe.Pointer(n)))
235+ runtime.KeepAlive(n)
236+ // We take the address and then dereference it to trick go vet from creating a possible miss-use of unsafe.Pointer
237+ return *(**Protocol)(unsafe.Pointer(&p))
238+}
239+
218240 // IMP is a function pointer that can be called by Objective-C code.
219241 type IMP uintptr
220242
@@ -25,6 +25,7 @@ var (
25 objc_msgSend = purego.Dlsym(objc, "objc_msgSend")25 objc_msgSend = purego.Dlsym(objc, "objc_msgSend")
26 objc_msgSendSuper2 = purego.Dlsym(objc, "objc_msgSendSuper2")26 objc_msgSendSuper2 = purego.Dlsym(objc, "objc_msgSendSuper2")
27 objc_getClass = purego.Dlsym(objc, "objc_getClass")27 objc_getClass = purego.Dlsym(objc, "objc_getClass")
28+ objc_getProtocol = purego.Dlsym(objc, "objc_getProtocol")
28 objc_allocateClassPair = purego.Dlsym(objc, "objc_allocateClassPair")29 objc_allocateClassPair = purego.Dlsym(objc, "objc_allocateClassPair")
29 objc_registerClassPair = purego.Dlsym(objc, "objc_registerClassPair")30 objc_registerClassPair = purego.Dlsym(objc, "objc_registerClassPair")
30 sel_registerName = purego.Dlsym(objc, "sel_registerName")31 sel_registerName = purego.Dlsym(objc, "sel_registerName")
@@ -32,6 +33,7 @@ var (
32 class_getInstanceVariable = purego.Dlsym(objc, "class_getInstanceVariable")33 class_getInstanceVariable = purego.Dlsym(objc, "class_getInstanceVariable")
33 class_addMethod = purego.Dlsym(objc, "class_addMethod")34 class_addMethod = purego.Dlsym(objc, "class_addMethod")
34 class_addIvar = purego.Dlsym(objc, "class_addIvar")35 class_addIvar = purego.Dlsym(objc, "class_addIvar")
36+ class_addProtocol = purego.Dlsym(objc, "class_addProtocol")
35 ivar_getOffset = purego.Dlsym(objc, "ivar_getOffset")37 ivar_getOffset = purego.Dlsym(objc, "ivar_getOffset")
36 object_getClass = purego.Dlsym(objc, "object_getClass")38 object_getClass = purego.Dlsym(objc, "object_getClass")
37 )39 )
@@ -189,6 +191,14 @@ func (c Class) AddIvar(name string, ty interface{}, types string) bool {
189 return byte(ret) != 0191 return byte(ret) != 0
190 }192 }
191 193
194+// AddProtocol adds a protocol to a class.
195+// Returns true if the protocol was added successfully, otherwise false (for example,
196+// the class already conforms to that protocol).
197+func (c Class) AddProtocol(protocol *Protocol) bool {
198+ ret, _, _ := purego.SyscallN(class_addProtocol, uintptr(c), uintptr(unsafe.Pointer(protocol)))
199+ return byte(ret) != 0
200+}
201+
192 // InstanceVariable returns an Ivar data structure containing information about the instance variable specified by name.202 // InstanceVariable returns an Ivar data structure containing information about the instance variable specified by name.
193 func (c Class) InstanceVariable(name string) Ivar {203 func (c Class) InstanceVariable(name string) Ivar {
194 n := strings.CString(name)204 n := strings.CString(name)
@@ -215,6 +225,18 @@ func (i Ivar) Offset() uintptr {
215 return ret225 return ret
216 }226 }
217 227
228+// Protocol is a type that declares methods that can be implemented by any class.
229+type Protocol uintptr
230+
231+// GetProtocol returns the protocol for the given name or nil if there is no protocol by that name.
232+func GetProtocol(name string) *Protocol {
233+ n := strings.CString(name)
234+ p, _, _ := purego.SyscallN(objc_getProtocol, uintptr(unsafe.Pointer(n)))
235+ runtime.KeepAlive(n)
236+ // We take the address and then dereference it to trick go vet from creating a possible miss-use of unsafe.Pointer
237+ return *(**Protocol)(unsafe.Pointer(&p))
238+}
239+
218 // IMP is a function pointer that can be called by Objective-C code.240 // IMP is a function pointer that can be called by Objective-C code.
219 type IMP uintptr241 type IMP uintptr
220 242

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 102

↑↓ moveenter openesc close