1 module objc.runtime;
2 
3 version(D_ObjectiveC):
4 
5 private bool isValidObjectiveCNumber(T)()
6 {
7     return  is(T == BOOL) || is(T == byte) || is(T == ubyte)  ||
8             is(T == short) || is(T == ushort) ||
9             is(T == int) || is(T == uint) ||
10             is(T == long) || is(T == ulong);
11 }
12 
13 ////ns Helper Section////
14 /**
15 *   .ns can be used as a postfix to convert almost any type to its Objective-C representation.
16 *   Currently it supports:
17     - string
18     - numbers
19     - associative arrays
20     - identity (used on any object that extends NSObject will return itself)
21 */
22 
23 NSString ns(string str)
24 {
25     import core.memory;
26     str~= '\0';
27     // scope(exit) GC.free(cast(void*)str.ptr);
28     return NSString.alloc.initWithUTF8String(str.ptr);
29 }
30 ///Identity. Always return the object itself if it inherits from NSObject
31 T ns(T)(T value) if(is(T : NSObject)){return value;}
32 
33 NSMutableDictionaryD!(K, V) ns(K, V)(V[K] aa){return NSMutableDictionaryD!(K, V)(aa);}
34 
35 NSNumberD!T ns(T)(T value) if(isValidObjectiveCNumber!T)
36 {
37     return NSNumberD!T(value);
38 }
39 
40 ////End ns Helper Section////
41 
42 
43 
44 extern(Objective-C):
45 
46 
47 public import core.attribute:selector;
48 alias BOOL = bool;
49 enum YES = true;
50 enum NO = false;
51 
52 ///Type used to represent elapsed time in seconds.
53 alias CFTimeInterval = double;
54 
55 version(watchOS)
56 {
57     alias NSUInteger = uint;
58     alias NSInteger = int;
59 } 
60 else
61 {
62     alias NSInteger = long;
63     alias NSUInteger = ulong;
64 }
65 extern class NSObject
66 {
67     static NSObject alloc() @selector("alloc");
68     NSObject initialize() @selector("init");
69     ///Increments the receiver’s reference count.
70     NSObject retain() @selector("retain");
71     ///Allocates a new instance of the receiving class, sends it an init message, and returns the initialized object.
72     NSObject new_() @selector("new");
73     ///Decrements the receiver’s reference count.
74     void release() @selector("release");
75     ///Deallocates the memory occupied by the receiver.
76     void dealloc() @selector("dealloc");
77     ///Decrements the receiver’s retain count at the end of the current autorelease pool block.
78     NSObject autorelease() @selector("autorelease");
79 
80 }
81 
82 ///A simple container for a single C or Objective-C data item.
83 extern class NSValue : NSObject
84 {
85 
86 }
87 
88 private void* _D4objc7runtime8NSNumber7__ClassZ = null;
89 ///An object wrapper for primitive scalar numeric values.
90 extern class NSNumber : NSValue
91 {
92     @selector("numberWithBool:") static NSNumber opCall(BOOL);
93     @selector("numberWithChar:") static NSNumber opCall(byte);
94     @selector("numberWithDouble:") static NSNumber opCall(double);
95     @selector("numberWithFloat:") static NSNumber opCall(float);
96     @selector("numberWithInt:") static NSNumber opCall(int);
97     @selector("numberWithLongLong:") static NSNumber opCall(long);
98     @selector("numberWithShort:") static NSNumber opCall(short);
99     @selector("numberWithUnsignedChar:") static NSNumber opCall(ubyte);
100     @selector("numberWithUnsignedInt:") static NSNumber opCall(uint);
101     @selector("numberWithUnsignedLongLong:") static NSNumber opCall(ulong);
102     @selector("numberWithUnsignedShort:") static NSNumber opCall(ushort);
103 
104     @selector("boolValue") BOOL boolValue();
105     @selector("charValue") byte charValue();
106     @selector("doubleValue") double doubleValue();
107     @selector("floatValue") float floatValue();
108     @selector("intValue") int intValue();
109     @selector("longLongValue") long longValue();
110     @selector("shortValue") short shortValue();
111     @selector("unsignedCharValue") ubyte ubyteValue();
112     @selector("unsignedIntValue") uint uintValue();
113     @selector("unsignedLongLongValue") ulong ulongValue();
114     @selector("unsignedShortValue") ushort ushortValue();
115 }
116 struct NSNumberD(T) if(isValidObjectiveCNumber!T)
117 {
118     NSNumber num;
119     this(T t){num = NSNumber(t);}
120     alias num this;
121 }
122 
123 /** 
124  * Used for NSObjects. It will define a new
125  *  alloc, init and an opCall for that.
126  */
127 mixin template ObjectiveCOpCall()
128 {
129     extern(Objective-C)
130     {
131         override static typeof(this) alloc() @selector("alloc");
132         override typeof(this) initialize() @selector("init");
133     }
134     extern(D) final static typeof(this) opCall()
135     {
136         return alloc.initialize;
137     }
138 }
139 
140 extern(C) void NSLog(NSString str, ...);
141 
142 extern class NSString
143 {
144     static NSString alloc() @selector("alloc");
145     NSString initWithUTF8String(in char* str) @selector("initWithUTF8String:");
146 
147     @selector("stringWithCString:encoding:")
148     static NSString stringWithCString(const(char)* stringWithCString, size_t encoding);
149 
150     ///Returns a string created by copying the data from a given C array of UTF8-encoded bytes.
151     @selector("stringWithUTF8String:")
152     static NSString stringWithUTF8String(const(char)* nullTerminatedCString);
153 
154     ///A null-terminated UTF8 representation of the string.
155     @selector("UTF8String")
156     immutable(char)* UTF8String() @nogc const;
157 
158 
159     static size_t defaultCStringEncoding();
160     void release() @selector("release");
161 
162     extern(D) final string toString() @nogc const
163     {
164         immutable(char)* ret = UTF8String();
165         size_t i = 0; while(ret[i++] != '\0'){}
166         if(i > 0) return ret[0..i-1];
167         return null;
168     }
169 }
170 
171 private extern(C) void* _D4objc7runtime7NSArray7__ClassZ = null;
172 extern class NSArray : NSObject
173 {
174     NSArray init() @selector("init");
175     ///Creates and returns an empty array.
176     @selector("array")
177     static NSArray array();
178 
179     ///Creates and returns an array containing the objects in another given array.
180     @selector("arrayWithArray:")
181     static NSArray array(NSArray array);
182 
183     ///Creates and returns an array containing a given object.
184     @selector("arrayWithObject:")
185     static NSArray array(NSObject object);  
186 
187     ///Creates and returns an array containing the objects in the argument list.
188     @selector("arrayWithObjects:")
189     static NSArray array(NSObject objects, ...);
190 
191     ///Creates and returns an array that includes a given number of objects from a given C array.
192     @selector("arrayWithObjects:count:")
193     static NSArray array(NSObject* objects, NSUInteger count); 
194 
195     ///The number of objects in the array.
196     @selector("count")
197     NSUInteger count();
198     alias length = count;
199 
200     ///Returns the object located at the specified index.
201     @selector("objectAtIndex:")
202     NSObject objectAtIndex(NSUInteger index);
203 }
204 
205 alias NSArray_(T) = NSArray;
206 
207 struct NSArrayD(T)
208 {
209     NSArray arr = void;
210     alias arr this;
211 
212     auto opAssign(NSArray arr)
213     {
214         this.arr = arr;
215         return this;
216     }
217 
218     extern(D) pragma(inline, true) T opIndex(size_t index)
219     {
220         return cast(T)cast(void*)arr.objectAtIndex(index);
221     }
222     extern(D) final int opApply(scope int delegate(T) dg)
223     {
224         int result = 0;
225         NSUInteger l = arr.count;
226         for(int i = 0; i < l; i++)
227         {
228             T item = opIndex(i);
229             result = dg(item);
230             if (result)
231                 break;
232         }
233         return result;
234     }
235 }
236 
237 extern class NSDictionary : NSObject
238 {
239     ///Creates an empty dictionary.
240     @selector("dictionary")
241     static NSDictionary dictionary();
242 
243     ///The number of entries in the dictionary.
244     @selector("count")
245     NSUInteger count();
246 
247     ///A new array containing the dictionary’s keys, or an empty array if the dictionary has no entries.
248     @selector("allKeys")
249     NSArray allKeys();
250 
251     ///A new array containing the dictionary’s values, or an empty array if the dictionary has no entries.
252     @selector("allValues")
253     NSArray allValues();
254 
255     ///Returns the value associated with a given key.
256     @selector("objectForKey:")
257     NSObject objectForKey(NSObject);
258 
259     ///Returns the value associated with a given key.
260     @selector("valueForKey:")
261     NSObject valueForKey(NSString);
262 }
263 
264 
265 private void* _D4objc7runtime19NSMutableDictionary7__ClassZ = null;
266 ///A dynamic collection of objects associated with unique keys.
267 extern class NSMutableDictionary : NSDictionary
268 {
269     @selector("dictionary")
270     override static NSMutableDictionary dictionary();
271 
272     ///Creates and returns a mutable dictionary, initially giving it enough allocated memory to hold a given number of entries.
273     @selector("dictionaryWithCapacity:")
274     static NSMutableDictionary dictionaryWithCapacity(NSUInteger);
275 
276     ///Adds a given key-value pair to the dictionary.
277     @selector("setObject:forKey:")
278     void setObject(NSObject, NSObject);
279 
280     ///Adds a given key-value pair to the dictionary.
281     @selector("setValue:forKey:")
282     void setValue(NSObject, NSString);
283 }
284 
285 struct NSMutableDictionaryD(Key, Value)
286 {
287     static if(isValidObjectiveCNumber!Value)
288         alias RealValue = NSNumber;
289     else static if(is(Value == string))
290         alias RealValue = NSString;
291     else
292     {
293         static assert(is(Value : NSObject), "Unknown object of type ", Value, " receive");
294         alias RealValue = Value;
295     }
296 
297     NSMutableDictionary dictionary;
298     this(NSMutableDictionary d){dictionary = d;}
299     this(scope Value[Key] kv)
300     {
301         dictionary = NSMutableDictionary.dictionaryWithCapacity(32);
302         foreach(key, value; kv)
303             opIndexAssign(value, key);
304     }
305 
306     void opIndexAssign(Value v, Key k)
307     {
308         static if(is(Key == string) || is(Key == NSString))
309             dictionary.setValue(v.ns, k.ns);
310         else
311             dictionary.setObject(v.ns, k.ns);
312     }
313 
314     RealValue opIndex(Key k)
315     {
316         static if(is(Key == string) || is(Key == NSString))
317             return cast(RealValue)cast(void*)dictionary.valueForKey(k.ns);
318         else
319             return cast(RealValue)cast(void*)dictionary.objectForKey(k.ns);
320     }
321 
322     alias dictionary this;
323 }
324 
325 alias NSErrorDomain = NSString;
326 
327 extern class NSError
328 {
329     ///The error code
330     @selector("code")
331     NSInteger code();
332 
333     ///A string containing the error domain.
334     @selector("domain")
335     NSErrorDomain domain();
336 
337 
338     ///A string containing the localized description of the error.
339     @selector("localizedDescription")
340     NSString localizedDescription();
341 
342     ///An array containing the localized titles of buttons appropriate for displaying in an alert panel.
343     @selector("localizedRecoveryOptions")
344     NSArray_!NSString _localizedRecoveryOptions();
345 
346     extern(D) final NSArrayD!NSString localizedRecoveryOptions()
347     {
348         return NSArrayD!NSString(_localizedRecoveryOptions);
349     }
350 
351     ///A string containing the localized recovery suggestion for the error.
352     @selector("localizedRecoverySuggestion")
353     NSString localizedRecoverySuggestion();
354 
355     ///A string containing the localized explanation of the reason for the error.
356     @selector("localizedFailureReason")
357     NSString localizedFailureReason();
358 
359 
360     extern(D) final void print()
361     {
362         NSLog("Objective-C Error: %@".ns, this);
363     }
364 }
365 struct NSRange
366 {
367     NSUInteger length;
368     NSUInteger location;
369 }
370 extern class NSData : NSObject{}