1 /**
2 Dynamic bindings to the Foundation framework.
3 
4 Copyright: Guillaume Piolat 2016.
5 License:   $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
6 */
7 module bindbc.cocoa.foundation;
8 
9 import std.string;
10 import std.utf;
11 
12 import dplug.core.nogc;
13 
14 import bindbc.cocoa.runtime;
15 
16 // NSZone
17 
18 extern (C) nothrow @nogc
19 {
20     alias void* function(NSUInteger bytes) pfNSAllocateMemoryPages;
21     alias void function (void* ptr, NSUInteger bytes) pfNSDeallocateMemoryPages;
22     alias void function(id format, ...) pfNSLog;
23     
24     alias Class function(id aClassName) pfNSClassFromString;
25     alias SEL function(id aString) pfNSSelectorFromString;
26     alias id function(Class aClass) pfNSStringFromClass;
27     alias id function(SEL aSelector) pfNSStringFromSelector;
28     alias id function(Protocol* aProtocol) pfNSStringFromProtocol;
29     alias Protocol* function(id aString) pfNSProtocolFromString;
30 }
31 
32 __gshared
33 {
34     pfNSDeallocateMemoryPages NSDeallocateMemoryPages;
35     pfNSAllocateMemoryPages NSAllocateMemoryPages;
36     pfNSLog NSLog;
37 
38     pfNSClassFromString NSClassFromString;
39     pfNSSelectorFromString NSSelectorFromString;
40     pfNSStringFromClass NSStringFromClass;
41     pfNSStringFromSelector NSStringFromSelector;
42     pfNSStringFromProtocol NSStringFromProtocol;
43     pfNSProtocolFromString NSProtocolFromString;
44 }
45 
46 __gshared
47 {
48     //NSString NSDefaultRunLoopMode;
49     NSString NSRunLoopCommonModes;
50 }
51 
52 alias NSTimeInterval = double;
53 
54 
55 // Mixin'd by all Cocoa objects
56 mixin template NSObjectTemplate(T, string className)
57 {
58 nothrow @nogc:
59 
60     // create from an id
61     this (id id_)
62     {
63         this._id = id_;
64     }
65 
66     /// Allocates, but do not init
67     static T alloc()
68     {
69         alias fun_t = extern(C) id function (id obj, SEL sel) nothrow @nogc;
70         return T( (cast(fun_t)objc_msgSend)(getClassID(), sel!"alloc") );
71     }
72 
73     static Class getClass()
74     {
75         return cast(Class)( lazyClass!className() );
76     }
77 
78     static id getClassID()
79     {
80         return lazyClass!className();
81     }
82 }
83 
84 struct NSObject
85 {
86 nothrow @nogc:
87 
88     // The only field available in all NSObject hierarchy
89     // That makes all these destructs idempotent with an id,
90     // and the size of a pointer.
91     id _id = null;
92 
93     // Subtype id
94     bool opCast()
95     {
96         return _id != null;
97     }
98 
99     mixin NSObjectTemplate!(NSObject, "NSObject");
100 
101     ~this()
102     {
103     }
104 
105     NSObject init_()
106     {
107         alias fun_t = extern(C) id function (id, const(SEL)) nothrow @nogc;
108         id result = (cast(fun_t)objc_msgSend)(_id, sel!"init");
109         return NSObject(result);
110     }
111 
112     void retain()
113     {
114         alias fun_t = extern(C) void function (id, const(SEL)) nothrow @nogc;
115         (cast(fun_t)objc_msgSend)(_id, sel!"retain");
116     }
117 
118     void release()
119     {
120         alias fun_t = extern(C) void function (id, const(SEL)) nothrow @nogc;
121         (cast(fun_t)objc_msgSend)(_id, sel!"release");
122     }
123 }
124 
125 struct NSData
126 {
127 nothrow @nogc:
128 
129     NSObject parent;
130     alias parent this;
131 
132     mixin NSObjectTemplate!(NSData, "NSData");
133 
134     static NSData data()
135     {
136         alias fun_t = extern(C) id function (id obj, const(SEL) sel) nothrow @nogc;
137         id result = (cast(fun_t)objc_msgSend)(getClassID(), sel!"data");
138         return NSData(result);
139     }
140 
141     static NSData dataWithBytesNoCopy(void* bytes, NSUInteger length, bool freeWhenDone)
142     {
143         alias fun_t = extern(C) id function(id, const(SEL), void*, NSUInteger, BOOL) nothrow @nogc;
144         id result = (cast(fun_t)objc_msgSend)(getClassID(), sel!"dataWithBytesNoCopy:length:freeWhenDone:",
145             bytes, length, freeWhenDone ? YES : NO);
146         return NSData(result);
147     }
148 }
149 
150 struct NSString
151 {
152 nothrow @nogc:
153 
154     NSObject parent;
155     alias parent this;
156 
157     mixin NSObjectTemplate!(NSString, "NSString");
158 
159     static NSString stringWith (wstring str) nothrow @nogc
160     {
161         alias fun_t = extern(C) id function(id, SEL, const(wchar)*, NSUInteger) nothrow @nogc;
162         id result = (cast(fun_t)objc_msgSend)(getClassID(), sel!"stringWithCharacters:length:",
163                                  CString16(str).storage, cast(NSUInteger)(str.length));
164         return NSString(result);
165     }
166 
167     size_t length ()
168     {
169         alias fun_t = extern(C) NSUInteger function(id, SEL) nothrow @nogc;
170         return cast(size_t)( (cast(fun_t)objc_msgSend)(_id, sel!"length") );
171     }
172 
173     char* UTF8String ()
174     {
175         alias fun_t = extern(C) char* function(id, SEL) nothrow @nogc;
176         return (cast(fun_t)objc_msgSend)(_id, sel!"UTF8String");
177     }
178 
179     void getCharacters (wchar* buffer, NSRange range)
180     {
181         alias fun_t = extern(C) void function(id, SEL, wchar*, NSRange) nothrow @nogc;
182         (cast(fun_t)objc_msgSend)(_id, sel!"getCharacters:range:", buffer, range);
183     }
184 
185     NSString stringWithCharacters (wchar* chars, size_t length)
186     {
187         alias fun_t = extern(C) id function(id, SEL, wchar*, NSUInteger) nothrow @nogc;
188         id result = (cast(fun_t)objc_msgSend)(_id, sel!"stringWithCharacters:length:", chars, cast(NSUInteger)length);
189         return NSString(result);
190     }
191 
192     NSRange rangeOfString (NSString aString)
193     {
194         alias fun_t = extern(C) NSRange function(id, SEL, id) nothrow @nogc;
195         return (cast(fun_t)objc_msgSend)(_id, sel!"rangeOfString", aString._id);
196     }
197 
198     NSString stringByAppendingString (NSString aString)
199     {
200         alias fun_t = extern(C) id function(id, SEL, id) nothrow @nogc;
201         id result = (cast(fun_t)objc_msgSend)(_id, sel!"stringByAppendingString:", aString._id);
202         return NSString(result);
203     }
204 
205     /// Returns: The character at a given UTF-16 code unit index.
206     wchar characterAtIndex(int index)
207     {
208         alias fun_t = extern(C) wchar function(id, SEL, NSUInteger) nothrow @nogc;
209         return (cast(fun_t)objc_msgSend)(_id, sel!"characterAtIndex:", cast(NSUInteger)index);
210     }
211 }
212 
213 struct NSURL
214 {
215 nothrow @nogc:
216     NSObject parent;
217     alias parent this;
218 
219     mixin NSObjectTemplate!(NSURL, "NSURL");
220 
221     static NSURL URLWithString(NSString str)
222     {
223         alias fun_t = extern(C) id function(id, SEL, id) nothrow @nogc;
224         id result = (cast(fun_t)objc_msgSend)(getClassID(), sel!"URLWithString:", str._id);
225         return NSURL(result);
226     }
227 
228 }
229 
230 struct NSEnumerator
231 {
232 nothrow @nogc:
233     NSObject parent;
234     alias parent this;
235 
236     mixin NSObjectTemplate!(NSEnumerator, "NSEnumerator");
237 
238     id nextObject ()
239     {
240         alias fun_t = extern(C) id function(id, SEL) nothrow @nogc;
241         return (cast(fun_t)objc_msgSend)(_id, sel!"nextObject");
242     }
243 }
244 
245 struct NSArray
246 {
247 nothrow @nogc:
248 
249     NSObject parent;
250     alias parent this;
251 
252     mixin NSObjectTemplate!(NSArray, "NSArray");
253 
254     NSEnumerator objectEnumerator ()
255     {
256         alias fun_t = extern(C) id function(id, SEL) nothrow @nogc;
257         id result = (cast(fun_t)objc_msgSend)(_id, sel!"objectEnumerator");
258         return NSEnumerator(result);
259     }
260 }
261 
262 
263 struct NSProcessInfo
264 {
265 nothrow @nogc:
266 
267     NSObject parent;
268     alias parent this;
269 
270     mixin NSObjectTemplate!(NSProcessInfo, "NSProcessInfo");
271 
272     static NSProcessInfo processInfo ()
273     {
274         alias fun_t = extern(C) id function(id, SEL) nothrow @nogc;
275         id result = (cast(fun_t)objc_msgSend)(lazyClass!"NSProcessInfo", sel!"processInfo");
276         return NSProcessInfo(result);
277     }
278 
279     NSString processName ()
280     {
281         alias fun_t = extern(C) id function(id, SEL) nothrow @nogc;
282         id result = (cast(fun_t)objc_msgSend)(_id, sel!"processName");
283         return NSString(result);
284     }
285 }
286 
287 struct NSNotification
288 {
289 nothrow @nogc:
290     NSObject parent;
291     alias parent this;
292 
293     mixin NSObjectTemplate!(NSNotification, "NSNotification");
294 }
295 
296 struct NSDictionary
297 {
298 nothrow @nogc:
299     NSObject parent;
300     alias parent this;
301 
302     mixin NSObjectTemplate!(NSDictionary, "NSDictionary");
303 
304     static NSDictionary dictionaryWithObjectsAndKeys(Args...)(id firstObject, Args args)
305     {
306         alias fun_t = extern(C) id function(id, SEL, id, ...) nothrow @nogc;
307         auto result = (cast(fun_t) objc_msgSend)(getClassID(), sel!"dictionaryWithObjectsAndKeys:", firstObject, args);
308 
309         return NSDictionary(result);
310     }
311 
312     id objectForKey(id key)
313     {
314         alias fun_t = extern(C) id function(id, SEL, id) nothrow @nogc;
315         id result = (cast(fun_t)objc_msgSend)(_id, sel!"objectForKey:", key);
316         return result;
317     }
318 }
319 
320 struct NSAutoreleasePool
321 {
322 nothrow @nogc:
323     NSObject parent;
324     alias parent this;
325 
326     mixin NSObjectTemplate!(NSAutoreleasePool, "NSAutoreleasePool");
327 }
328 
329 enum : int
330 {
331     NSFileErrorMaximum = 1023,
332     NSFileErrorMinimum = 0,
333     NSFileLockingError = 255,
334     NSFileNoSuchFileError = 4,
335     NSFileReadCorruptFileError = 259,
336     NSFileReadInapplicableStringEncodingError = 261,
337     NSFileReadInvalidFileNameError = 258,
338     NSFileReadNoPermissionError = 257,
339     NSFileReadNoSuchFileError = 260,
340     NSFileReadUnknownError = 256,
341     NSFileReadUnsupportedSchemeError = 262,
342     NSFileWriteInapplicableStringEncodingError = 517,
343     NSFileWriteInvalidFileNameError = 514,
344     NSFileWriteNoPermissionError = 513,
345     NSFileWriteOutOfSpaceError = 640,
346     NSFileWriteUnknownError = 512,
347     NSFileWriteUnsupportedSchemeError = 518,
348     NSFormattingError = 2048,
349     NSFormattingErrorMaximum = 2559,
350     NSFormattingErrorMinimum = 2048,
351     NSKeyValueValidationError = 1024,
352     NSUserCancelledError = 3072,
353     NSValidationErrorMaximum = 2047,
354     NSValidationErrorMinimum = 1024,
355 
356     NSExecutableArchitectureMismatchError = 3585,
357     NSExecutableErrorMaximum = 3839,
358     NSExecutableErrorMinimum = 3584,
359     NSExecutableLinkError = 3588,
360     NSExecutableLoadError = 3587,
361     NSExecutableNotLoadableError = 3584,
362     NSExecutableRuntimeMismatchError = 3586,
363     NSFileReadTooLargeError = 263,
364     NSFileReadUnknownStringEncodingError = 264,
365 
366     GSFoundationPlaceHolderError = 9999
367 }
368 
369 struct NSError
370 {
371 nothrow @nogc:
372     NSObject parent;
373     alias parent this;
374 
375     mixin NSObjectTemplate!(NSError, "NSError");
376 
377     NSString localizedDescription()
378     {
379         alias fun_t = extern(C) id function(id, SEL) nothrow @nogc;
380         id res = (cast(fun_t)objc_msgSend)(_id, sel!"localizedDescription");
381         return NSString(res);
382     }
383 }
384 
385 struct NSBundle
386 {
387 nothrow @nogc:
388     NSObject parent;
389     alias parent this;
390 
391     mixin NSObjectTemplate!(NSBundle, "NSBundle");
392 
393     void initWithPath(NSString path)
394     {
395         alias fun_t = extern(C) void function(id, SEL, id) nothrow @nogc;
396         (cast(fun_t)objc_msgSend)(_id, sel!"initWithPath:", path._id);
397     }
398 
399     bool load()
400     {
401         alias fun_t = extern(C) BOOL function(id, SEL) nothrow @nogc;
402         return (cast(fun_t)objc_msgSend)(_id, sel!"load") != NO;
403     }
404 
405     bool unload()
406     {
407         alias fun_t = extern(C) BOOL function(id, SEL) nothrow @nogc;
408         return (cast(fun_t)objc_msgSend)(_id, sel!"unload") != NO;
409     }
410 
411     bool loadAndReturnError(NSError error)
412     {
413         alias fun_t = extern(C) BOOL function(id, SEL, id) nothrow @nogc;
414         return (cast(fun_t)objc_msgSend)(_id, sel!"loadAndReturnError:", error._id) != NO;
415     }
416 }
417 
418 struct NSTimer
419 {
420 nothrow @nogc:
421     NSObject parent;
422     alias parent this;
423 
424     mixin NSObjectTemplate!(NSTimer, "NSTimer");
425 
426     static NSTimer timerWithTimeInterval(double seconds, NSObject target, SEL selector, void* userInfo, bool repeats)
427     {
428         alias fun_t = extern(C) id function(id, SEL, double, id, SEL, id, BOOL) nothrow @nogc;
429         id result = (cast(fun_t)objc_msgSend)(getClassID(), sel!"timerWithTimeInterval:target:selector:userInfo:repeats:",
430                     seconds, target._id, selector, cast(id)userInfo, repeats ? YES : NO);
431         return NSTimer(result);
432     }
433 
434     void invalidate()
435     {
436         alias fun_t = extern(C) void function(id, SEL) nothrow @nogc;
437         (cast(fun_t)objc_msgSend)(_id, sel!"invalidate");
438     }
439 }
440 
441 struct NSRunLoop
442 {
443 nothrow @nogc:
444     NSObject parent;
445     alias parent this;
446 
447     mixin NSObjectTemplate!(NSRunLoop, "NSRunLoop");
448 
449     static NSRunLoop currentRunLoop()
450     {
451         alias fun_t = extern(C) id function(id, SEL) nothrow @nogc;
452         id result = (cast(fun_t)objc_msgSend)(getClassID(), sel!"currentRunLoop");
453         return NSRunLoop(result);
454     }
455 
456     static NSRunLoop mainRunLoop()
457     {
458         alias fun_t = extern(C) id function(id, SEL) nothrow @nogc;
459         id result = (cast(fun_t)objc_msgSend)(getClassID(), sel!"mainRunLoop");
460         return NSRunLoop(result);
461     }
462 
463     void runUntilDate(NSDate limitDate)
464     {
465         alias fun_t = extern(C) void function(id, SEL, id) nothrow @nogc;
466         (cast(fun_t)objc_msgSend)(_id, sel!"runUntilDate:", limitDate._id);
467     }
468 
469     void addTimer(NSTimer aTimer, NSString forMode)
470     {
471         alias fun_t = extern(C) void function(id, SEL, id, id) nothrow @nogc;
472         (cast(fun_t)objc_msgSend)(_id, sel!"addTimer:forMode:", aTimer._id, forMode._id);
473     }
474 }
475 
476 struct NSDate
477 {
478 nothrow @nogc:
479     NSObject parent;
480     alias parent this;
481 
482     mixin NSObjectTemplate!(NSDate, "NSDate");
483 
484     static NSDate date()
485     {
486         return NSDate(objc_msgSend(getClassID(), sel!"date"));
487     }
488 
489     static NSTimeInterval timeIntervalSinceReferenceDate()
490     {
491         alias fun_t = extern(C) NSTimeInterval function(id, SEL) nothrow @nogc;
492 
493         version(X86)
494             return (cast(fun_t)objc_msgSend_fpret)(getClassID(), sel!"timeIntervalSinceReferenceDate");
495         else version(X86_64)
496             return (cast(fun_t)objc_msgSend)(getClassID(), sel!"timeIntervalSinceReferenceDate");
497         else
498             return (cast(fun_t)objc_msgSend)(getClassID(), sel!"timeIntervalSinceReferenceDate");
499     }
500 
501     static NSDate dateWithTimeIntervalSinceNow(double secs)
502     {
503         alias fun_t = extern(C) id function(id, SEL, double) nothrow @nogc;
504         id res = (cast(fun_t)objc_msgSend)(getClassID(), sel!"dateWithTimeIntervalSinceNow:", secs);
505 
506         return NSDate(res);
507     }
508 
509     NSString description()
510     {
511         alias fun_t = extern(C) id function(id, SEL) nothrow @nogc;
512         id result = (cast(fun_t)objc_msgSend)(_id, sel!"description");
513 
514         return NSString(result);
515     }
516 
517     NSString descriptionWithLocale()
518     {
519         alias fun_t = extern(C) id function(id, SEL, void*) nothrow @nogc;
520         id result = (cast(fun_t)objc_msgSend)(_id, sel!"descriptionWithLocale:", null);
521         return NSString(result);
522     }
523 }
524 
525 struct NSNumber
526 {
527 nothrow @nogc:
528     NSObject parent;
529     alias parent this;
530 
531     mixin NSObjectTemplate!(NSNumber, "NSNumber");
532 
533     static NSNumber numberWithUnsignedInt(uint value)
534     {
535         alias fun_t = extern(C) id function(id, SEL, uint) nothrow @nogc;
536         id result = (cast(fun_t)objc_msgSend)(getClassID(), sel!"numberWithUnsignedInt:", value);
537 
538         return NSNumber(result);
539     }
540 }