1#include "pyobjc.h"
2
3@implementation OC_PythonNumber
4
5+ (instancetype)numberWithPythonObject:(PyObject*)v
6{
7	OC_PythonNumber* res;
8
9	res = [[OC_PythonNumber alloc] initWithPythonObject:v];
10	[res autorelease];
11	return res;
12}
13
14- (id)initWithPythonObject:(PyObject*)v
15{
16	self = [super init];
17	if (unlikely(self == nil)) return nil;
18
19	Py_INCREF(v);
20	Py_XDECREF(value);
21	value = v;
22	return self;
23}
24
25-(PyObject*)__pyobjc_PythonObject__
26{
27	Py_INCREF(value);
28	return value;
29}
30
31-(PyObject*)__pyobjc_PythonTransient__:(int*)cookie
32{
33	*cookie = 0;
34	Py_INCREF(value);
35	return value;
36}
37
38-(BOOL)supportsWeakPointers { return YES; }
39
40-(oneway void)release
41{
42	/* See comment in OC_PythonUnicode */
43	PyObjC_BEGIN_WITH_GIL
44		[super release];
45	PyObjC_END_WITH_GIL
46}
47
48-(void)dealloc
49{
50	PyObjC_BEGIN_WITH_GIL
51		PyObjC_UnregisterObjCProxy(value, self);
52		Py_XDECREF(value);
53
54	PyObjC_END_WITH_GIL
55
56	[super dealloc];
57}
58
59-(const char*)objCType
60{
61	PyObjC_BEGIN_WITH_GIL
62		if (PyBool_Check(value)) {
63			PyObjC_GIL_RETURN(@encode(BOOL));
64		} else if (PyFloat_Check(value)) {
65			PyObjC_GIL_RETURN(@encode(double));
66#if PY_MAJOR_VERSION == 2
67		} else if (PyInt_Check(value)) {
68			PyObjC_GIL_RETURN(@encode(long));
69#endif
70		} else if (PyLong_Check(value)) {
71			PyObjC_GIL_RETURN(@encode(long long));
72		} 
73	PyObjC_END_WITH_GIL
74	[NSException raise:NSInvalidArgumentException 
75		    format:@"Cannot determine objective-C type of this number"];
76	return @encode(char);
77}
78
79-(void)getValue:(void*)buffer
80{
81	const char* encoded = [self objCType];
82	int r;
83	PyObjC_BEGIN_WITH_GIL
84		r = depythonify_c_value(encoded, value, buffer);
85		if (r == -1) {
86			PyObjC_GIL_FORWARD_EXC();
87		}
88	PyObjC_END_WITH_GIL
89}
90
91/* TODO:
92-(BOOL)isEqualToValue:(NSValue*)other
93  // convert other to Python, then use python's comparison operators to
94  // check for equality.
95}
96*/
97
98
99-(BOOL)boolValue
100{
101	return (BOOL)PyObject_IsTrue(value);
102}
103
104-(char)charValue
105{
106	return (char)[self longLongValue];
107}
108
109-(NSDecimal)decimalValue
110{
111	NSDecimal result;
112	NSDecimalNumber* num;
113
114	unsigned long long mantissa = 0;
115	unsigned short exponent = 0;
116	BOOL negative = NO;
117
118	PyObjC_BEGIN_WITH_GIL
119#if PY_MAJOR_VERSION == 2
120		if (PyInt_Check(value)) {
121			long lng = PyInt_AsLong(value);
122			if (lng < 0) {
123				mantissa = -lng;
124				exponent = 0;
125				negative = YES;
126			} else {
127				mantissa = lng;
128				exponent = 0;
129				negative = NO;
130			}
131
132		} else 
133#endif
134		if (PyLong_Check(value)) {
135			mantissa = PyLong_AsUnsignedLongLong(value);
136			if (PyErr_Occurred()) {
137				long long lng;
138				PyErr_Clear();
139				lng = PyLong_AsLongLong(value);
140				if (PyErr_Occurred()) {
141					PyObjC_GIL_FORWARD_EXC();
142				}
143
144				if (lng < 0) {
145					mantissa = -lng;
146					exponent = 0;
147					negative = YES;
148				} else {
149					mantissa = lng;
150					exponent = 0;
151					negative = NO;
152				}
153			} else {
154				exponent = 0;
155				negative = NO;
156			}
157
158		} else if (PyFloat_Check(value)) {
159			PyObject* strVal = PyObject_Repr(value);
160			PyObject* uniVal = NULL;
161
162			if (strVal == NULL) {
163				PyObjC_GIL_FORWARD_EXC();
164			}
165
166			uniVal = PyUnicode_FromEncodedObject(strVal, "ascii", "strict");
167			Py_DECREF(strVal);
168			if (uniVal == NULL) {
169				PyObjC_GIL_FORWARD_EXC();
170			}
171
172			NSString* stringVal = PyObjC_PythonToId(uniVal);
173			Py_DECREF(uniVal);
174			
175			num = [[NSDecimalNumber alloc] initWithString:stringVal];
176			result = [num decimalValue];
177			[num release];
178			PyObjC_GIL_RETURN(result);
179
180		} else {
181			PyErr_Format(PyExc_TypeError, "cannot convert object of %s to NSDecimal",
182					Py_TYPE(value)->tp_name);
183			PyObjC_GIL_FORWARD_EXC();
184		}
185
186	PyObjC_END_WITH_GIL
187
188
189
190	num = [[NSDecimalNumber alloc] 
191		initWithMantissa:mantissa
192			exponent:exponent
193		      isNegative:negative];
194	result = [num decimalValue];
195	[num release];
196	return result;
197}
198
199-(double)doubleValue
200{
201	PyObjC_BEGIN_WITH_GIL
202		if (PyFloat_Check(value)) {
203			PyObjC_GIL_RETURN(PyFloat_AsDouble(value));
204		} 
205	PyObjC_END_WITH_GIL
206	return (double)[self longLongValue];
207}
208
209-(float)floatValue
210{
211	return (float)[self doubleValue];
212}
213
214-(NSInteger)integerValue
215{
216	return (NSInteger)[self longLongValue];
217}
218
219-(int)intValue
220{
221	return (int)[self longLongValue];
222}
223
224
225-(long)longValue
226{
227	return (long)[self longLongValue];
228}
229
230-(short)shortValue
231{
232	return (short)[self longLongValue];
233}
234
235
236-(unsigned char)unsignedCharValue
237{
238	return (unsigned char)[self unsignedLongLongValue];
239}
240-(NSUInteger)unsignedIntegerValue
241{
242	return (NSUInteger)[self unsignedLongLongValue];
243}
244-(unsigned int)unsignedIntValue
245{
246	return (unsigned int)[self unsignedLongLongValue];
247}
248-(unsigned long)unsignedLongValue
249{
250	return (unsigned long)[self unsignedLongLongValue];
251}
252-(unsigned short)unsignedShortValue
253{
254	return (unsigned short)[self unsignedLongLongValue];
255}
256
257-(long long)longLongValue
258{
259	long long result;
260
261	PyObjC_BEGIN_WITH_GIL
262#if PY_MAJOR_VERSION == 2
263		if (PyInt_Check(value)) {
264			result =  PyInt_AsLong(value);
265			PyObjC_GIL_RETURN(result);
266		} else 
267#endif
268		if (PyFloat_Check(value)) {
269			result =  (long long)PyFloat_AsDouble(value);
270			PyObjC_GIL_RETURN(result);
271		} else if (PyLong_Check(value)) {
272			result =  PyLong_AsUnsignedLongLongMask(value);
273			PyObjC_GIL_RETURN(result);
274		}
275	PyObjC_END_WITH_GIL
276
277	[NSException raise:NSInvalidArgumentException 
278		    format:@"Cannot determine objective-C type of this number"];
279	return -1;
280}
281
282-(unsigned long long)unsignedLongLongValue
283{
284	unsigned long long result;
285
286	PyObjC_BEGIN_WITH_GIL
287		if (PyLong_Check(value)) {
288			result =  PyLong_AsUnsignedLongLongMask(value);
289			PyObjC_GIL_RETURN(result);
290#if PY_MAJOR_VERSION == 2
291		} else if (PyInt_Check(value)) {
292			result =  (unsigned long long)PyInt_AsLong(value);
293			PyObjC_GIL_RETURN(result);
294#endif
295		} else if (PyFloat_Check(value)) {
296			double temp = PyFloat_AsDouble(value);
297			if (temp < 0) {
298				/* Conversion of negative numbers to
299				 * unsigned long long is undefined behaviour,
300				 * the code below seems to get the behaviour
301				 * we'd like: casting to unsigned long long
302				 * behaves simular to casting a signed integer
303				 * to undefined.
304				 */
305				long long t = (long long)temp;
306				result = (unsigned long long)t;
307			} else {
308				result =  (unsigned long long)temp;
309			}
310			PyObjC_GIL_RETURN(result);
311		}
312	PyObjC_END_WITH_GIL
313
314	[NSException raise:NSInvalidArgumentException 
315		    format:@"Cannot determine objective-C type of this number"];
316	return -1;
317}
318
319-(NSString*)description
320{
321	return [self stringValue];
322}
323
324-(NSString*)descriptionWithLocale:(NSObject*)locale
325{
326	/* FIXME: use locale information to format */
327	 /* TODO: compare with regular NSNumber */
328	(void)locale;
329	return [self stringValue];
330}
331
332-(NSString*)stringValue
333{
334	PyObject* repr;
335	NSObject* result = nil;
336
337	PyObjC_BEGIN_WITH_GIL
338		repr = PyObject_Repr(value);
339		if (repr == NULL) {
340			PyObjC_GIL_FORWARD_EXC();
341		}
342
343#if PY_MAJOR_VERSION == 2
344		PyObject* uniVal = PyUnicode_FromEncodedObject(repr, "ascii", "strict");
345		Py_DECREF(repr);
346		if (PyErr_Occurred()) {
347			PyObjC_GIL_FORWARD_EXC();
348		}
349	
350		result = PyObjC_PythonToId(uniVal);
351		Py_DECREF(uniVal);
352		if (PyErr_Occurred()) {
353			PyObjC_GIL_FORWARD_EXC();
354		}
355#else
356		result = PyObjC_PythonToId(repr);
357		Py_DECREF(repr);
358		if (PyErr_Occurred()) {
359			PyObjC_GIL_FORWARD_EXC();
360		}
361#endif
362
363
364	PyObjC_END_WITH_GIL
365	return (NSString*)result;
366}
367
368/* NSCoding support */
369
370- (void)encodeWithCoder:(NSCoder*)coder
371{
372	int use_super = 0;
373
374	PyObjC_BEGIN_WITH_GIL
375		if (PyFloat_CheckExact(value)) {
376			/* Float is a C double and can be roundtripped using 
377			 * NSNumber.
378			 */
379			use_super = 1;
380
381#if PY_MAJOR_VERSION == 2
382		} else if (PyInt_CheckExact(value)) {
383			/* Int is a C double and can be roundtripped using 
384			 * NSNumber.
385			 */
386			use_super = 1;
387#endif
388		} else if (PyLong_CheckExact(value)) {
389			/* Long object that fits in a long long */
390			(void)PyLong_AsLongLong(value);
391			if (PyErr_Occurred()) {
392				PyErr_Clear();
393				use_super = 0;
394			} else {
395				use_super = 1;
396			}
397		}
398	PyObjC_END_WITH_GIL
399
400	if (use_super) {
401		[super encodeWithCoder:coder];
402	} else {
403		PyObjC_encodeWithCoder(value, coder);
404	}
405}
406
407
408/* 
409 * Helper method for initWithCoder, needed to deal with
410 * recursive objects (e.g. o.value = o)
411 */
412-(void)pyobjcSetValue:(NSObject*)other
413{
414	PyObjC_BEGIN_WITH_GIL
415		PyObject* v = PyObjC_IdToPython(other);
416		Py_XDECREF(value);
417		value = v;
418	PyObjC_END_WITH_GIL
419}
420
421- (id)initWithCoder:(NSCoder*)coder
422{
423	if (PyObjC_Decoder != NULL) {
424		PyObjC_BEGIN_WITH_GIL
425			PyObject* cdr = PyObjC_IdToPython(coder);
426			if (cdr == NULL) {
427				PyObjC_GIL_FORWARD_EXC();
428			}
429
430			PyObject* setValue;
431			PyObject* selfAsPython = PyObjCObject_New(self, 0, YES);
432			setValue = PyObject_GetAttrString(selfAsPython, "pyobjcSetValue_");
433
434			PyObject* v = PyObject_CallFunction(PyObjC_Decoder, "OO", cdr, setValue);
435			Py_DECREF(cdr);
436			Py_DECREF(setValue);
437			Py_DECREF(selfAsPython);
438
439			if (v == NULL) {
440				PyObjC_GIL_FORWARD_EXC();
441			}
442
443			Py_XDECREF(value);
444			value = v;
445
446			NSObject* proxy = PyObjC_FindObjCProxy(value);
447			if (proxy == NULL) {
448				PyObjC_RegisterObjCProxy(value, self);
449			} else {
450				[self release];
451				[proxy retain];
452				self = (OC_PythonNumber*)proxy;
453			}
454
455
456		PyObjC_END_WITH_GIL
457
458		return self;
459
460	} else {
461		[NSException raise:NSInvalidArgumentException
462				format:@"decoding Python objects is not supported"];
463		return nil;
464
465	}
466}
467
468- (NSComparisonResult)compare:(NSNumber *)aNumber
469{
470	/* Rely on -[NSNumber compare:] when the other value
471	 * is a number and we're not a python int that doesn't
472	 * fit into a 'long long'.
473	 *
474	 * In all other cases use Python's comparison semantics.
475	 */
476	if ([aNumber isKindOfClass:[NSNumber class]] && ![aNumber isMemberOfClass: [OC_PythonNumber class]]) {
477		if (PyLong_Check(value)) {
478			PY_LONG_LONG r;
479			r = PyLong_AsLongLong(value);
480			if (r == -1 && PyErr_Occurred()) {
481				PyErr_Print();
482				PyErr_Clear();
483			} else {
484			     return [super compare:aNumber];
485			}
486		} else {
487			return [super compare:aNumber];
488		}
489	} 
490
491	PyObjC_BEGIN_WITH_GIL
492		PyObject* other = PyObjC_IdToPython(aNumber);
493		if (other == NULL) {
494			PyObjC_GIL_FORWARD_EXC();
495		}
496
497		int r;
498		int ok = PyObject_Cmp(value, other, &r);
499		Py_DECREF(other);
500		if (ok == -1) {
501			PyObjC_GIL_FORWARD_EXC();
502		}
503
504		if (r < 0) {
505			PyObjC_GIL_RETURN(NSOrderedAscending);
506		} else if (r > 0) {
507			PyObjC_GIL_RETURN(NSOrderedDescending);
508		} else {
509			PyObjC_GIL_RETURN(NSOrderedSame);
510		}
511
512
513	PyObjC_END_WITH_GIL
514}
515
516
517#define COMPARE_METHOD(NAME, OPERATOR) \
518	-(BOOL)NAME:(NSObject*)aNumber \
519{ \
520	PyObjC_BEGIN_WITH_GIL \
521		PyObject* other = PyObjC_IdToPython(aNumber); \
522		if (other == NULL) { \
523			PyObjC_GIL_FORWARD_EXC(); \
524		} \
525 \
526		int r = PyObject_RichCompareBool(value, other, OPERATOR); \
527		Py_DECREF(other); \
528		if (r == -1) { \
529			PyObjC_GIL_FORWARD_EXC(); \
530		} \
531 \
532		if (r) { \
533			PyObjC_GIL_RETURN(YES); \
534		} else { \
535			PyObjC_GIL_RETURN(NO); \
536		} \
537 \
538	PyObjC_END_WITH_GIL \
539}
540
541COMPARE_METHOD(isEqualTo, Py_EQ)
542COMPARE_METHOD(isNotEqualTo, Py_NE)
543COMPARE_METHOD(isGreaterThan, Py_GT)
544COMPARE_METHOD(isGreaterThanOrEqualTo, Py_GE)
545COMPARE_METHOD(isLessThan, Py_LT)
546COMPARE_METHOD(isLessThanOrEqualTo, Py_LE)
547
548
549-(BOOL)isEqualToNumber:(NSNumber*)aNumber
550{
551	return [self isEqualTo:aNumber];
552}
553
554
555
556
557#if 1
558
559-(NSObject*)replacementObjectForArchiver:(NSArchiver*)archiver
560{
561	(void)archiver;
562	return (NSObject*)self;
563}
564
565-(NSObject*)replacementObjectForKeyedArchiver:(NSKeyedArchiver*)archiver
566{
567	(void)archiver;
568	return (NSObject*)self;
569}
570
571-(NSObject*)replacementObjectForCoder:(NSCoder*)archiver
572{
573	(void)archiver;
574	return (NSObject*)self;
575}
576
577-(NSObject*)replacementObjectForPortCoder:(NSPortCoder*)archiver
578{
579	(void)archiver;
580	return (NSObject*)self;
581}
582
583-(Class)classForArchiver
584{
585	PyObjC_BEGIN_WITH_GIL
586		if (PyFloat_CheckExact(value)) {
587			/* Float is a C double and can be roundtripped using 
588			 * NSNumber.
589			 */
590			PyObjC_GIL_RETURN([NSNumber class]);
591
592#if PY_MAJOR_VERSION == 2
593		} else if (PyInt_CheckExact(value)) {
594			/* Int is a C double and can be roundtripped using 
595			 * NSNumber.
596			 */
597			PyObjC_GIL_RETURN([NSNumber class]);
598#endif
599		} else if (PyLong_CheckExact(value)) {
600			/* Long object that fits in a long long */
601			(void)PyLong_AsLongLong(value);
602			if (PyErr_Occurred()) {
603				PyErr_Clear();
604				PyObjC_GIL_RETURN([OC_PythonNumber class]);
605			} else {
606				PyObjC_GIL_RETURN([NSNumber class]);
607			}
608
609		} else {
610			PyObjC_GIL_RETURN([OC_PythonNumber class]);
611		}
612	PyObjC_END_WITH_GIL
613}
614
615-(Class)classForKeyedArchiver
616{
617	return [self classForArchiver];
618}
619
620+(Class)classForUnarchiver
621{
622	return [OC_PythonNumber class];
623}
624
625+(Class)classForKeyedUnarchiver
626{
627	return [OC_PythonNumber class];
628}
629
630-(Class)classForCoder
631{
632	return [self classForArchiver];
633}
634
635-(Class)classForPortCoder
636{
637	return [self classForArchiver];
638}
639
640-(id)copy
641{
642	return [self copyWithZone:0];
643}
644
645-(id)copyWithZone:(NSZone*)zone
646{
647	(void)zone;
648	[self retain];
649	return self;
650}
651
652
653#endif
654@end
655