1/* 2 * NOTE: the implementation uses PyDict_* APIs whenever possible and falls 3 * back to the generic PyObject_* APIs otherwise. We don't use the PyMapping_* 4 * APIs because those are incomplete(!). 5 */ 6#include "pyobjc.h" 7#import "OC_PythonDictionary.h" 8 9static PyObject* mapTypes = NULL; 10 11/* 12 * OC_PythonDictionaryEnumerator - Enumerator for Python dictionaries 13 * 14 * This class implements an NSEnumerator for proxied Python dictionaries. 15 */ 16@interface OC_PythonDictionaryEnumerator : NSEnumerator 17{ 18 OC_PythonDictionary* value; 19 BOOL valid; 20 Py_ssize_t pos; 21} 22+ (instancetype)enumeratorWithWrappedDictionary:(OC_PythonDictionary*)value; 23- (id)initWithWrappedDictionary:(OC_PythonDictionary*)value; 24-(void)dealloc; 25 26-(id)nextObject; 27 28@end /* interface OC_PythonDictionaryEnumerator */ 29 30 31 32@implementation OC_PythonDictionaryEnumerator 33 34+(instancetype)enumeratorWithWrappedDictionary:(OC_PythonDictionary*)v 35{ 36 return [[[self alloc] initWithWrappedDictionary:v] autorelease]; 37} 38 39-(id)initWithWrappedDictionary:(OC_PythonDictionary*)v 40{ 41 self = [super init]; 42 if (unlikely(self == nil)) return nil; 43 44 value = [v retain]; 45 valid = YES; 46 pos = 0; 47 return self; 48} 49 50-(void)dealloc 51{ 52 [value release]; 53 [super dealloc]; 54} 55 56-(id)nextObject 57{ 58 id key = nil; 59 60 if (valid) { 61 valid = [value wrappedKey:&key value:nil atPosition:&pos]; 62 } 63 return key; 64} 65 66@end // implementation OC_PythonDictionaryEnumerator 67 68 69@implementation OC_PythonDictionary 70 71+ (OC_PythonDictionary*)depythonifyObject:(PyObject*)object 72{ 73 Py_ssize_t i, len; 74 75 if (mapTypes == NULL) return NULL; 76 77 len = PyList_GET_SIZE(mapTypes); 78 79 for (i = 0; i < len; i++) { 80 PyObject* tp = PyList_GET_ITEM(mapTypes, i); 81 int r = PyObject_IsInstance(object, tp); 82 if (r == -1) { 83 return NULL; 84 } 85 86 if (!r) continue; 87 88 /* Instance of this type should be pythonifyed as a sequence */ 89 return [OC_PythonDictionary dictionaryWithPythonObject:object]; 90 } 91 92 return NULL; 93} 94 95+ (id)depythonifyTable 96{ 97 NSObject* result; 98 99 PyObjC_BEGIN_WITH_GIL 100 101 if (mapTypes == NULL) { 102 mapTypes = PyList_New(0); 103 if (mapTypes == NULL) { 104 PyObjC_GIL_FORWARD_EXC(); 105 } 106 } 107 result = PyObjC_PythonToId(mapTypes); 108 if (result == NULL) { 109 PyObjC_GIL_FORWARD_EXC(); 110 } 111 112 PyObjC_END_WITH_GIL 113 114 return result; 115} 116 117+(OC_PythonDictionary*)dictionaryWithPythonObject:(PyObject*)v 118{ 119 OC_PythonDictionary* res = 120 [[OC_PythonDictionary alloc] initWithPythonObject:v]; 121 [res autorelease]; 122 return res; 123} 124 125-(OC_PythonDictionary*)initWithPythonObject:(PyObject*)v 126{ 127 self = [super init]; 128 if (unlikely(self == nil)) return nil; 129 130 Py_INCREF(v); 131 Py_XDECREF(value); 132 value = v; 133 return self; 134} 135 136-(BOOL)supportsWeakPointers { return YES; } 137 138-(oneway void)release 139{ 140 /* See comment in OC_PythonUnicode */ 141 PyObjC_BEGIN_WITH_GIL 142 [super release]; 143 PyObjC_END_WITH_GIL 144} 145 146 147 148-(void)dealloc 149{ 150 PyObjC_BEGIN_WITH_GIL 151 PyObjC_UnregisterObjCProxy(value, self); 152 Py_XDECREF(value); 153 154 PyObjC_END_WITH_GIL 155 156 [super dealloc]; 157} 158 159-(PyObject*)__pyobjc_PythonObject__ 160{ 161 Py_INCREF(value); 162 return value; 163} 164-(PyObject*)__pyobjc_PythonTransient__:(int*)cookie 165{ 166 *cookie = 0; 167 Py_INCREF(value); 168 return value; 169} 170 171-(NSUInteger)count 172{ 173 Py_ssize_t result; 174 175 PyObjC_BEGIN_WITH_GIL 176 if (likely(PyDict_CheckExact(value))) { 177 result = PyDict_Size(value); 178 } else { 179 result = PyObject_Length(value); 180 } 181 182 PyObjC_END_WITH_GIL 183 184 if (sizeof(Py_ssize_t) > sizeof(NSUInteger)) { 185 if (result > (Py_ssize_t)NSUIntegerMax) { 186 return NSUIntegerMax; 187 } 188 } 189 return result; 190} 191 192-(int)depythonify:(PyObject*)v toId:(id*)datum 193{ 194 if (unlikely(depythonify_c_value(@encode(id), v, datum) == -1)) { 195 return -1; 196 } 197 if (unlikely(*datum == nil)) { 198 *datum = [NSNull null]; 199 } 200 return 0; 201} 202 203-(id)objectForKey:key 204{ 205 PyObject* v; 206 PyObject* k; 207 id result; 208 209 PyObjC_BEGIN_WITH_GIL 210 211 if (unlikely(key == [NSNull null])) { 212 Py_INCREF(Py_None); 213 k = Py_None; 214 } else { 215 k = PyObjC_IdToPython(key); 216 if (k == NULL) { 217 PyObjC_GIL_FORWARD_EXC(); 218 } 219 } 220 221 if (likely(PyDict_CheckExact(value))) { 222 v = PyDict_GetItem(value, k); 223 Py_XINCREF(v); 224 } else { 225 v = PyObject_GetItem(value, k); 226 } 227 Py_DECREF(k); 228 229 if (unlikely(v == NULL)) { 230 PyErr_Clear(); 231 PyObjC_GIL_RETURN(nil); 232 } 233 234 if (unlikely([self depythonify:v toId:&result] == -1)) { 235 Py_DECREF(v); 236 PyObjC_GIL_FORWARD_EXC(); 237 } 238 Py_DECREF(v); 239 240 PyObjC_END_WITH_GIL 241 242 return result; 243} 244 245 246-(void)setObject:val forKey:key 247{ 248 PyObject* v = NULL; 249 PyObject* k = NULL; 250 id null = [NSNull null]; 251 252 PyObjC_BEGIN_WITH_GIL 253 if (unlikely(val == null)) { 254 Py_INCREF(Py_None); 255 v = Py_None; 256 } else { 257 v = PyObjC_IdToPython(val); 258 if (unlikely(v == NULL)) { 259 PyObjC_GIL_FORWARD_EXC(); 260 } 261 } 262 263 if (unlikely(key == nil)) { 264 Py_INCREF(Py_None); 265 k = Py_None; 266 } else { 267 k = PyObjC_IdToPython(key); 268 if (k == NULL) { 269 Py_XDECREF(v); 270 PyObjC_GIL_FORWARD_EXC(); 271 } 272 } 273 274 if (likely(PyDict_CheckExact(value))) { 275 if (unlikely(PyDict_SetItem(value, k, v) < 0)) { 276 Py_XDECREF(v); 277 Py_XDECREF(k); 278 PyObjC_GIL_FORWARD_EXC(); 279 } 280 281 } else { 282 if (unlikely(PyObject_SetItem(value, k, v) < 0)) { 283 Py_XDECREF(v); 284 Py_XDECREF(k); 285 PyObjC_GIL_FORWARD_EXC(); 286 } 287 288 } 289 290 Py_DECREF(v); 291 Py_DECREF(k); 292 293 PyObjC_END_WITH_GIL 294} 295 296-(BOOL)wrappedKey:(id*)keyPtr value:(id*)valuePtr atPosition:(Py_ssize_t*)positionPtr 297{ 298 PyObject *pykey = NULL; 299 PyObject *pyvalue = NULL; 300 PyObject **pykeyptr = (keyPtr == nil) ? NULL : &pykey; 301 PyObject **pyvalueptr = (valuePtr == nil) ? NULL : &pyvalue; 302 303 PyObjC_BEGIN_WITH_GIL 304 if (unlikely(!PyDict_Next(value, positionPtr, pykeyptr, pyvalueptr))) { 305 PyObjC_GIL_RETURN(NO); 306 } 307 if (keyPtr) { 308 if (unlikely([self depythonify:pykey toId:keyPtr] == -1)) { 309 PyObjC_GIL_FORWARD_EXC(); 310 } 311 } 312 if (likely(valuePtr)) { 313 if (unlikely([self depythonify:pyvalue toId:valuePtr] == -1)) { 314 PyObjC_GIL_FORWARD_EXC(); 315 } 316 } 317 PyObjC_END_WITH_GIL 318 return YES; 319} 320 321-(void)removeObjectForKey:key 322{ 323 PyObject* k; 324 325 PyObjC_BEGIN_WITH_GIL 326 if (unlikely(key == [NSNull null])) { 327 Py_INCREF(Py_None); 328 k = Py_None; 329 } else { 330 k = PyObjC_IdToPython(key); 331 if (unlikely(k == NULL)) { 332 PyObjC_GIL_FORWARD_EXC(); 333 } 334 } 335 336 if (PyDict_CheckExact(value)) { 337 if (unlikely(PyDict_DelItem(value, k) < 0)) { 338 Py_DECREF(k); 339 PyObjC_GIL_FORWARD_EXC(); 340 } 341 } else { 342 if (unlikely(PyObject_DelItem(value, k) < 0)) { 343 Py_DECREF(k); 344 PyObjC_GIL_FORWARD_EXC(); 345 } 346 } 347 Py_DECREF(k); 348 349 PyObjC_END_WITH_GIL 350} 351 352-(NSEnumerator *)keyEnumerator 353{ 354 if (PyDict_CheckExact(value)) { 355 return [OC_PythonDictionaryEnumerator enumeratorWithWrappedDictionary:self]; 356 } else { 357 PyObjC_BEGIN_WITH_GIL 358 PyObject* keys = PyObject_CallMethod(value, "keys", NULL); 359 if (keys == NULL) { 360 PyObjC_GIL_FORWARD_EXC(); 361 } 362 363 PyObject* iter = PyObject_GetIter(keys); 364 Py_DECREF(keys); 365 if (iter == NULL) { 366 PyObjC_GIL_FORWARD_EXC(); 367 } 368 369 NSEnumerator* result = [OC_PythonEnumerator enumeratorWithPythonObject:iter]; 370 PyObjC_GIL_RETURN(result); 371 372 PyObjC_END_WITH_GIL 373 } 374} 375 376 377- (id)initWithObjects:(NSObject**)objects 378 forKeys:(NSObject**)keys 379 count:(NSUInteger)count 380{ 381 /* This implementation is needed for our support for the NSCoding 382 * protocol, NSDictionary's initWithCoder: will call this method. 383 */ 384 NSUInteger i; 385 386 PyObjC_BEGIN_WITH_GIL 387 for (i = 0; i < count; i++) { 388 PyObject* k; 389 PyObject* v; 390 int r; 391 392 if (objects[i] == [NSNull null]) { 393 v = Py_None; 394 Py_INCREF(Py_None); 395 } else { 396 v = PyObjC_IdToPython(objects[i]); 397 if (v == NULL) { 398 PyObjC_GIL_FORWARD_EXC(); 399 } 400 } 401 402 if (keys[i] == [NSNull null]) { 403 k = Py_None; 404 Py_INCREF(Py_None); 405 } else { 406 k = PyObjC_IdToPython(keys[i]); 407 if (k == NULL) { 408 PyObjC_GIL_FORWARD_EXC(); 409 } 410 } 411 412 r = PyDict_SetItem(value, k, v); 413 Py_DECREF(k); Py_DECREF(v); 414 415 if (r == -1) { 416 PyObjC_GIL_FORWARD_EXC(); 417 } 418 } 419 PyObjC_END_WITH_GIL 420 return self; 421} 422 423/* 424 * Helper method for initWithCoder, needed to deal with 425 * recursive objects (e.g. o.value = o) 426 */ 427-(void)pyobjcSetValue:(NSObject*)other 428{ 429 PyObjC_BEGIN_WITH_GIL 430 PyObject* v = PyObjC_IdToPython(other); 431 Py_XDECREF(value); 432 value = v; 433 PyObjC_END_WITH_GIL 434} 435 436- (id)initWithCoder:(NSCoder*)coder 437{ 438 int code; 439 if ([coder allowsKeyedCoding]) { 440 code = [coder decodeInt32ForKey:@"pytype"]; 441 } else { 442 [coder decodeValueOfObjCType:@encode(int) at:&code]; 443 } 444 switch (code) { 445 case 1: 446 PyObjC_BEGIN_WITH_GIL 447 value = PyDict_New(); 448 if (value == NULL) { 449 PyObjC_GIL_FORWARD_EXC(); 450 } 451 PyObjC_END_WITH_GIL 452 453 self = [super initWithCoder:coder]; 454 return self; 455 456 case 2: 457 if (PyObjC_Decoder != NULL) { 458 PyObjC_BEGIN_WITH_GIL 459 PyObject* cdr = PyObjC_IdToPython(coder); 460 if (cdr == NULL) { 461 PyObjC_GIL_FORWARD_EXC(); 462 } 463 464 PyObject* setValue; 465 PyObject* selfAsPython = PyObjCObject_New(self, 0, YES); 466 setValue = PyObject_GetAttrString(selfAsPython, "pyobjcSetValue_"); 467 468 PyObject* v = PyObject_CallFunction(PyObjC_Decoder, "OO", cdr, setValue); 469 Py_DECREF(cdr); 470 Py_DECREF(setValue); 471 Py_DECREF(selfAsPython); 472 473 if (v == NULL) { 474 PyObjC_GIL_FORWARD_EXC(); 475 } 476 477 Py_XDECREF(value); 478 value = v; 479 480 NSObject* proxy = PyObjC_FindObjCProxy(value); 481 if (proxy == NULL) { 482 PyObjC_RegisterObjCProxy(value, self); 483 } else { 484 [self release]; 485 [proxy retain]; 486 self = (OC_PythonDictionary*)proxy; 487 } 488 489 490 PyObjC_END_WITH_GIL 491 492 return self; 493 494 } else { 495 [NSException raise:NSInvalidArgumentException 496 format:@"decoding Python objects is not supported"]; 497 return nil; 498 499 } 500 } 501 [NSException raise:NSInvalidArgumentException 502 format:@"decoding Python objects is not supported"]; 503 [self release]; 504 return nil; 505} 506 507-(Class)classForCoder 508{ 509 return [OC_PythonDictionary class]; 510} 511 512 513- (void)encodeWithCoder:(NSCoder*)coder 514{ 515 if (PyDict_CheckExact(value)) { 516 if ([coder allowsKeyedCoding]) { 517 [coder encodeInt32:1 forKey:@"pytype"]; 518 } else { 519 int v = 1; 520 [coder encodeValueOfObjCType:@encode(int) at:&v]; 521 } 522 [super encodeWithCoder:coder]; 523 524 } else { 525 if ([coder allowsKeyedCoding]) { 526 [coder encodeInt32:2 forKey:@"pytype"]; 527 } else { 528 int v = 2; 529 [coder encodeValueOfObjCType:@encode(int) at:&v]; 530 } 531 PyObjC_encodeWithCoder(value, coder); 532 533 } 534} 535 536-(id)copyWithZone:(NSZone*)zone 537{ 538 if (PyObjC_CopyFunc) { 539 PyObjC_BEGIN_WITH_GIL 540 PyObject* copy = PyObject_CallFunctionObjArgs(PyObjC_CopyFunc, 541 value, NULL); 542 if (copy == NULL) { 543 PyObjC_GIL_FORWARD_EXC(); 544 } 545 546 NSObject* result = PyObjC_PythonToId(copy); 547 Py_DECREF(copy); 548 549 if (PyErr_Occurred()) { 550 PyObjC_GIL_FORWARD_EXC(); 551 } 552 553 [result retain]; 554 555 PyObjC_GIL_RETURN(result); 556 557 PyObjC_END_WITH_GIL 558 } else { 559 return [super copyWithZone:zone]; 560 } 561} 562 563-(id)mutableCopyWithZone:(NSZone*)zone 564{ 565 if (PyObjC_CopyFunc) { 566 PyObjC_BEGIN_WITH_GIL 567 PyObject* copy = PyDict_New(); 568 if (copy == NULL) { 569 PyObjC_GIL_FORWARD_EXC(); 570 } 571 572 int r = PyDict_Update(copy, value); 573 if (r == -1) { 574 PyObjC_GIL_FORWARD_EXC(); 575 } 576 577 NSObject* result = PyObjC_PythonToId(copy); 578 Py_DECREF(copy); 579 580 if (PyErr_Occurred()) { 581 PyObjC_GIL_FORWARD_EXC(); 582 } 583 584 [result retain]; 585 586 PyObjC_GIL_RETURN(result); 587 588 PyObjC_END_WITH_GIL 589 } else { 590 return [super mutableCopyWithZone:zone]; 591 } 592} 593 594 595@end // interface OC_PythonDictionary 596