Last active
December 21, 2017 15:21
-
-
Save mrphobby/a247deb15d38aea86b3346079f32ce58 to your computer and use it in GitHub Desktop.
Primitive Objective-C support in D
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module cocoa.objc; | |
version(OSX): | |
import cocoa.runtime; | |
struct ObjCMethod { | |
const(char)* selector; | |
} | |
struct ObjCSuperClass { | |
const(char)* superclass; | |
} | |
mixin template MetaclassTrait() { | |
import std.meta : Alias; | |
alias Parent = Alias!(__traits(parent, typeof(this))); | |
extern(D) private static Class classof() { | |
import cocoa.runtime : objc_lookUpClass; | |
enum name = __traits(identifier, Parent); | |
auto cls = cast(typeof(this)) objc_lookUpClass(name); | |
assert(cls, "Failed to lookup class: " ~ name); | |
return cls; | |
} | |
} | |
mixin template ClassTrait() { | |
extern(Objective-C) interface Class { | |
mixin MetaclassTrait; | |
Parent alloc() @selector("alloc"); | |
} | |
extern(D) private static Class classof() { | |
return Class.classof; | |
} | |
extern(D) static typeof(this) alloc() { | |
return classof.alloc(); | |
} | |
} | |
mixin template ObjCClass() { | |
mixin ClassTrait; | |
shared static this() { | |
import std.traits; | |
import std.meta : Alias, AliasSeq; | |
alias Class = typeof(this); | |
alias BaseClasses = AliasSeq!(InterfacesTuple!Class); | |
auto attrs = getUDAs!(Class, ObjCSuperClass); | |
const(char)* superClass; | |
static if (attrs.length > 0) | |
superClass = attrs[0].superclass; | |
else | |
superClass = BaseClasses[0].stringof; | |
objc_method[] methods; | |
foreach (symbol ; getSymbolsByUDA!(Class, ObjCMethod)) { | |
auto uda = getUDAs!(symbol, ObjCMethod)[0]; | |
methods ~= objc_method(sel_registerName(uda.selector), null, cast(IMP) &symbol); | |
} | |
registerClass(Class.stringof, superClass, methods); | |
} | |
} | |
void registerClass(const char* name, const char* superClassName, objc_method[] methods, objc_ivar[] ivars = []) { | |
auto superClass = objc_lookUpClass(superClassName); | |
assert(superClass, "Failed to lookup superclass"); | |
auto cls = objc_allocateClassPair(superClass, name, 0); | |
assert(cls, "Failed to allocate class pair"); | |
foreach (method ; methods) { | |
auto result = cls.class_addMethod( | |
method.method_name, | |
method.method_imp, | |
method.method_types | |
); | |
assert(result, "Failed to add method"); | |
} | |
foreach (objc_ivar ivar ; ivars) { | |
auto result = cls.class_addIvar( | |
ivar.ivar_name, | |
size_t(ivar.space), | |
cast(byte) ivar.ivar_offset, | |
ivar.ivar_type | |
); | |
assert(result, "Failed to add instance variable"); | |
} | |
objc_registerClassPair(cls); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment