Skip to content

Commit

Permalink
runtime use CoreFoundation
Browse files Browse the repository at this point in the history
  • Loading branch information
hsiafan committed Aug 18, 2023
1 parent 4f2b310 commit c2311ff
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 151 deletions.
2 changes: 1 addition & 1 deletion objc/objc_cgo.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package objc

// #cgo CFLAGS: -x objective-c -Wno-unguarded-availability-new
// #cgo LDFLAGS: -framework Foundation -framework CoreFoundation
// #cgo LDFLAGS: -framework CoreFoundation
import "C"
122 changes: 67 additions & 55 deletions objc/type_convertion.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
package objc

// #import <stdint.h>
// #include "type_convertion.h"
// void* to_ns_string(const char* str);
// const char* to_c_string(void* ptr);
// #import <stdlib.h>
// #import <stdbool.h>
// void* to_ns_string(void* str, unsigned long len);
// const char* to_c_string(void* ptr, bool* shouldFree);
//
// void* to_ns_data(data);
// data to_c_bytes(void* ptr);
// void* to_ns_data(void* data, unsigned long len);
// void* to_c_bytes(void* ptr, unsigned long *len);
//
// void* to_ns_array(array array);
// array to_c_array(void* ptr);
// void* to_ns_array(void** items, unsigned long len);
// unsigned long ns_array_len(void* ptr);
// void ns_array_get(void* ptr, void** item, unsigned long len);
//
// dict to_c_items(void* ptr);
// void* to_ns_dict(dict cDict);
// void* to_ns_dict(void** keys, void** values, unsigned long size);
// unsigned long ns_dict_size(void* ptr);
// void ns_dict_get(void* ptr, void** keys, void** values);
import "C"

import (
Expand Down Expand Up @@ -42,17 +45,32 @@ type reValue struct {
// flagIndir: val holds a pointer to the data
var flagIndir uintptr = 1 << 7

func autoRelease(p unsafe.Pointer) unsafe.Pointer {
MakeObject(p).Autorelease()
return p
}

func ToNSString(s string) unsafe.Pointer {
cs := C.CString(s)
defer C.free(unsafe.Pointer(cs))
return C.to_ns_string(cs)
sp := unsafe.StringData(s)

Check failure on line 54 in objc/type_convertion.go

View workflow job for this annotation

GitHub Actions / build

undefined: unsafe.StringData
p := C.to_ns_string(unsafe.Pointer(sp), C.ulong(len(s)))
return autoRelease(p)
}

func ToGoString(p unsafe.Pointer) string {
if p == nil {
return ""
}
return C.GoString(C.to_c_string(p))
cstr := CallMethod[*C.char](MakeObject(p), GetSelector("UTF8String"))
if cstr != nil {
return C.GoString(cstr)
}
var shouldFree C.bool
cstr = C.to_c_string(p, &shouldFree)
str := C.GoString(cstr)
if shouldFree {
C.free(unsafe.Pointer(cstr))
}
return str
}

func ToNSData(bytes []byte) unsafe.Pointer {
Expand All @@ -61,28 +79,25 @@ func ToNSData(bytes []byte) unsafe.Pointer {
}
size := len(bytes)
var p unsafe.Pointer
var d C.data
if size == 0 {
p = C.to_ns_data(d)
p = C.to_ns_data(nil, C.ulong(0))
} else {
p = C.to_ns_data(C.data{
len: C.ulong(size),
data: unsafe.Pointer(&bytes[0]),
})
p = C.to_ns_data(unsafe.Pointer(&bytes[0]), C.ulong(size))
}
return p
return autoRelease(p)
}

func ToGoBytes(p unsafe.Pointer) []byte {
if p == nil {
return nil
}
d := C.to_c_bytes(p)
size := int(d.len)
var len C.ulong
data := C.to_c_bytes(p, &len)
size := int(len)
if size <= 0 {
return nil
}
bytes := unsafe.Slice((*byte)(d.data), size)
bytes := unsafe.Slice((*byte)(data), size)
newBytes := make([]byte, size)
copy(newBytes, bytes)
return newBytes
Expand Down Expand Up @@ -140,27 +155,26 @@ func ToNSArray(slice reflect.Value) unsafe.Pointer {
if slice.IsNil() {
return nil
}
var cArray C.array
if slice.Len() > 0 {
cArrayData := make([]unsafe.Pointer, slice.Len())
for i := 0; i < slice.Len(); i++ {
cArrayData[i] = toNSElement(slice.Index(i))
}
cArray.data = unsafe.Pointer(&cArrayData[0])
cArray.len = C.ulong(len(cArrayData))
if slice.Len() == 0 {
return autoRelease(C.to_ns_array(nil, C.ulong(0)))
}
cArrayData := make([]unsafe.Pointer, slice.Len())
for i := 0; i < slice.Len(); i++ {
cArrayData[i] = toNSElement(slice.Index(i))
}
return C.to_ns_array(cArray)
return autoRelease(C.to_ns_array((*unsafe.Pointer)(&cArrayData[0]), C.ulong(len(cArrayData))))
}

func ToGoSlice(ptr unsafe.Pointer, sliceType reflect.Type) reflect.Value {
if ptr == nil {
return reflect.New(sliceType).Elem()
}
ca := C.to_c_array(ptr)
if ca.len > 0 {
defer C.free(ca.data)
length := int(C.ns_array_len(ptr))
if length == 0 {
return reflect.MakeSlice(sliceType, 0, 0)
}
ptrSlice := unsafe.Slice((*unsafe.Pointer)(ca.data), int(ca.len))
ptrSlice := make([]unsafe.Pointer, length)
C.ns_array_get(ptr, (*unsafe.Pointer)(&ptrSlice[0]), C.ulong(length))
var slice = reflect.MakeSlice(sliceType, len(ptrSlice), len(ptrSlice))
for idx, ptr := range ptrSlice {
slice.Index(idx).Set(toGoElement(ptr, sliceType.Elem()))
Expand All @@ -172,33 +186,31 @@ func ToNSDict(m reflect.Value) unsafe.Pointer {
if m.IsNil() {
return nil
}
var cDict C.dict
if m.Len() > 0 {
keyData := make([]unsafe.Pointer, m.Len())
valueData := make([]unsafe.Pointer, m.Len())
for idx, k := range m.MapKeys() {
v := m.MapIndex(k)
keyData[idx] = toNSElement(k)
valueData[idx] = toNSElement(v)
}
cDict.key_data = unsafe.Pointer(&keyData[0])
cDict.value_data = unsafe.Pointer(&valueData[0])
cDict.len = C.ulong(m.Len())
if m.Len() == 0 {
return C.to_ns_dict(nil, nil, 0)
}
return C.to_ns_dict(cDict)
keys := make([]unsafe.Pointer, m.Len())
values := make([]unsafe.Pointer, m.Len())
for idx, k := range m.MapKeys() {
v := m.MapIndex(k)
keys[idx] = toNSElement(k)
values[idx] = toNSElement(v)
}
rp := C.to_ns_dict((*unsafe.Pointer)(&keys[0]), (*unsafe.Pointer)(&values[0]), C.ulong(m.Len()))
return autoRelease(rp)
}

func ToGoMap(ptr unsafe.Pointer, mapType reflect.Type) reflect.Value {
if ptr == nil {
return reflect.New(mapType).Elem()
}
cDict := C.to_c_items(ptr)
if cDict.len > 0 {
defer C.free(cDict.key_data)
defer C.free(cDict.value_data)
size := int(C.ns_dict_size(ptr))
if size == 0 {
return reflect.MakeMap(mapType)
}
keys := unsafe.Slice((*unsafe.Pointer)(cDict.key_data), int(cDict.len))
values := unsafe.Slice((*unsafe.Pointer)(cDict.value_data), int(cDict.len))
keys := make([]unsafe.Pointer, size)
values := make([]unsafe.Pointer, size)
C.ns_dict_get(ptr, (*unsafe.Pointer)(&keys[0]), (*unsafe.Pointer)(&values[0]))
var m = reflect.MakeMap(mapType)
for idx, k := range keys {
v := values[idx]
Expand Down
19 changes: 0 additions & 19 deletions objc/type_convertion.h

This file was deleted.

123 changes: 47 additions & 76 deletions objc/type_convertion.m
Original file line number Diff line number Diff line change
@@ -1,92 +1,63 @@
#import "type_convertion.h"
#import <Foundation/NSString.h>
#import <Foundation/NSData.h>
#import <Foundation/NSArray.h>
#import <Foundation/NSDictionary.h>
#import <stdint.h>
#import <stdlib.h>
#import <stdbool.h>
#import <CoreFoundation/CFString.h>
#import <CoreFoundation/CFData.h>
#import <CoreFoundation/CFArray.h>
#import <CoreFoundation/CFDictionary.h>

void* to_ns_string(const char* str) {
return [NSString stringWithUTF8String:str];
}

const char* to_c_string(void* ptr) {
return [((NSString*)ptr) UTF8String];
void* to_ns_string(void* str, unsigned long len) {
return (void*)CFStringCreateWithBytes(kCFAllocatorDefault, (const UInt8 *)str, len, kCFStringEncodingUTF8, false);
}

void* to_ns_data(data d) {
if (d.len <= 0) {
return [NSData data];
const char* to_c_string(void* ptr, bool* shouldFree) {
const char * cstr = CFStringGetCStringPtr(ptr, kCFStringEncodingUTF8);
if (cstr != NULL) {
return cstr;
}
CFIndex length = CFStringGetLength(ptr);
CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1;
char *buffer = (char *)malloc(maxSize);
if (CFStringGetCString(ptr, buffer, maxSize, kCFStringEncodingUTF8)) {
*shouldFree = true;
return buffer;
}
return [NSData dataWithBytes:(Byte *)d.data length:d.len];
free(buffer); // If we failed
return NULL;
}

data to_c_bytes(void* ptr) {
NSData* nsData = (NSData*)ptr;
data array = {
.data = [nsData bytes],
.len = nsData.length
};
return array;
void* to_ns_data(void* data, unsigned long len) {
return (void *)CFDataCreate(kCFAllocatorDefault, (const UInt8 *)data, len);
}

void* to_ns_array(array array) {
NSMutableArray* nsArray = [NSMutableArray arrayWithCapacity:array.len];
if (array.len > 0) {
void** arrayData = (void**)array.data;
for (int i = 0; i < array.len; i++) {
void* p = arrayData[i];
[nsArray addObject:(NSObject*)p];
}
}
return nsArray;
void* to_c_bytes(void* ptr, unsigned long *len) {
*len = CFDataGetLength(ptr);
const UInt8 * bytesPtr = CFDataGetBytePtr(ptr);
return (void*)bytesPtr;
}

array to_c_array(void* ptr) {
NSArray* result_ = (NSArray*)ptr;
array result_Array;
int result_count = [result_ count];
if (result_count > 0) {
void** result_Data = malloc(result_count * sizeof(void*));
for (int i = 0; i < result_count; i++) {
void* p = [result_ objectAtIndex:i];
result_Data[i] = p;
}
result_Array.data = result_Data;
result_Array.len = result_count;
}
return result_Array;
void* to_ns_array(void** items, unsigned long len) {
return (void*)CFArrayCreate(kCFAllocatorDefault, (const void**)items, len, &kCFTypeArrayCallBacks);
}

dict to_c_items(void* ptr) {
NSDictionary* result_ = (NSDictionary*)ptr;
dict c_dict;
NSArray * keys = [result_ allKeys];
int size = [keys count];
if (size > 0) {
void** key_data = malloc(size * sizeof(void*));
void** value_data = malloc(size * sizeof(void*));
for (int i = 0; i < size; i++) {
NSString* kp = [keys objectAtIndex:i];
id vp = result_[kp];
key_data[i] = kp;
value_data[i] = vp;
}
c_dict.key_data = key_data;
c_dict.value_data = value_data;
c_dict.len = size;
}
return c_dict;
unsigned long ns_array_len(void* ptr) {
return CFArrayGetCount(ptr);
}

void* to_ns_dict(dict cDict) {
NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithCapacity:cDict.len];
if (cDict.len > 0) {
void** key_data = (void**)cDict.key_data;
void** value_data = (void**)cDict.value_data;
for (int i = 0; i < cDict.len; i++) {
void* kp = key_data[i];
void* vp = value_data[i];
[dict setObject:(id)vp forKey:(id<NSCopying>)(NSString*)kp];
}
}
return dict;
void ns_array_get(void* ptr, const void** item, unsigned long len) {
CFArrayGetValues(ptr, CFRangeMake(0, len), item);
}


void* to_ns_dict(const void** keys, const void** values, unsigned long size) {
return (void*)CFDictionaryCreate(kCFAllocatorDefault, keys, values, size, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
}

unsigned long ns_dict_size(void* ptr) {
return CFDictionaryGetCount(ptr);
}

void ns_dict_get(void* ptr, const void** keys, const void** values) {
CFDictionaryGetKeysAndValues(ptr, keys, values);
}
Loading

0 comments on commit c2311ff

Please sign in to comment.